2

OK, so I know how to do a backround task, I know how to do a periodic task (using handle postdelayed and runnable), I also know how to do UI task from background thread (via handler) but I am not able to execute a periodic background task that does some action on the UI thread.

I am trying to execute some background task every minute in which I have to make a network call. After the call is over, depending on the output I have to update the UI. I tried to do something like this

private void DoTask() {
        Thread thread = new Thread() {
            public void run() {
                Looper.prepare();
                final Handler handler = new Handler();
                handler.post(netRunnable);
                Looper.loop();
            }
        };
        thread.start();
}

Runnable netRunnable = new Runnable() {
    @Override
    public void run() {
        handler.getLooper().prepare();
        final Handler handler1 = new Handler(Looper.getMainLooper());
        if ( do background work and check result){
            handler1.post(new Runnable() {
                @Override
                public void run() {
                    //Do UI Task
                }
            });
        }
        handler.getLooper().loop();
        handler.postDelayed(netRunnable, 60000);
    }
}

I understand that there might be some fundamental flaws with my implementation but I do not know how to do this task properly. Right now it is giving the error that Only one Looper may be created per thread.I get what it is trying to say. But can anyone please suggest to do this the right way.

varunkr
  • 5,364
  • 11
  • 50
  • 99

3 Answers3

4

You could use Async Tasks. These are designed for it :

http://developer.android.com/reference/android/os/AsyncTask.html

It allows you to execute a network call in the background, then when you get the result, execute an action on the UI thread

Declaration :

 private class MyTask extends AsyncTask<Input, Void, Output> {
 protected Output doInBackground(Input... inputs) {
       // do something on the network
       return myOutput;// use this to transmit your result
 }

 protected void onPostExecute(Output result) {
     // do something on UI thread with the result
 }

}

If you want to repeat it, just create a runnable to launch it, and after every call, schedule the next one :

MyTask myTask;
Handler handler = new Handler();

    Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                MyTask myTask = new MyTask();
                myTask.execute(myArg);
                handler.postDelayed(netRunnable, 60000); // schedule next call
            }
        }

To launch it for the first time :

handler.postDelayed(myRunnable, 60000);

Or, if you want to launch it immediately :

handler.post(myRunnable);

Do not forget to cancel the Task when your activity is destroyed :

myTask.cancel(true);
Yves Delerm
  • 785
  • 4
  • 10
  • What if you rotate the phone while asyncTask is running? – AlbAtNf Oct 09 '15 at 15:37
  • It depends whether a configuration change event is triggered. If so, the activity is destroyed and the AsyncTask needs to be cancelled. If there is no configuration change, activity is not destroyed, so I think it is OK. – Yves Delerm Oct 09 '15 at 15:41
  • If I look at [this](http://stackoverflow.com/q/4748964/4791726), I think the task will not be cancelled that easily. You might also loose the reference to a valid activity. Cancelling network task might also not be the best idea. – AlbAtNf Oct 09 '15 at 15:45
  • I tdo not think that is really what the link means. Whether or not this will actually cancel anything is dependent a bit upon what you are doing. You remain free to check whether the task has been cancelled. Also, if you want it, the network task can continue on its own. – Yves Delerm Oct 09 '15 at 15:52
  • What I mean: You can not simply call `myTask.cancel(true)` and the task stops automatically. You have to handle this condition in the doInBackground of the Task. And because you could loose the reference to your Activity, you have to check that aswell. Just some points that you should be aware of, when using AsyncTasks. – AlbAtNf Oct 09 '15 at 15:59
  • That is not exact. If you handle it correctly, you will never lose (and not "loose") the reference to your activity. – Yves Delerm Oct 09 '15 at 16:01
  • As I stated before, and it is explained in the link you posted : "Whether or not this will actually cancel anything is dependent a bit upon what you are doing". Please do not be confused between the background task and the UI task. If you want to cancel the background task, you have to check it regularly. Any way, if you call cancel(), the PostExecute() method will not be called, so potential activity reference loss, is not dangerous – Yves Delerm Oct 09 '15 at 16:08
  • @YvesDelerm Thanks for the response but during these tasks there might be swithing of activities. As such I do not think AsyncTask will be the ight way to go in that case !! – varunkr Oct 09 '15 at 16:18
  • OK, I understand. My answer is more for general cases. Maybe you should precise it in your question, in order to have more specific answers. – Yves Delerm Oct 09 '15 at 16:28
1

Maybe you are better of, creating a seperate (Intent)Service and calling it periodically with postDelayed. Create a BroadcastReceiver in your Activity and handle UI changes there.

Another hint for handling UI changes from other threads: It is not possible. Therefore you need to call runOnUiThread. Here is how to use it

Community
  • 1
  • 1
AlbAtNf
  • 3,859
  • 3
  • 25
  • 29
  • Intent service is an option but there are two reasons i do not want to use it. Firstly I don't need to do the task while the app is in the background which is the main reason for using IntentService. Secondly my need is something that self runs periodically, and I think it can be done in a simpler way. Thanks for the response anyways. – varunkr Oct 09 '15 at 16:25
0

If activities are frequently switching, why not reversing the responsibilities. You might create a service which executes a periodic network task.

Then, - either your activities periodically call this service to get the value. - or you use a listener system : you create an interface that your activities must implement in order to get notified from the task completion

Yves Delerm
  • 785
  • 4
  • 10