我有一个活动A,片段为frag2。在片段内部,我有一个RecyclerView和Adapter来显示自定义类对象的列表。将对象添加到适配器是通过编程方式处理的。我在TwoFragment内部有一个打开FragmentDialog的按钮。我想通过确认此对话框将一个对象添加到我的适配器,但是当从FragmentDialog调用时,适配器似乎为空。
相同的适配器不为null,并且如果我从片段OnClick调用它也可以使用。
此外,适配器仅在屏幕旋转后才为空,在旋转之前工作正常。
为了在两个片段之间进行通信,我在活动A中实现了一个通信器类。
活动A
public void respond(String type) {
frag2.addSupport(type);
}
碎片2
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());
}
}
日志猫
FATAL EXCEPTION: main
java.lang.NullPointerException: Attempt to invoke virtual method 'myAdapter.addItem(myObject)' on a null object reference
希望没有错误,为了简化理解,我缩短了代码。请记住,如果我从不旋转屏幕,一切都会正常。
我是android的初学者,现在已经坚持了好几天。请帮忙。
最佳答案
要理解这个问题,就像您说的那样:
..如果我从不旋转屏幕,一切都会正常
因此,首先要了解旋转发生了什么,这是来自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
的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)
添加到onCreate
的frag2
中。删除隐式引用,即
comm = (myCommunicator) getActivity();
,并为dialog
实现一些松散耦合。对话
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();
}
这使您可以在
frag2
(或与此相关的任何其他类)中执行以下操作:碎片2
<pre><code>
public class Frag2 extends Fragment implements dialog.Communicator {
........
public void showDialog() {
FragmentManager manager = getFragmentManager();
myDialog dialog = new myDialog();
dialog.addCommunicator(this);
dialog.show(manager, "dialog");
}
@Override
public void respond(String type){
adapter.addItem(new support(type));
}
}