1

我已成功处理配置更改与片段,但我只使用一个XML布局的容器。使用多个布局中断方向更改

现在我需要使用横向模式布局,当我打开我的手机,并试图改变当前显示的片段,我得到一个错误:

E/AndroidRuntime: FATAL EXCEPTION: main 
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState 
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1328) 
at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1346) 
at android.app.BackStackRecord.commitInternal(BackStackRecord.java:729) 
at android.app.BackStackRecord.commit(BackStackRecord.java:705) 

这里是我的两个布局:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/main_layout_container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" /> 

而对于景观之一:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/main_layout_container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="horizontal" /> 

正如你所看到的都是完全一样的除了方向。 我想这个问题可能来自于重新使用以另一个方向添加的旧片段?

感谢您的帮助

编辑: 代码为我的活动

package crysteo.pluggicontroller; 

public class MainFragmentActivity extends FragmentActivity implements StateModifier,IpAddressChangedListener { 

private RemoteFragment remoteFragment; 
private MainFragment mainFragment; 
private DeviceListFragment deviceListFragment; 
private RetainedFragment retainedFragment; 
private HandleConnection handleConnection; 
private ConnectedFragment connectedFragment; 
private CameraFragment cameraFragment; 
private final PluggiHandler handler = new PluggiHandler(this); 


private static class PluggiHandler extends Handler { 
    private final WeakReference<MainFragmentActivity> mainFragmentActivityWeakReference; 

    public PluggiHandler(MainFragmentActivity mainFragmentActivity) { 
     this.mainFragmentActivityWeakReference = new WeakReference<>(mainFragmentActivity); 
    } 

    @Override 
    public void handleMessage(Message msg) { 
     MainFragmentActivity mainFragmentActivity = this.mainFragmentActivityWeakReference.get(); 
     BluetoothConstants.BluetoothMessageWhat msgEnum = BluetoothConstants.BluetoothMessageWhat.values()[msg.what]; 
     switch (msgEnum) { 
      case MESSAGE_STATE_CHANGE: 
       BluetoothConstants.BluetoothStates argEnum = BluetoothConstants.BluetoothStates.values()[msg.arg1]; 
       switch (argEnum) { 
        case STATE_CONNECTED: 
         mainFragmentActivity.connected(); 
         break; 
        case STATE_CONNECTING: 
         Toast.makeText(mainFragmentActivity.getApplicationContext(), R.string.connecting_bluetooth, Toast.LENGTH_SHORT).show(); 
         break; 
        case STATE_NONE: 
         break; 
        default: 
         break; 
       } 
       break; 
      case MESSAGE_WRITE: 
       /*byte[] writeBuf = (byte[]) msg.obj; 
       // construct a string from the buffer 
       String writeMessage = new String(writeBuf); 
       mConversationArrayAdapter.add("Me: " + writeMessage);*/ 
       break; 
      case MESSAGE_READ: 
       /*byte[] readBuf = (byte[]) msg.obj; 
       // construct a string from the valid bytes in the buffer 
       String readMessage = new String(readBuf, 0, msg.arg1); 
       mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage);*/ 
       break; 
      case MESSAGE_DEVICE_NAME: 
       Toast.makeText(mainFragmentActivity, String.format(mainFragmentActivity.getResources().getString(R.string.connected_bluetooth), 
         msg.getData().getString(Constants.DEVICE_NAME)), Toast.LENGTH_SHORT).show(); 
       break; 
      case MESSAGE_TOAST: 
       if (null != mainFragmentActivity) { 
        Toast.makeText(mainFragmentActivity, msg.getData().getString(Constants.TOAST), 
          Toast.LENGTH_SHORT).show(); 
       } 
       break; 
      default: 
       break; 
     } 
     mainFragmentActivity.connected(); 
    } 
} 

; 


@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main_layout); 

    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 

    if (savedInstanceState == null) { 
     retainedFragment = new RetainedFragment(); 
     fragmentTransaction.add(retainedFragment, RetainedFragment.class.toString()); 
     handleConnection = new HandleConnection(this, handler); 
     retainedFragment.setHandleConnection(handleConnection); 

     deviceListFragment = new DeviceListFragment(); 
     remoteFragment = new RemoteFragment(); 
     mainFragment = new MainFragment(); 
     connectedFragment = new ConnectedFragment(); 
     cameraFragment = new CameraFragment(); 
     fragmentTransaction.add(R.id.main_layout_container, mainFragment, MainFragment.class.toString()); 
    } else { 
     mainFragment = (MainFragment) getFragmentManager().findFragmentByTag(MainFragment.class.toString()); 
     deviceListFragment = (DeviceListFragment) getFragmentManager().findFragmentByTag(DeviceListFragment.class.toString()); 
     remoteFragment = (RemoteFragment) getFragmentManager().findFragmentByTag(RemoteFragment.class.toString()); 
     retainedFragment = (RetainedFragment) getFragmentManager().findFragmentByTag(RetainedFragment.class.toString()); 
     connectedFragment = (ConnectedFragment) getFragmentManager().findFragmentByTag(ConnectedFragment.class.toString()); 
     cameraFragment = (CameraFragment) getFragmentManager().findFragmentByTag(CameraFragment.class.toString()); 

     if (mainFragment == null) 
      mainFragment = new MainFragment(); 

     if (deviceListFragment == null) 
      deviceListFragment = new DeviceListFragment(); 

     if (remoteFragment == null) 
      remoteFragment = new RemoteFragment(); 

     if (connectedFragment == null) 
      connectedFragment = new ConnectedFragment(); 

     if (cameraFragment == null) 
      cameraFragment = new CameraFragment(); 

     handleConnection = retainedFragment.getHandleConnection(); 
    } 

    fragmentTransaction.commit(); 

    mainFragment.setBluetoothListener(handleConnection); 
    if (retainedFragment.getSelectedMac() != null) 
     mainFragment.onMacAddressChanged(retainedFragment.getSelectedMac()); 
    remoteFragment.setHandleConnection(handleConnection); 
    mainFragment.setStateModifier(this); 
    deviceListFragment.setStateModifier(this); 
    deviceListFragment.setMacAddressChangedListener(mainFragment); 
    connectedFragment.setStateModifier(this); 
    connectedFragment.setIpAddressChangedListener(this); 
} 

@Override 
public void onDestroy() { 
    retainedFragment.setHandleConnection(handleConnection); 
    super.onDestroy(); 
} 

@Override 
public void listDevices() { 
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 
    fragmentTransaction.replace(R.id.main_layout_container, deviceListFragment, DeviceListFragment.class.toString()); 
    fragmentTransaction.addToBackStack("listDevices"); 
    fragmentTransaction.commit(); 
} 

@Override 
public void deviceSelected(String macAddress) { 
    getFragmentManager().popBackStack(); 
    retainedFragment.setSelectedMac(macAddress); 
    mainFragment.onMacAddressChanged(macAddress); 
} 

@Override 
public void connected() { 
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 
    fragmentTransaction.replace(R.id.main_layout_container, connectedFragment, ConnectedFragment.class.toString()); 
    fragmentTransaction.addToBackStack("connected"); 
    fragmentTransaction.commit(); 
} 

@Override 
public void onBackPressed() { 
    if (getFragmentManager().getBackStackEntryCount() > 0) { 
     getFragmentManager().popBackStack(); 
    } else { 
     super.onBackPressed(); 
    } 
} 

@Override 
public void remoteControl() { 
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 
    fragmentTransaction.remove(connectedFragment); 
    fragmentTransaction.add(R.id.main_layout_container, cameraFragment, CameraFragment.class.toString()); 
    fragmentTransaction.add(R.id.main_layout_container, remoteFragment, RemoteFragment.class.toString()); 
    fragmentTransaction.addToBackStack("manualMode"); 
    fragmentTransaction.commit(); 
} 

@Override 
public void soundsControl() { 
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 
    fragmentTransaction.replace(R.id.main_layout_container, cameraFragment, CameraFragment.class.toString()); 
    fragmentTransaction.addToBackStack("soundControl"); 
    fragmentTransaction.commit(); 
} 

@Override 
public void infoDisplay() { 

} 

@Override 
public void onIpChangedListener(String ip) { 
    cameraFragment.setIp(ip); 
} 
} 

而对于应显示的片段:

public class ConnectedFragment extends Fragment { 

private StateModifier stateModifier; 
private IpAddressChangedListener ipAddressChangedListener; 

@Nullable 
@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    View root = inflater.inflate(R.layout.connected_fragment_layout, container, false); 

    root.findViewById(R.id.remote_control_button).setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      stateModifier.remoteControl(); 
     } 
    }); 

    root.findViewById(R.id.sounds_button).setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      stateModifier.soundsControl(); 
     } 
    }); 

    final EditText editText = (EditText)root.findViewById(R.id.ip_edit_text); 

    root.findViewById(R.id.change_ip_button).setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      ipAddressChangedListener.onIpChangedListener(editText.getText().toString()); 
     } 
    }); 

    return root; 
} 

public void setStateModifier(StateModifier stateModifier) { 
    this.stateModifier = stateModifier; 
} 

public void setIpAddressChangedListener(IpAddressChangedListener ipAddressChangedListener) { 
    this.ipAddressChangedListener = ipAddressChangedListener; 
} 
} 
+0

从活动和片段发布您的代码。问题是别的。 –

回答

0

所以问题来自我的HandleConnection对象。我没有更新对处理程序的引用,这意味着所调用的处理程序是指已经被销毁的活动。

我发现通过在我的片段事务中使用commitAllowingStateLoss()。而不是只得到一个java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState 我得到java.lang.IllegalStateException: Activity has been destroyed错误,这让我猜猜问题是什么。

0

问题来源于这样的事实是,蓝牙连接消息事件调用您的connected()方法,然后执行片段事务以显示ConnectedFragment

因此,这是发生了什么事:

  • 用户旋转设备
  • 活动开始关停,状态保存
  • 关联的事件发生(因为活动尚未完全关闭至今)
  • 尝试片段交易,但状态已保存

您现在有一个竞赛条件。

您需要更仔细地管理这些碎片交易。我会建议开始在connected()开头添加该代码和其他地方的事件可能导致一个片段交易:

if (isFinishing()) { 
     return; 
    } 

那么活动的状态发生时(可能),你会不会尝试片段的交易已经保存。

这个单独的代码片段可能无法解决您的所有问题。您可能需要添加一些生命周期日志记录来分析什么时候发生。然后,您可以添加必要的代码,以确保以正确的顺序发生。

顺便提及:此代码

@Override 
    public void onBackPressed() { 
     if (getFragmentManager().getBackStackEntryCount() > 0) { 
      getFragmentManager().popBackStack(); 
     } else { 
      super.onBackPressed(); 
     } 
    } 

是多余的; FragmentActivityonBackPressed方法已经处理检查片段返回堆栈并在必要时弹出它。也许你会添加更多的自定义后退按钮处理?

+0

感谢kris,我还没有时间去尝试你的建议,但我的蓝牙连接只发生在用户按下按钮时。我认为这意味着不存在任何竞争条件(或者我对此不了解)?在为横向模式添加第二个布局后,问题出现了,但是之前它的工作原理(我仍然会将这些建议考虑在内以避免将来的崩溃!)。 – pLesur

+0

问题出现是因为您无法控制a)BlueTooth何时完成连接,b)用户何时旋转设备。这些旋转可能会发生虚假 - 我将设备放在我的桌子上,并且运动导致旋转。这是一个邪恶的问题,可能90%的测试只是针对这些情况,因为我的大多数错误都是轮换崩溃。 –