我有FragmentActivity
两个标签,它们是ListFragment
s。每个ListFragment
都有一个回调。
(注意:如果有人注意到,这个问题的大部分是从我自己的问题Callback after orientation change become null重新散列的,但这是一个不同的问题,因为这与旋转无关,但我希望了解我的实际问题回调。)
回调示例
如http://developer.android.com/training/basics/fragments/communicating.html所述,回调与onAttach(...)方法内部相关联
OnTab1Listener mTab1Callback;
public interface OnTab1Listener {
public void onTab1Update();
}
@Override
public void onAttach(Activity activity) {
Log.d(TAG, "onAttach");
super.onAttach(activity);
try {
mTab1Callback = (OnTab1Listener)activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnTab1Listener");
}
}
后来,我FragmentActivity
通过这个正常工作的回调与通信。
在应用程序被发送到后台一段时间后,我将应用程序带到前面并触发将使用回调的东西,回调为空,我的应用程序崩溃。我相信一旦它在后台并且系统进行垃圾收集就会发生这种情况。
这是一个在正常执行期间工作正常的示例调用。
public void toggleEnabled(View v) {
Log.d(TAG, "toggleEnabled");
// null pointer here
mTab1Callback.onTab1Update();
}
问题
- 如果东西被垃圾收集,为什么mTab1Callback被垃圾收集而不是恢复?我的印象是
Activity
生命周期和Fragment
生命周期将重新启动,包括onAttach(...)如果部分引用被垃圾收集。 - 这是如何正确修复的?
示例应用
我创建了一个展示这种行为的示例应用程序。完整的源代码在这里http://www.2shared.com/file/kkgFejUq/broken_example.html
示例应用程序堆栈跟踪
FATAL EXCEPTION: main
java.lang.IllegalStateException: Could not execute method of the activity
at android.view.View$1.onClick(View.java:3591)
at android.view.View.performClick(View.java:4084)
at android.widget.CompoundButton.performClick(CompoundButton.java:100)
at android.view.View$PerformClick.run(View.java:16966)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at android.view.View$1.onClick(View.java:3586)
... 12 more
Caused by: java.lang.NullPointerException
at com.example.myapp.Tab2.toggleEnabled(Tab1.java:87)
at com.example.myapp.MainActivity.onClick(MainActivity.java:50)
... 15 more
这是Tab1.java:87
mTab1Callback.onTab1Update();
如果您让应用程序进入后台,做一些其他的事情,例如玩一会儿游戏,听音乐等,然后将其返回到前台并单击其中一个复选框,这将成为一个空指针。
万一这很重要,我将应用程序图标放在启动器上并从那里启动它,然后在我运行其他应用程序一段时间后将其带到前台。这是它崩溃的时候。
我也不能让它在模拟器上崩溃,只有真正的硬件。当手机插入计算机时,它似乎不太可能崩溃,如果在测试时拔掉电源,它似乎更容易崩溃。
TabsAdapter与此有关吗?
此外,这使用了文件中包含的SherlockActionBar 。它应该用作MyApp的库。
更新
我开始看到getActivity()在哪里为空,并且在旋转或长期在后台运行之后,它唯一为空的地方是触发回调的toggleEnabled()函数内部。
这似乎表明罪魁祸首是不再存在的MainActivity
引用 a 。Fragment
结合空间代码,这本质上是我在单击in后引用toggleEnabled()函数的方式。(完整代码见附件示例)CheckBox
Tab1
public void onClick(View v) {
Tab1 tab = (Tab1)mTabsAdapter.getItem(0);
tab.toggleEnabled(v);
}
所以我深入研究TabsAdapter
了getItem(...)。这里有什么
私有 ArrayList mFragments = new ArrayList(); // 设置标签等的代码 @Override public Fragment getItem(int position) { Fragment frag = mFragments.get(position); if (frag.getActivity() == null) Log.d(TAG, "getItem: Activity is null");
return mFragments.get(position);
}
在旋转之前会发生什么,getActivity()不是null。旋转后,getActivity()为null。这似乎表明它没有重新创建我认为Fragment
的正确的。Context
然而,这就是我对这类事情的了解结束的地方。
我可以制作mFragments
静态并且它可以工作,但我觉得这不是一个正确的解决方案。
有谁知道为什么Fragment
s 没有正确连接Activity
?