【问题标题】:ResultReceiver doesn't survire to screen rotationResultReceiver 无法适应屏幕旋转
【发布时间】:2012-06-07 07:16:54
【问题描述】:

我正在 Android 中实现一个 REST 客户端。 我已经看到了一个使用Service 执行与服务器的连接并通知ResultReceiver 操作完成的示例。我正在从片段调用服务,如果我在服务运行时尝试旋转屏幕,ResultReceiver 中的 getActivity() 方法会返回 null,因为该片段可能不再处于布局中。

片段中的回调方法:

@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
    Response response = (Response) resultData
            .getSerializable(RestService.RESULT);
    if (resultCode == RestService.SUCCESS
            && response != null) {
        if (getActivity() != null) {
            recommendationResponse = response;
            getLoaderManager().restartLoader(0, new Bundle(),
                    Fragment.this);
        }

    }
}

getActivity() 返回 null。 这是正常的吗?即使在屏幕旋转时,我可以使用什么方法来允许通知?本地广播?

【问题讨论】:

    标签: android rest service


    【解决方案1】:

    不,

    android:configChanges="orientation"
    

    不是解决方案。

    使用 ResultReceiver I:

    • 保存方向变化:

      @Override
      public void onSaveInstanceState(Bundle outState) {
          outState.putParcelable(Consts.RECEIVER, mReceiver);
          super.onSaveInstanceState(outState);
      }
      
    • 重置接收器:

      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
          Bundle savedInstanceState) {
      
          if (savedInstanceState != null) {
              mReceiver = savedInstanceState.getParcelable(Consts.RECEIVER);
          }
          else {
              mReceiver = new MyResultReceiver(new Handler());
          }
          mReceiver.setReceiver(this);
      }
      

    这是我的 ResultReceiver 类:

    import android.os.Bundle;
    import android.os.Handler;
    import android.os.ResultReceiver;
    
    public class MyResultReceiver extends ResultReceiver {
        private Receiver mReceiver;
    
        public MyResultReceiver(Handler handler) {
            super(handler);
        }
    
        public void setReceiver(Receiver receiver) {
            mReceiver = receiver;
        }
    
        public interface Receiver {
            public void onReceiveResult(int command, Bundle resultData);
        }
    
        @Override
        protected void onReceiveResult(int command, Bundle resultData) {
            if (mReceiver != null) {
                mReceiver.onReceiveResult(command, resultData);
            }
        }
    }
    

    【讨论】:

    • 太棒了!我看到了许多其他与ResultReceiver 相关的类似问题(有很多赞成票),其中任何一个都成功地解决了活动娱乐等常见场景。
    • 在调用 getParcelable() 时如何避免 onCreateView() 中的 ClassCastException? getParcelable() 不会返回 ResultReceiver 实例(不是您的子类的实例),因为您的子类没有实现 Parcelable.CREATOR?
    • @Alan 根据我的测试,当您旋转设备时,上述方法有效。但是,如果 android 在后台关闭应用程序并再次启动它,我会在 onCreateView() 中得到 ClassCastException。我不知道为什么,但这是我从测试中发现的......
    • @MicroR 我猜这是因为在旋转时,Bundle 不会序列化为 Parcel,它会保留在内存中,因此您可以将原始对象取回。如果应用程序被终止(内存压力),Bundle 很可能会变成一个 Parcel,您在重新提取对象时遇到问题,因为 Parcel 只会返回一个基本的 ResultReceiver。我还没有找到好的解决方案。
    • @Alan 确实!这就说得通了。我在这里提出了一个问题(stackoverflow.com/q/37439838/3075340),但是是否可以使自定义 ResultReceiver 实现 parcelable 或 no..?
    【解决方案2】:

    我正在使用使用LocalBroadcastManager 注册的BroadcastReceiver,它工作正常。这不是那么简单。是否存在更好的解决方案?

    【讨论】:

      【解决方案3】:

      我想我偶然发现了同样的问题,并通过在我的 ResultReceiver 的 onReceivedResult 方法中验证 NULL 来解决它。此处发布的代码适用于工作片段(没有 UI 的片段和 onCreate 中的 setRetainInstance(true))

      protected void onReceiveResult(int resultCode, Bundle resultData) {
                  //Verify activity
                  if(getActivity() != null){
                      //Handle result
                  }else{
                      notificationPending = true;                 
                  }
              }
      

      notificationPending 标志帮助片段在未找到活动时保持未决通知(活动在片段分离上不可用)。

      当片段重新附加到活动时,我执行此逻辑

      public void onAttach(Activity activity){
          super.onAttach(activity);
              if(notificationPending){
                  //Handle notification
                  notificationPending = false;
              }
      }
      

      希望对您有所帮助。如果您愿意,可以询问更多详细信息。干杯

      【讨论】:

        【解决方案4】:

        是的,这很正常,因为 ResultReceiver 可能是“无头的”。

        我尝试将ResultReceiver 保存在onSaveInstanceState(),但它不起作用,因为更新,当接收Fragment 被破坏、丢失以及对回调的引用时发生。

        可以在此处找到解释和可能的解决方案:https://stanmots.blogspot.com/2016/10/androids-bad-company-intentservice.html

        另一个关于这个问题的好读物: https://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

        我的完整解决方案如何使用ResultReceiver 可以在这里找到: https://stackoverflow.com/a/54334864/6747171

        【讨论】:

          【解决方案5】:

          getActivity() 返回 null。这正常吗?

          Android 活动在设备旋转后重新创建。

          重新创建活动后,它不包含旧上下文。这就是为什么您将 getActivity() 设为 null

          我可以使用什么方法来允许屏幕上的通知 回转?本地广播?

          如果您不想在屏幕旋转上重新创建活动,请在清单中提及

                  <activity
                      android:name=".MyActivity"
                      android:configChanges="orientation"    <<<<<<<<<
                      android:label="@string/app_name"
                      android:screenOrientation="portrait" >
                      <intent-filter>
                          <action android:name="android.intent.action.MAIN" />
          
                          <category android:name="android.intent.category.LAUNCHER" />
                      </intent-filter>
                  </activity>
          

          最后,您必须在 Activity 中覆盖关注。

          @Override
              public void onConfigurationChanged(Configuration newConfig)
              {
                  // TODO Auto-generated method stub
                  super.onConfigurationChanged(newConfig);
              }
          

          【讨论】:

          • 感谢您的回答。实际上,我宁愿不在清单上设置 screenOrientation,因为横向模式下的布局不同,所以我无法设置。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-12
          • 1970-01-01
          相关资源
          最近更新 更多