Eri*_* H. 0 android nullpointerexception fragmentpageradapter
getActivity()null如果之前被调用,片段内将返回fragment.onAttach(activity).
fragment.onActivityCreated(savedInstanceState)被称为fragment.onAttach(activity).有关片段生命周期的信息,请参阅developer.android.
我的片段中有一个尝试实例化数据库连接的方法.最初调用该方法时,它可以正常工作.
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
Log.d("MyTag", "Activity being created");
if (savedInstanceState == null){
listAdapter.setContext(getActivity());
execSearch(0);
} else { listAdapter.setContext(getActivity()); }
}
public void execSearch(Long searchId) {
MySQLiteHelper dbHelper = new MySQLiteHelper(getActivity());
SQLiteDatabase database = dbHelper.getReadableDatabase();
...
}
Run Code Online (Sandbox Code Playgroud)
现在,当在列表视图中单击按钮后通过接口调用此相同方法时,getActivity()返回null(在片段中).
以下是ListAdapter中的按钮回调:
private final View.OnClickListener editSearchListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Long search_id = (Long) v.getTag();
((MyInterface) context).searchCalled(search_id);
}
};
Run Code Online (Sandbox Code Playgroud)
以及MainActivity中的接口实现:
@Override
public void searchCalled(Long search_id) {
fragment.execSearch(id);
}
Run Code Online (Sandbox Code Playgroud)
第二次我null从getActivity()内部得到回应fragment.execSearch(id).
我被困了!! 这是否与来自UI操作的接口调用有关.我是否需要在UI线程上实现mainActivity.searchCalled作为runnable ???
由于这是我第一次开发Android应用程序,想要分享我学到的一些东西,以便为其他新的Android开发人员更直观地解决这个问题.我正在开发的背景:
基本上我试图做的是保留用户在配置更改中所做的任何更改(这对于新手了解活动创建与应用程序启动不同是有帮助的 - 当应用程序遇到配置更改时,会重复创建活动,或被另一个应用程序取代.这对我来说并不直观.)
有两种方法可以做到这一点.您可以在Fragment.onSaveInstanceState中保存必要的数据,然后在创建新活动时使用保存的数据重新创建片段,也可以在您的活动中调用setRetainInstanceFragment.onCreate.
我最初使用的是savedInstanceState方法.因为这不保留我的片段实例,所以我得到的时候getActivity() == null,这是因为代码是从未附加到活动的旧片段实例运行的.当从onClickListener调用接口时,可能会发生这种情况,该接口尚未更新为指向当前活动实例(即附加到当前活动的实例).即侦听器是在配置更改之前创建的,并在配置更改后调用,而不会被告知已创建新的Activity实例.
我最终选择了去setRetainInstance(true)路线.这意味着:
onCreate创建新活动时不会调用. onDestroy如果活动被破坏,则不会被调用.savedInstanceState在你的onActivityCreated将永远是空的这使得事情变得简单而困难.基本上我推荐这条路线,如果你有很多属性/数据不依赖于知道当前活动是什么(例如表格值,要显示的列表).但是,在这种情况下,必须在创建新活动时告知需要了解当前活动的任何属性.你可以这样做:
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.activity = (MainActivity) activity;
// custom method on list adapter, so any calls to SearchManager interface
// are properly routed to current activity
myListAdapter.setContext(activity);
}
Run Code Online (Sandbox Code Playgroud)
片段实例之间的通信
关于如何在片段之间进行通信,我听到了相互矛盾的建议.一方面,我听说你不应该在适配器之外引用你的片段实例.另一方面,您听到片段实例不应该直接相互通信.这意味着使用FragmentPagerAdapter为片段实现通信接口.但是,即使在这种情况下,您也必须聪明地在适配器中获取片段实例(例如,您可以获取片段的适配器标签或更好地利用适配器的instantiateItem方法).
最终,因为任何你削减馅饼的方法,你必须破解以获得你的片段实例,我走出适配器并创建了一个实现我的界面的无头片段SearchManager.这使接口与适配器分离,避免了我的功能片段之间的通信,以及MainActivity之外的通信.
跨配置更改保留视图
最后一点.当我创建新的搜索表单时,我注意到所有输入都被删除了我的配置更改(即附加/创建新片段时).这是因为即使setRetainInstance设置为true,onCreateView仍会调用片段的方法,要求您对视图进行充气并将其返回.正是这个过程消除了对视图的任何用户操作.所以我在我的所有片段onCreateView方法中都做了以下事情:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (view == null){
view = inflater.inflate(R.layout.doc_list_fragment,
container, false);
} else {
((ViewGroup) view.getParent()).removeView(view);
}
setContext();
return view;
}
Run Code Online (Sandbox Code Playgroud)
因为setRetainInstance是,所以视图在第一次充气后保留在片段实例中.该removeView业务可防止此错误:
FATAL EXCEPTION: main java.lang.IllegalStateException:
The specified child already has a parent. You must call removeView() on the child's parent first.
Run Code Online (Sandbox Code Playgroud)
此外,我在setContext这里调用了我的自定义方法,因为在这一点上,我同时拥有自己的视图和活动.因此,如果有点击监听器需要知道当前的活动是什么,现在我有准备视图,可以创建听众正确它们指向当前的活动.
您可以在GitHub上查看已完成的应用程序.
| 归档时间: |
|
| 查看次数: |
1682 次 |
| 最近记录: |