【发布时间】:2018-07-22 14:32:29
【问题描述】:
我在片段中的 RecyclerView 上的 clickListener 上遇到 NPE 问题。最初它可以很好地显示一条吐司消息,但是当我旋转设备并触摸我得到的任何图标时:
java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.android.newswiz.OnItemClickListener.onItemClick(java.lang.String)' on a null object reference
at com.example.android.newswiz.Fragments.PublishersSlidePageFragment$PublishersAdapter$PublishersAdapterViewHolder$1.onClick(PublishersSlidePageFragment.java:86)
这是我的片段类。我已经评论了日志中有 NPE 的部分:
package com.example.android.newswiz.Fragments;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.android.newswiz.OnItemClickListener;
import com.example.android.newswiz.R;
public class PublishersSlidePageFragment extends Fragment {
public OnItemClickListener listener;
public PublishersSlidePageFragment(){}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle
savedInstanceState) {
ViewGroup rootView = (ViewGroup)
inflater.inflate(R.layout.fragment_publishers_slide_page,
container, false);
RecyclerView mRecyclerView =
rootView.findViewById(R.id.recyclerView_publishers);
int numberOfColumns =
Integer.parseInt(getContext().getResources().getString(R.string.no_of_cols));
mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(),
numberOfColumns));
mRecyclerView.setHasFixedSize(true);
PublishersAdapter mAdapter = new PublishersAdapter();
mRecyclerView.setAdapter(mAdapter);
return rootView;
}
public void setListener(OnItemClickListener onItemClickListener) {
this.listener = onItemClickListener;
}
public class PublishersAdapter extends RecyclerView.Adapter<PublishersAdapter.PublishersAdapterViewHolder>{
@NonNull
@Override
public PublishersAdapter.PublishersAdapterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.publisher_item, parent, false);
return new PublishersAdapterViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull PublishersAdapter.PublishersAdapterViewHolder holder, int position) {
holder.mPublisherImageView.setImageResource(mThumbIds[position]);
holder.mPublisherTextView.setText(mPublishers[position]);
holder.bind(mPublishers[position], listener);
}
@Override
public int getItemCount() {
return mThumbIds.length;
}
public class PublishersAdapterViewHolder extends RecyclerView.ViewHolder {
private final ImageView mPublisherImageView;
private final TextView mPublisherTextView;
public PublishersAdapterViewHolder(View itemView) {
super(itemView);
mPublisherImageView = itemView.findViewById(R.id.publisher_icon);
mPublisherTextView = itemView.findViewById(R.id.publisher_desc);
}
public void bind(final String mPublisher, final OnItemClickListener clickListener) {
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clickListener.onItemClick(mPublisher); //NPE on this line
}
});
}
}
}
// references to the images
private Integer[] mThumbIds = {
R.drawable.abc_news, R.drawable.abc_news_au,
R.drawable.aftenposten, R.drawable.aljazeera_english,
R.drawable.bbc, R.drawable.cbs_news,
R.drawable.cnn_news, R.drawable.entertainment_weekly,
R.drawable.espn, R.drawable.financial_post,
R.drawable.financial_times, R.drawable.fox_news,
R.drawable.fox_sports, R.drawable.ign,
R.drawable.independent, R.drawable.lequipe,
R.drawable.metro, R.drawable.msnbc,
R.drawable.mtvnews, R.drawable.nat_geo,
R.drawable.nbc_news, R.drawable.new_scientist,
R.drawable.new_york_magazine, R.drawable.talk_sport,
R.drawable.techradar, R.drawable.the_guardian,
R.drawable.the_nyt, R.drawable.wsj
};
private String[] mPublishers = {"ABC News", "ABC News (AU)", "Aftenposten", "AlJazeera (ENG)"
, "BBC", "CBS News", "CNN News", "Entertainment Weekly", "ESPN", "Financial Post",
"Financial Times", "Fox News", "Fox Sports", "IGN", "Independent", "L'Equipe",
"Metro", "MSNBC", "MTV News", "Nat. Geo.", "NBC News", "New Scientist",
"NY Magazine", "Talk Sport", "TechRadar", "The Guardian", "NYT",
"Wall Street Journal"};
}
Fragment 类和监听器在 Main Activity 中初始化:
public class MainActivity extends AppCompatActivity {
private ViewPager mPager;
private SectionsPageAdapter mSectionsPageAdapter;
private Context context;
private TabLayout tabLayout;
private OnItemClickListener publisherClickListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
// Login authentication code ....
//Set up the ViewPager and PagerAdapter
mSectionsPageAdapter = new
SectionsPageAdapter(getSupportFragmentManager());
mPager = findViewById(R.id.sources_container);
setupViewPager(mPager);
tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mPager);
}
//FIXME NPE on listener object if you rotate screen and touch icon
private void setupViewPager(ViewPager mPager) {
SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
PublishersSlidePageFragment publishersSlidePageFragment = new PublishersSlidePageFragment();
publisherClickListener = new OnItemClickListener() {
@Override
public void onItemClick(String item) {
Toast.makeText(context, "You have selected " + item, Toast.LENGTH_SHORT).show();
}
};
publishersSlidePageFragment.setListener(publisherClickListener);
adapter.addFragment(publishersSlidePageFragment, "Publishers");
adapter.addFragment(new CategoriesSlidePageFragment(), "Categories");
adapter.addFragment(new CountriesSlidePageFragment(), "Countries");
mPager.setAdapter(adapter);
}
我觉得很奇怪,当屏幕旋转时重新创建片段是可以的,但无法为片段创建新的 clickListener。我搜索了 StackOverflow 并发现 Save interface (Listener) in onSaveInstanceState 很有用,但我认为在我的情况下保存听众不是一个好习惯。我想创建一个新的侦听器并将其设置在片段内的 Recycler View 上。我可能遗漏了一些琐碎的事情,但有人可以建议吗?
【问题讨论】:
标签: android-fragments android-recyclerview onitemclicklistener