Reputation: 336
Hi in my MainActivity
I implemented ViewPager
with TabLayout
with 3 tabs and each view page starts new Fragment. I am showing cards in a grid view in each Fragment and when a card is clicked DetailActivtiy
starts.
I am starting detail activity from Fragments but when I try to put some extra in Intent
starting detail activity I get NullPointerException
. I tried to debug code but I am unable to find where the problem is.
Here's my code:
PopularFragment
(one of the tab layout in 3 tabs)
public class PopularFragment extends Fragment implements PosterTask.GetPoster,RecyclerAdapter.OnClick {
private RecyclerAdapter mRecyclerAdapter;
private ProgressDialog mProgressBar;
private ArrayList<Movie> movies;
public PopularFragment() {
// 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_popular, container, false);
//Show progress bar
showProgressBar();
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
//Setting layout manager
recyclerView.setLayoutManager(new GridLayoutManager(inflater.getContext(), 2));
//Setting adapter
mRecyclerAdapter = new RecyclerAdapter(inflater.getContext());
recyclerView.setAdapter(mRecyclerAdapter);
return view;
}
@Override
public void onStart() {
super.onStart();
//Starting asyncTask
new PosterTask(this).execute(buildUrl().toString());
//Setting listener to cards
mRecyclerAdapter.setOnClickListener(this);
}
//Building url
private Uri buildUrl(){
//Building url
String api_key = "api_key";
return Uri.parse(Utility.POPULAR_URL).buildUpon()
.appendQueryParameter(api_key, getString(R.string.API_KEY))
.build();
}
//Called after getting posters url's
@Override
public void onPosterCompleted(ArrayList<Movie> movies) {
ArrayList<String> poster = new ArrayList<>();
for(int i=0;i<movies.size();i++){
poster.add(movies.get(i).getPoster());
}
//Passing data to adapter
mRecyclerAdapter.setPoster(poster);
//Removing progress bar
mProgressBar.hide();
this.movies = movies;
}
//Showing progress bar
private void showProgressBar(){
mProgressBar = new ProgressDialog(getContext());
mProgressBar.setMessage("Fetching data...");
mProgressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressBar.show();
}
@Override
public void onClicked(int position, View v) {
//Starting detail activity
Intent intent = new Intent(getActivity(), DetailActivity.class);
intent.putExtra(Utility.INTENT_CONSTANT, "sahil");
startActivity(intent);
}
}
Here onClicked()
method is called when any card of RecyclerView
is clicked.
RecyclerAdapter
:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private Context mContext;
private ArrayList<String> mPosters;
private static OnClick mListener;
//Listener listening clicks
public interface OnClick{
void onClicked(int position, View v);
}
public RecyclerAdapter(Context context){
mContext = context;
}
//Set poster url
public void setPoster(ArrayList<String> poster){
mPosters = poster;
notifyDataSetChanged();
}
//Set listener
public void setOnClickListener(OnClick listener){
mListener = listener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.card_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Loading url images to image view in cards
Picasso.with(mContext).load(mPosters.get(position)).into(holder.imageView);
}
@Override
public int getItemCount() {
if(mPosters!=null) {
return mPosters.size();
}
return 0;
}
//View holder for adapter
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.card_image);
imageView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
mListener.onClicked(getPosition(), v);
}
}
}
When I start DetailActivity
without putting extra in Intent
it works but when I put extra in Intent
and try to retrieve it in DetailActivity
I get NullPointerException
.
In DetailFragment
(contained by DetailActivity
i try to get intent as):
//Exception:Detailfragment:
public class DetailFragment extends Fragment implements TrailerRecyclerAdapter.OnClick,TrailerTask.TrailerCompleted {
@Bind(R.id.movie_title)TextView titleView;
@Bind(R.id.movie_date)TextView dateView;
@Bind(R.id.movie_image)ImageView imageView;
@Bind(R.id.movie_vote_avg)TextView voteView;
@Bind(R.id.movie_votes)TextView totalView;
@Bind(R.id.favorite_button)Button favButton;
@Bind(R.id.trailer_view)RecyclerView trailerView;
@Bind(R.id.review_view)RecyclerView reviewView;
private TrailerRecyclerAdapter mTrailerAdapter;
private ArrayList<String> mTrailers;
public DetailFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_detail, container, false);
//Binding views
ButterKnife.bind(this, view);
//Getting clicked movie
// Movie movie = getActivity().getIntent().getParcelableExtra(Utility.INTENT_CONSTANT);
//Starting asyncTask
// new TrailerTask(this).execute(movie.getId());
//Binding data
// bindData(movie);
Log.v("title", getActivity().getIntent().getStringExtra(Utility.INTENT_CONSTANT));
return view;
}
//Binds data to views
/*
private void bindData(Movie movie){
titleView.setText(movie.getTitle());
dateView.setText(movie.getDate());
Picasso.with(getContext()).load(movie.getBack_poster()).into(imageView);
voteView.setText(String.valueOf(movie.getVote_avg()));
String total = getString(R.string.before) + movie.getTotal_votes() + getString(R.string.after);
totalView.setText(total);
//Setting adapter to trailerView
mTrailerAdapter = new TrailerRecyclerAdapter(getContext());
trailerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
trailerView.setAdapter(mTrailerAdapter);
}
*/
@Override
public void onClicked(int position, View v) {
//Building intent
Uri uri = Uri.parse(mTrailers.get(position)).buildUpon().build();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivity(intent);
}
}
@Override
public void onTrailerCompleted(ArrayList<String> trailers, ArrayList<String> trailer_posters) {
mTrailers = trailers;
mTrailerAdapter.setPoster(trailer_posters);
}
}
Here's the Github repo
Logcat:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.movies, PID: 14578
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.movies/com.example.android.movies.DetailActivity}: android.view.InflateException: Binary XML file line #1: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2338)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class fragment
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:816)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:745)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:256)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:109)
at com.example.android.movies.DetailActivity.onCreate(DetailActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5292)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1088)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2302)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException: println needs a message
at android.util.Log.println_native(Native Method)
at android.util.Log.v(Log.java:118)
at com.example.android.movies.DetailFragment.onCreateView(DetailFragment.java:54)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1036)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1226)
at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1328)
at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2284)
at android.support.v4.app.FragmentController.onCreateView(FragmentController.java:111)
at android.support.v4.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:314)
at android.support.v4.app.BaseFragmentActivityHoneycomb.onCreateView(BaseFragmentActivityHoneycomb.java:31)
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:79)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:689)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:816)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:745)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:256)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:109)
at com.example.android.movies.DetailActivity.onCreate(DetailActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5292)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1088)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2302)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
Upvotes: 0
Views: 1194
Reputation: 11903
You should not be using a static variable to hold the callback listener in your RecyclerAdapter
. This means each RecyclerAdapter
will always have the same callback listener when you want each one to have its own.
That is why you are experiencing this issue. RatedFragment
and PopularFragment
are both using a RecyclerAdapter
. When you click an image the callback from your RatedFragment
will be called even when viewing the PopulareFragmnet
.
RatedFragment
is then not adding the extra you are looking for which is causing the NullPointerException
.
To fix this remove static from mListener in the RecyclerAdapter
:
private OnClick mListener;
Then remove static also from the definition of the ViewHolder
class so it becomes an inner class and can access the listener directly:
public class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
After doing this you will still have to fix the RatedFragment
since it will show the same DetailsFragment
without the extra you are currently requiring.
Upvotes: 1