【问题标题】:How to prevent a Fragment from being added when an Activity is closing如何防止 Activity 关闭时添加 Fragment
【发布时间】:2014-07-14 00:28:14
【问题描述】:

我正在创建一个Activity,它与Service 通信以通过POST 方法从互联网下载一些数据。为此,我使用Messenger。这是我的代码,让您更清楚:

我的onCreated() 方法:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_comments);

    CommentsHandler commentsHandler = new CommentsHandler(this, savedInstanceState);
    Messenger messenger = new Messenger(commentsHandler);

    Intent serviceIntent = new Intent(this, WindowService.class);
    serviceIntent.putExtra("messenger", messenger);
    serviceIntent.putExtra("state", 888);
    serviceIntent.putExtra("number", getIntent().getStringExtra("number"));
    startService(serviceIntent);
}

我的Service 线程中的代码通过Messenger 对象将结果数据发布到Activity

    /** ... **/
    Messenger messenger = intent.getParcelableExtra("messenger");
    /** ... **/
    Message resultMsg = this.obtainMessage();
    resultMsg.obj = jParser.getArrayList(); //This is an ArrayList of my downloaded data.
    messenger.send(resultMsg);

Activity 中的代码用于处理来自ServiceMessage

public static class CommentsHandler extends Handler {
    Bundle mSavedInstanceState;
    ActionBarActivity activity;

    public CommentsHandler(Activity a, Bundle savedInstanceState) {
        activity = (ActionBarActivity) a;
        mSavedInstanceState = savedInstanceState;
    }

    @Override
    public void handleMessage(Message msg) {
        comments = (ArrayList<HashMap<String, String>>) msg.obj;
        if (mSavedInstanceState == null && msg.arg1 != 793) {
            activity.getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new CommentsFragment()).commit();
        } else if (msg.arg1 == 793) { //793 is my preferred code to determine
                                      //if the internet connection could not be
                                      //established when the Service was trying
                                      //to download the data.
            activity.finish();
        }
    }
}

问题是:如果我在下载数据之前打开Activity并关闭它,则此代码.add(R.id.container, new CommentsFragment()).commit();会给我错误Can not perform this action after onSaveInstanceState,因为此代码仅在我的Service中的数据之后执行通过Messenger 对象处理和发送,但当时Activity 已被用户关闭,因此无法添加Fragment。如何解决这个问题?如何在添加Fragment 之前检查Activity 是否未关闭/正在关闭?或者,更好的是,如何停止在ActivityonDestroy() 方法上运行该代码的线程,以便在Activity 关闭时不会执行它?提前致谢!

【问题讨论】:

    标签: java android android-fragments android-service android-handler


    【解决方案1】:

    在您的活动中,您应该创建一个布尔值来检查活动是否可见:

    public ActionBarActivity extends Activity {
      private boolean isActivityVisible = false;
    
      @Override
      protected void onResume(){
         isActivityVisible = true;
      }
    
      @Override
      protected void onPause(){
         isActivityVisible = false;
      }
    
      public boolean isVisible(){
         return this.isActivityVisible;
      }
    }
    

    然后你修改你的 Handler 类定义:

    public static class CommentsHandler extends Handler {
    Bundle mSavedInstanceState;
    ActionBarActivity activity;
    
    public CommentsHandler(Activity a, Bundle savedInstanceState) {
        activity = (ActionBarActivity) a;
        mSavedInstanceState = savedInstanceState;
    }
    
    @Override
    public void handleMessage(Message msg) {
        // here you check if your activity is no longer visible and then break up
        if(activity == null || !activity.isVisible())
            return;
    
        comments = (ArrayList<HashMap<String, String>>) msg.obj;
        if (mSavedInstanceState == null && msg.arg1 != 793) {
            activity.getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new CommentsFragment()).commit();
        } else if (msg.arg1 == 793) { //793 is my preferred code to determine
                                      //if the internet connection could not be
                                      //established when the Service was trying
                                      //to download the data.
            activity.finish();
        }
    }
    }
    

    【讨论】:

    • 伟大而非常简单的解决方案,但@matiash 的答案更全面,解释更合理。谢谢!
    【解决方案2】:

    最小的变化是在 Activity 中有一个布尔字段,在 onResume() 中将其设置为 true,在 onPause() 中设置为 false,并检查其在 handleMessage() 中的值(即,如果标志为目前为假)。

    另一个选项,而不是使用 Messenger 和 handleMessage(),使用 BroadcastReceiver 执行此操作。在onResume() 中注册接收器,在onPause() 中注销它。这样,来自服务的广播将被简单地忽略。

    无论如何,两种解决方案基本相同,但广播有点“更高级别”。

    这假设如果活动暂停,您对服务的结果不感兴趣。如果您是(例如,如果您退出应用程序并重新进入,并且需要显示更新),那么您应该将接收到的数据放在一个字段中并在以下onResume() 上处理它。

    【讨论】:

    • 很好的答案,非常感谢!但是如果我选择最简单的方法(你上面描述的布尔方法),我的代码会比BroadcastReceiver 实现更糟糕或更不合适吗?
    • @Salivan 一点也不。我只是想指出LocalBroadcastManager 非常适合服务->应用程序中的活动通信
    • 好的。非常感谢!
    【解决方案3】:

    您的处理方式与我的处理方式不同,但使用您所拥有的,我会做出这些调整:

    public static class CommentsHandler extends Handler {
        Bundle mSavedInstanceState;
        ActionBarActivity activity;
    
        public CommentsHandler(Activity a, Bundle savedInstanceState) {
            activity = (ActionBarActivity) a;
            mSavedInstanceState = savedInstanceState;
        }
    
        public void setActivity(Activity a){
            activity = a;
        }
    
        @Override
        public void handleMessage(Message msg) {
            if(activity == null){
                return;
            }
            comments = (ArrayList<HashMap<String, String>>) msg.obj;
            if (mSavedInstanceState == null && msg.arg1 != 793) {
                activity.getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new CommentsFragment()).commit();
            } else if (msg.arg1 == 793) { //793 is my preferred code to determine
                                          //if the internet connection could not be
                                          //established when the Service was trying
                                          //to download the data.
                activity.finish();
            }
        }
    }
    

    然后我会使用你的活动 onPause()/onResume() 方法来喜欢这个:

    @Override
    protected void onPause() {
        super.onPause();
        commentsHandler.setActivity(null);  
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        commentsHandler.setActivity(this);  
    }
    

    【讨论】:

    • 很酷的答案!我非常喜欢您的逻辑,但遗憾的是您没有按照您的方式与我分享。还是谢谢你!
    • 嗯,我不知道你项目的全部范围,所以我会做的方式可能会改变,但我会使用这篇文章中提到的库:stackoverflow.com/questions/16902716/…
    • 嗯,我不知道实现这个库的复杂性,但我想我不必为了下载几个 JASON 字符串而使用整个库。无论如何,非常感谢。
    猜你喜欢
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 1970-01-01
    • 2017-03-31
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    相关资源
    最近更新 更多