Android 从意图处理程序提交片段事务时出错
我正试图写一个简单的音乐播放器,却遇到了这样的问题。在我的UI中,我有几个片段,用于不同的歌曲显示模式(例如,所有音乐、选定文件夹中的音乐、播放列表中的音乐等等)。我还有一个播放音乐的服务 当用户在播放状态下关闭播放器时,我想保存UI状态(即当前显示片段),并在再次打开播放器后恢复此状态(如果用户在暂停状态下关闭播放器,则不需要) 为了保存状态,我使用上面提到的Android 从意图处理程序提交片段事务时出错,android,Android,我正试图写一个简单的音乐播放器,却遇到了这样的问题。在我的UI中,我有几个片段,用于不同的歌曲显示模式(例如,所有音乐、选定文件夹中的音乐、播放列表中的音乐等等)。我还有一个播放音乐的服务 当用户在播放状态下关闭播放器时,我想保存UI状态(即当前显示片段),并在再次打开播放器后恢复此状态(如果用户在暂停状态下关闭播放器,则不需要) 为了保存状态,我使用上面提到的服务。在我的活动的ondestory()方法中,我放置了恢复到intent所需的所有数据,并调用startService(intent)
服务。在我的活动的ondestory()
方法中,我放置了恢复到intent所需的所有数据,并调用startService(intent)
。服务将此数据保存到本地变量。在我的活动的onCreate()
方法中,我有意调用startService
,其中包含保存状态的请求。在服务中,我使用LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
方法将保存的数据放入intent并发送到Activity
。在我的活动的内部BroadcastListener
类中
我接收到这个意图并提取数据。看来没关系
但当我试图恢复用户关闭播放器时显示的片段时,问题就开始了。应用程序崩溃,出现未处理的异常。
这里是backstack:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1377)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1395)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:637)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:616)
at com.borune.test.MainActivity.switchFragments(MainActivity.java:58)
at com.borune.test.MainActivity$MyServiceListener.onReceive(MainActivity.java:102)
at android.support.v4.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:297)
at android.support.v4.content.LocalBroadcastManager.access$000(LocalBroadcastManager.java:46)
at android.support.v4.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:116)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5032)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
我在谷歌上搜索过这个例外,但所有提出的解决方案对我的情况都没有帮助。我写了一个简单的项目,重复描述了这个问题。代码如下:
MainActivity.java:
public class MainActivity extends ActionBarActivity {
private int current_fragment;
private FragmentA fragmentA = null;
private FragmentB fragmentB = null;
private MyServiceListener myServiceListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
current_fragment = 1;
switchFragments(null);
myServiceListener = new MyServiceListener();
LocalBroadcastManager.getInstance(this).registerReceiver(myServiceListener,new IntentFilter(MyService.RESPONSE_RESTORE));
requestState();
}
public void switchFragments(View view) {
switch(current_fragment) {
case 1 : {
if(fragmentA == null) {
fragmentA = FragmentA.newInstance();
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, fragmentA);
current_fragment = 1;
transaction.commit();
current_fragment = 2;
break;
}
case 2 : {
if(fragmentB == null) {
fragmentB = FragmentB.newInstance();
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, fragmentB);
current_fragment = 1;
transaction.commit();
current_fragment = 1;
break;
}
}
}
protected void onDestroy(){
super.onDestroy();
Log.d("log", "onDestroy() called, saving fragment number");
Intent intent = new Intent(this,MyService.class);
intent.setAction(MyService.SAVE_STATE);
intent.putExtra(MyService.FRAGMENT_NUMBER,current_fragment);
startService(intent);
}
private class MyServiceListener extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(MyService.RESPONSE_RESTORE)) {
current_fragment = intent.getIntExtra(MyService.FRAGMENT_NUMBER,-1);
Log.d("log", "received fragment number, restoring now");
switchFragments(null);
}
}
}
private void requestState() {
Intent intent = new Intent(this,MyService.class);
intent.setAction(MyService.REQUEST_RESTORE);
startService(intent);
}
}
MyService.java
public class MyService extends Service {
public static final String REQUEST_RESTORE = "action.REQUEST_RESTORE";
public static final String RESPONSE_RESTORE = "action.RESPONSE_RESTORE";
public static final String SAVE_STATE = "action.SAVE_STATE";
public static final String FRAGMENT_NUMBER = "FRAGMENT_NUMBER";
private int fragment_number = -1;
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if(action.equals(REQUEST_RESTORE)) {
if(fragment_number != -1)
sendState();
} else if (action.equals(SAVE_STATE)) {
fragment_number = intent.getIntExtra(FRAGMENT_NUMBER,-1);
}
return START_NOT_STICKY;
}
private void sendState() {
Intent intent = new Intent(RESPONSE_RESTORE);
intent.putExtra(FRAGMENT_NUMBER,fragment_number);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
在这个应用程序中,我有一个带有容器和带有android:onClick=“switchFragments”
的按钮的布局。关闭应用程序并再次打开后,我收到相同的异常
有人能解释一下,为什么会发生这个错误以及如何解决它吗?这个线程将解释发生了什么:
简短的回答,但可能很危险:使用commitAllowingStateLoss()
而不是commit()
,但如果不小心,它可能会破坏某些东西
至于我所做的,我创建了一个名为“isSafeToCommitFragment”的布尔标志,在默认情况下将其设置为false,然后将该值分配给活动生命周期,如下所示:
if (isSafeToCommitFragment) {
fragmentTransaction.commit();
}
- onDestroy():false
- onPause():false
- onResume():false
- onStart():false
- onStop():false
- onPostResume():true
调用fragmentTransaction.commit()
之前,请检查以下标志:
if (isSafeToCommitFragment) {
fragmentTransaction.commit();
}
在哪里调用LocalBroadcastManager.getInstance(this).unregisterReceiver()
?如果您不想在活动被销毁后接收广播,则需要取消注册。