简体   繁体   中英

How to update UI thread when Network call is placed before rotating?

Okay this is driving me nuts. I have a worker thread, (Network call) that needs to run separate of the UI thread, (Its actually a ThreadPoolExecutor but I simplified it to prove my point). If you run this code in portrait, without rotation, the text updates. I put in the delay there to allow for rotations to show my issue. If you start in portrait and before text updates rotation to landscape the text does not update. If you comment the code you can see the listener fire but the text never updates.

I am trying to simulate a custom network call running in a separate thread that may take some time to come back if the user rotates in between then the data gets lost. We are trying to prevent multiple network calls to save data usage on a phone.

package com.example.test;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.res.Configuration;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    int orientation = getResources().getConfiguration().orientation; 
    if (Configuration.ORIENTATION_LANDSCAPE == orientation) { 
        //Do SomeThing; // Landscape
    } else { 
        startBackgroundWork();
        //Do SomeThing;  // Portrait
    } 

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

private Handler mHandler = new Handler();

public void startBackgroundWork() {
    new WorkingThread(new SomeListener() {
        public void onSomethingDone(final Object result) {

            mHandler.post(new Runnable() {
                public void run() { 
                    ((TextView)findViewById(R.id.text)).setText((String)result);
                    //showMyDialog(result); 
                }
            });

        }    
    }).start();
}

public interface SomeListener {
    public void onSomethingDone(Object result);
}

public class WorkingThread extends Thread {
    private SomeListener mListener;

    public WorkingThread(SomeListener listener) {
        mListener = listener;
    }

    public void run() {
        /* do some work */
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        mListener.onSomethingDone("New Text");
    }
}
}

It's because on rotation, the activity is re created, therefore all your code is binded to the old activity. You should make a reference to your working thread :

private static WorkingThread mWorkingThread;
public void startBackgroundWork() {
    mWorkingThread = new WorkingThread(new SomeListener() {
        public void onSomethingDone(final Object result) {

            mHandler.post(new Runnable() {
                public void run() { 
                    ((TextView)findViewById(R.id.text)).setText((String)result);
                    //showMyDialog(result); 
                }
            });

        }    
    }).start();
}

then onCreate update it :

public class WorkingThread extends Thread {
    private SomeListener mListener;

    public WorkingThread(SomeListener listener) {
        mListener = listener;
    }

    public void run() {
        /* do some work */
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        mListener.onSomethingDone("New Text");
    }

    public void updateListener(SomeListener listener) {
        mListener = listener;
    }
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    startBackgroundWork();
}

public void startBackgroundWork() {
    if (mWorkingThread == null || mWorkingThread.isFinished()) { // Use a boolean to know if it still running


    mWorkingThread  = new WorkingThread(new SomeListener() {
        public void onSomethingDone(final Object result) {

            mHandler.post(new Runnable() {
                public void run() { 
                    ((TextView)findViewById(R.id.text)).setText((String)result);
                    //showMyDialog(result); 
                }
            });

        }    
    });
        mWorkingThread.start();

    } else { 
        mWorkingThread.updateListener(new SomeListener() {
        public void onSomethingDone(final Object result) {

            mHandler.post(new Runnable() {
                public void run() { 
                    ((TextView)findViewById(R.id.text)).setText((String)result);
                    //showMyDialog(result); 
                }
            });

        }    
    });
    } 
}

But there is some improvments you could make :

  • The WorkingThread class should be static to avoid direct reference to the old activity : Java: Static vs non static inner class

  • Then make a reference to the current activity, and update it when it is recreated

  • Make a method for update of the text, instead of having the code directly in the listener

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