我有一个片段为frag2的活动A.在片段内部,我有一个RecyclerView和Adapter来显示自定义类对象的列表。以编程方式处理向适配器添加对象。我在TwoFragment中有一个按钮,可以打开FragmentDialog。我想通过确认这个对话框向我的适配器添加一个对象,但是当从FragmentDialog调用时,似乎适配器为null。
同一个适配器不为null,如果我从片段OnClick调用它,它就可以工作。
此外,只有在屏幕旋转后适配器才为空,它在旋转之前工作正常。
为了在两个片段之间进行通信,我在活动A中实现了一个通信器类。
活动A
public void respond(String type) {
frag2.addSupport(type);
}
frag2
public RecyclerView rv;
public ArrayList<support> supports;
public myAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supports = new ArrayList<>();
adapter = new myAdapter(supports);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View layout = inflater.inflate( R.layout.fragment_two, container, false);
layout.setId(R.id.frag2);
if (savedInstanceState!=null)
{
supports = savedInstanceState.getParcelableArrayList("supports");
}
rv = (RecyclerView) layout.findViewById(R.id.rv);
adapter = new myAdapter(supports);
rv.setAdapter(myAdapter);
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
rv.setItemAnimator(new DefaultItemAnimator());
@Override
public void onClick(View v) {
int id = v.getId();
switch (id){
case R.id.button1:
addSupport(type); // THIS WORKS ALWAYS, even after screen rotate
break;
case R.id.button2:
showDialog();
break;
}
}
public void showDialog(){
FragmentManager manager = getFragmentManager();
myDialog dialog = new myDialog();
dialog.show(manager, "dialog");
}
public void addSupport(String type){
adapter.addItem(new support(type)); // this line gives null pointer on adapter, but only if called after screen rotate and only if called from the dialog
}
对话框
communicator comm;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog, null);
comm = (myCommunicator) getActivity();
create = (Button) view.findViewById(R.id.button_ok);
create.setOnClickListener(this);
return view;
}
@Override
public void onClick(View v) {
if(v.getId()==R.id.button_ok)
{
// some controls to set type
comm.respond(type)
dismiss();
}
else {
dismiss();
}
myAdapter
public class myAdapter extends RecyclerView.Adapter<myAdapter.VH> {
private LayoutInflater inflater;
private ArrayList<support> data = new ArrayList<>();
// settings for viewholder
public myAdapter (ArrayList<support> data)
{
this.data=data;
}
public void addItem(support dataObj) {
data.add(dataObj);
notifyItemInserted(data.size());
}
}
logcat的
FATAL EXCEPTION: main
java.lang.NullPointerException: Attempt to invoke virtual method 'myAdapter.addItem(myObject)' on a null object reference
我希望没有错误,我缩短了代码以便更好地理解。请记住,如果我从不旋转屏幕,一切正常。
我是Android的初学者,现在我已经坚持了好几天了。请帮忙。
答案 0 :(得分:0)
要理解这个问题,就像你说的那样:
..如果我从不旋转屏幕,一切正常
首先要了解旋转时会发生什么,这是来自Android Developer website:
的引用警告:每次用户旋转屏幕时,您的活动都将被销毁并重新创建。当屏幕更改方向时,系统会破坏并重新创建前台活动,因为屏幕配置已更改,您的活动可能需要加载其他资源(例如布局)。
好的,现在要了解错误:
FATAL EXCEPTION: main
java.lang.NullPointerException: Attempt to invoke virtual method 'myAdapter.addItem(myObject)' on a null object reference
基本上,在您的dialog
课程中,您通过声明:
comm = (myCommunicator) getActivity();
因为comm
引用了旋转时销毁的对象,因此NullPointerException
。
为了进一步了解运行时更改,例如方向更改,我建议您浏览Handling Runtime Changes。
感谢您的回答,您会推荐什么而不是comm =(myCommunicator)getActivity(); ?
解决方案分为三部分:
onCreate
的{{1}}具有以下内容:Activity A
将
@Override
public void onCreate(Bundle savedInstanceState) {
......
// find the retained fragment on activity restarts
FragmentManager fm = getFragmentManager();
frag2 = (Frag2) fm.findFragmentByTag(“frag2”);
// create frag2 only for the first time
if (frag2 == null) {
// add the fragment
frag2 = new Frag2();
fm.beginTransaction().add(frag2 , “frag2”).commit();
}
......
}
添加到setRetainInstance(true)
的{{1}}。
删除隐式引用,即onCreate
,并为frag2
实现更松散耦合的内容。
<强>对话框强>
comm = (myCommunicator) getActivity();
这允许您在dialog
(或任何其他类别)中执行以下操作:
<强> frag2 强>
public interface Communicator {
void respond(String type);
}
Communicator comm;
....
public void addCommunicator(Communicator communicator) {
comm = communicator;
}
public void removeCommunicator() {
comm = null;
}
@Override
public void onClick(View v) {
if((v.getId()==R.id.button_ok) && (comm!=null))
{
// some controls to set type
comm.respond(type);
}
// Regardless of what button is pressed, the dialog will dismiss
dismiss();
}