Reputation: 15
I am trying to open a url link when I click on a list item in a recyclerview but I keep getting a NullPointerException
. I am using a ViewPager, I don't know if this is the cause of the exception, maybe I'm doing something wrong. Please check out my code and logcat below.
This is my adapter:
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.NewsHolder> {
private ArrayList<News> mNews = new ArrayList<>();
private static ClickListener clickListener;
public NewsAdapter(ArrayList<News> news) {
mNews = news;
}
private static String timeConverter(String inputTime) {
long startTime = 0;
SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
simpleDate.setTimeZone(TimeZone.getTimeZone("GMT"));
try {
Date date = simpleDate.parse(inputTime);
startTime = date.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
long currentTime = System.currentTimeMillis();
long end = currentTime - startTime;
long seconds = TimeUnit.MILLISECONDS.toSeconds(end);
long minutes = TimeUnit.SECONDS.toMinutes(seconds);
long hours = TimeUnit.MINUTES.toHours(minutes);
if (minutes > 59) {
return hours + "h";
}else if (seconds > 59) {
return minutes + "m";
}else {
return seconds + "s";
}
}
@Override
public NewsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_view, parent, false);
return new NewsHolder(view);
}
@Override
public void onBindViewHolder(NewsHolder holder, int position) {
String imagePath = mNews.get(position).getImageUrl();
Picasso.with(holder.mImageView.getContext()).load(imagePath).into(holder.mImageView);
holder.mNewsTextView.setText(mNews.get(position).getNews());
holder.mTimeStampTextView.setText(timeConverter(mNews.get(position).getTime()));
}
@Override
public int getItemCount() {
return mNews.size();
}
// NewsHolder class that extends the ViewHolder
public static class NewsHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ImageView mImageView;
private TextView mNewsTextView;
private TextView mTimeStampTextView;
// Setting the views
public NewsHolder(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.simple_imageView);
mNewsTextView = (TextView) itemView.findViewById(R.id.news_tv);
mTimeStampTextView = (TextView) itemView.findViewById(R.id.time_tv);
}
@Override
public void onClick(View view) {
clickListener.onItemClick(getAdapterPosition(), view);
}
}
public void setOnItemClickListener(ClickListener listener) {
NewsAdapter.clickListener = listener;
}
public interface ClickListener {
void onItemClick(int position, View v);
}
}
This is one of my ViewPager fragments:
public class TechFragment extends Fragment {
private SwipeRefreshLayout mSwipeRefreshLayout;
private TextView mErrorMessage;
private NewsAdapter mNewsAdapter;
ArrayList<News> news;
NetworkInfo info;
// The Loader takes in a bundle
Bundle sourceBundle = new Bundle();
private final String LOG_TAG = MainActivity.class.getSimpleName();
private static final String TECH_NEWS_QUERY_URL = "query";
private static final String TECH_NEWS_SOURCE = "techcrunch";
private static final String TECH_SOURCE_CATEGORY = "latest";
private static final int TECH_NEWS_LOADER = 22;
private RecyclerView mRecyclerView;
public TechFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_news, container, false);
mErrorMessage = (TextView) view.findViewById(R.id.tv_error_message);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view_main);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefresh);
getActivity().getSupportLoaderManager().initLoader(TECH_NEWS_LOADER, sourceBundle, new NewsDataLoader());
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
Log.v(LOG_TAG, "Refreshing");
restartLoader();
mSwipeRefreshLayout.setColorSchemeResources(
R.color.colorPrimary,
R.color.colorPrimaryDark);
}
});
return view;
}
private boolean isConnected() {
ConnectivityManager cm = (ConnectivityManager) getActivity()
.getSystemService(CONNECTIVITY_SERVICE);
info = cm.getActiveNetworkInfo();
return info != null && info.isConnectedOrConnecting();
}
private int anyRandomInt(Random random) {
return random.nextInt();
}
private void restartLoader() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
URL techNewsUrl = NetworkUtils.buildUrl(TECH_NEWS_SOURCE, TECH_SOURCE_CATEGORY);
sourceBundle.putString(TECH_NEWS_QUERY_URL, techNewsUrl.toString());
Random random = new Random();
int uniqueId = anyRandomInt(random); //Generates a new ID for each loader call;
LoaderManager loaderManager = getActivity().getSupportLoaderManager();
if (loaderManager.getLoader(TECH_NEWS_LOADER) == null) {
loaderManager.initLoader(uniqueId, sourceBundle, new NewsDataLoader());
} else {
loaderManager.restartLoader(TECH_NEWS_LOADER, sourceBundle, new
NewsDataLoader());
}
}
}, 5000);
mSwipeRefreshLayout.setRefreshing(false);
Log.v(LOG_TAG, "Finished refreshing");
}
private void showErrorScreen() {
mErrorMessage.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.INVISIBLE);
mErrorMessage.setText(getString(R.string.internet_error));
}
public class NewsDataLoader implements LoaderManager.LoaderCallbacks<ArrayList<News>> {
@Override
public Loader<ArrayList<News>> onCreateLoader(int id, final Bundle args) {
if (isConnected()) {
mErrorMessage.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
return new AsyncTaskLoader<ArrayList<News>>(getActivity()) {
ArrayList<News> mNewsData;
@Override
protected void onStartLoading() {
super.onStartLoading();
if (mNewsData != null) {
deliverResult(mNewsData);
} else {
forceLoad();
mSwipeRefreshLayout.setRefreshing(true);
}
}
@Override
public ArrayList<News> loadInBackground() {
try {
ArrayList<News> news = NetworkUtils.parseJSON(TECH_NEWS_SOURCE, TECH_SOURCE_CATEGORY);
return news;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public void deliverResult(ArrayList<News> data) {
mNewsData = data;
super.deliverResult(data);
}
};
} else {
showErrorScreen();
return null;
}
}
@Override
public void onLoadFinished(Loader<ArrayList<News>> loader, final ArrayList<News> data) {
mSwipeRefreshLayout.setRefreshing(false);
if (null == data) {
showErrorScreen();
} else {
mErrorMessage.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
if (news != null) {
news.clear();
news.addAll(data);
mNewsAdapter = new NewsAdapter(news);
mRecyclerView.setAdapter(mNewsAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
mNewsAdapter.notifyDataSetChanged();
} else {
news = data;
}
}
mNewsAdapter.setOnItemClickListener(new NewsAdapter.ClickListener() {
@Override
public void onItemClick(int position, View v) {
News currentNews = news.get(position);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(currentNews.getUrl()));
if (intent.resolveActivity(getActivity().getPackageManager()) != null){
startActivity(intent);
}
}
});
}
@Override
public void onLoaderReset(Loader<ArrayList<News>> loader) {
}
}
}
And this is my error:
06-13 12:11:38.667 3890-3890/com.ire.blogbot E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ire.blogbot, PID: 3890
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.ire.blogbot.adapter.NewsAdapter.setOnItemClickListener(com.ire.blogbot.adapter.NewsAdapter$ClickListener)' on a null object reference
at com.ire.blogbot.fragments.TechFragment$NewsDataLoader.onLoadFinished(TechFragment.java:192)
at com.ire.blogbot.fragments.TechFragment$NewsDataLoader.onLoadFinished(TechFragment.java:131)
at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:476)
at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:444)
at android.support.v4.content.Loader.deliverResult(Loader.java:126)
at com.ire.blogbot.fragments.TechFragment$NewsDataLoader$1.deliverResult(TechFragment.java:164)
at com.ire.blogbot.fragments.TechFragment$NewsDataLoader$1.deliverResult(TechFragment.java:137)
at android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:252)
at android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:80)
at android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:485)
at android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:502)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Upvotes: 0
Views: 1584
Reputation: 1
Try this code, it is working
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
@Override public void onItemClick(View view, int position) {
// on click
}
})
);
RecyclerItemClickListener Class
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}}
Upvotes: 1
Reputation: 9342
Move
mNewsAdapter.setOnItemClickListener(new NewsAdapter.ClickListener() {
@Override
public void onItemClick(int position, View v) {
News currentNews = news.get(position);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(currentNews.getUrl()));
if (intent.resolveActivity(getActivity().getPackageManager()) != null){
startActivity(intent);
}
}
});
after
mNewsAdapter = new NewsAdapter(news);
Upvotes: 0