简体   繁体   中英

How to prevent a Fragment from being added when an Activity is closing

I am creating an Activity which communicates with a Service to download some data from internet via POST method. To do this, I use Messenger . Here is my code to make it clearer for you:

My onCreated() method:

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);
}

The code in my Service 's thread to post the result data to the Activity via the Messenger object:

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

The code in the Activity to handle the Message from the Service :

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();
        }
    }
}

The problem is: if I open the Activity and close it before the data is downloaded, this code .add(R.id.container, new CommentsFragment()).commit(); gives me the error Can not perform this action after onSaveInstanceState , because this code only gets executed after the data in my Service is processed and sent via the Messenger object, but at that time the Activity is already closed by the user so the Fragment cannot be added. How to solve this issue? How to check if the Activity is not closed/being closed before adding the Fragment ? Or, better, how to stop the thread in which that code is running on Activity 's onDestroy() method so it doesn't get executed if the Activity is closed? Thanks in advance!

In your activity, you should create a boolean to check if the activity is visible or not:

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;
  }
}

And then you modify your Handler class definition:

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();
    }
}
}

The smallest change would be to have a boolean field in the Activity, setting it to true in onResume() and to false in onPause() , and check its value in handleMessage() (ie ignore the message if the flag is currently false).

Another option, instead of using Messenger and handleMessage() , do this with a BroadcastReceiver . Register the receiver in onResume() and unregister it in onPause() . That way the broadcast from the service will be simply ignored.

Both solutions are basically the same, anyway, but broadcasts are somewhat "higher level".

This assumes that you're not interested in the Service's result if the activity is paused. If you are (for example, if you switch out of the application and back in, and you need to display the update) then you should put the received data in a field and process it on the following onResume() .

Your way of doing this is different than how I would handle it but using what you have I would make these adjustments:

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();
        }
    }
}

Then I would use your activities onPause()/onResume() methods to like this:

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM