WebViewClient.shouldOverrideUrlLoading中的FragmentTransaction抛出IllegalStateException

Bri*_*SFT 2 java android android-fragments otto

我似乎正在与竞争条件作斗争,其原因似乎无法确定.执行下面的代码时,我会间歇性地获得下面的堆栈跟踪.

是否有一些明显的片段生命周期规则我不服从?我不清楚明确禁止我在这里执行事务处理事件的内容.

我正在使用a WebViewClient来检测在本地.html文档中单击的外部URL - 例如,指向非本地主机的URL.我正在使用Otto EventBus将这些行动发布到Activity.当Activity收到这些事件时,我想Fragment通过调用显示不同的外部URLFragmentTransaction.replace()


DefaultWebViewClient.java

@Override
  public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
    boolean shouldOverride;
    if (urlIsLocal(url)) {
      shouldOverride = super.shouldOverrideUrlLoading(view, url);
    } else {
      // trigger an event for the fragment to swap out
      // return true to tell the webview not to load it...
      EventBus.getInstance().post(new LoadExternalUrlEvent(url));
      shouldOverride = true;
    }
    return shouldOverride;
  }
Run Code Online (Sandbox Code Playgroud)

FragmentActivity.java

@Subscribe
  public void onLoadExternalUrlEvent(LoadExternalUrlEvent externalLoadEvent) {
    final BrowserFragment browserFragment = new BrowserFragment();
    Bundle args = new Bundle();
    args.putSerializable(BrowserFragment.ARG_LOAD_EXTERNAL_URL_EVENT, externalLoadEvent);
    browserFragment.setArguments(args);
    getSupportFragmentManager().beginTransaction()
        .replace(R.id.fragment_container, browserFragment, BrowserFragment.FRAGMENT_TAG)
        .addToBackStack(null).commit();
  }
Run Code Online (Sandbox Code Playgroud)

LoadExternalUrlEvent.java

public class LoadExternalUrlEvent implements Serializable {

  private static final long serialVersionUID = 1L;

  public final String url;

  public LoadExternalUrlEvent(String url) {
    this.url = url;
  }

  @Override
  public String toString() {
    return "LoadExternalUrlEvent [url=" + url + "]";
  }

}
Run Code Online (Sandbox Code Playgroud)

EventBus.java

import com.squareup.otto.Bus;

public class EventBus {

  private static Bus _INSTANCE;

  public static synchronized Bus getInstance() {
    if (null == _INSTANCE) {
      _INSTANCE = new Bus();
    }
    return _INSTANCE;
  }

}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪

 java.lang.RuntimeException: Could not dispatch event: class <omitted>.LoadExternalUrlEvent to handler [EventHandler public void <omitted>Activity.onLoadExternalUrlEvent(<omitted>LoadExternalUrlEvent)]: Can not perform this action after onSaveInstanceState
    at com.squareup.otto.Bus.throwRuntimeException(Bus.java:456)
    at com.squareup.otto.Bus.dispatch(Bus.java:386)
    at com.squareup.otto.Bus.dispatchQueuedEvents(Bus.java:367)
    at com.squareup.otto.Bus.post(Bus.java:336)
    at <omitted>DefaultWebViewClient.shouldOverrideUrlLoading(DefaultWebViewClient.java:51)
    at com.android.webview.chromium.WebViewContentsClientAdapter.shouldOverrideUrlLoading(WebViewContentsClientAdapter.java:293)
    at com.android.org.chromium.android_webview.AwContentsClientBridge.shouldOverrideUrlLoading(AwContentsClientBridge.java:96)
    at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
    at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:27)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:157)
    at android.app.ActivityThread.main(ActivityThread.java:5356)
    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:1265)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
    at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1360)
    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1378)
    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
    at <omitted>Activity.run(<omitted>Activity.java:162)
    at <omitted>Activity.onLoadExternalUrlEvent(<omitted>Activity.java:156)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.squareup.otto.EventHandler.handleEvent(EventHandler.java:89)
    at com.squareup.otto.Bus.dispatch(Bus.java:384)
    ... 15 more
 A/libc(2689): Fatal signal 6 (SIGABRT) at 0x00000a81 (code=-6), thread 2689
Run Code Online (Sandbox Code Playgroud)

Bri*_*SFT 7

我发现了这个问题.

因为我在打电话EventBus.register(),Activity.onCreate()所以Activity我的背板上有多个实例,可以作为这些事件的响应者.

解决方案是Activity尽可能延迟注册

@Override
  protected void onResume() {
    super.onResume();
    EventBus.getInstance().register(this);
  }

  @Override
  protected void onPause() {
    EventBus.getInstance().unregister(this);
    super.onPause();
  }
Run Code Online (Sandbox Code Playgroud)

或者将您声明Activity为单个实例

android:launchMode="singleTask"
Run Code Online (Sandbox Code Playgroud)