11

I noticed that sometimes Async task does not work properly , Actually its doInBackground() method does not get called , this happens mostly when any service run in background for that activity. For Example , when music runs in background with service, the Async task does not parse XML in background as its doInBackground does not work that time and the progress Dialog or progressBar kept spinning.

I read in few articles that AsyncTask.THREAD_POOL_EXECUTOR can help in these issues like :

if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
    new Test().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
    new Test().execute();
}

but that did not help in my case. Having the same issue after the above implmentation.

Here I am giving just a bit of my sample code to understand what I am doing::

public class TestAct extends Activity {

    ImageButton play,forward,backward;  
    private ListView mList;
    // many more variables

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

        //binding the service here
        // start service is called

        init();
    }

    private void init(){

        play=(ImageButton)findViewById(R.id.playBtn);
        forward=(ImageButton)findViewById(R.id.forward);
        backward=(ImageButton)findViewById(R.id.backward);  
        mList=(ListView)findViewById(R.id.list);

        new GetData().execute();

        play.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // calling the play() method of ServiceConnection here
            }
        });

            // adding header to Listview
            // other code and click listeners

    }

    class GetData extends AsyncTask<Void, Void, Void>{

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            // starting the progress Bar
            // initializing the Arraylist,Maps etc
        }

        @Override
        protected Void doInBackground(Void... params) {
            //parsing the XML here
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            // stop the ProgressBar 
            // Updating my UI here
                    // setting Adapter for ListView 
        }   
    }
}

This works fine generally but hangs when Service runs in backgound (I mean when music is playing in back).

I am not getting the exact reason behind this problem of Async task. Will mannual thread implementation help in this case ...??

Well, I think the problem is because "Service runs in main thread so when it runs, it blocks my AsyncTask to run"... So I think If we can run Service in background thread then that can help . Thats why I tried IntentService for running service in separate thread but I am in doubt... if IntentService can run for indefinite time similar to Service ... and Also IntentService blocks AsyncTask few times. So I dont't think its 100% perfect solutions for this kind of problem.

Can anyone help me to sort out this problem and understand the complete scenario.

Thanks in advance.

Dinesh Sharma
  • 11,533
  • 7
  • 42
  • 60
  • are you extending Service or IntentService – koti Feb 15 '13 at 09:50
  • I am using service for playing music in background – Dinesh Sharma Feb 15 '13 at 09:54
  • async task should work. you've made mistake somewhere. – Leonidos Feb 15 '13 at 09:57
  • I am pretty much sure that I did not make any mistake in implementing Asynctask as generally(in most cases) it works fine but when music plays in background, the progressBar kept spinning. One thing, I am calling AsyncTask in onResume() method as I need to refresh data each time, the activity comes in foreground. Does it effect the performance of AsyncTask.. I don't think so but let me know if there is any problem in that. – Dinesh Sharma Feb 15 '13 at 10:02
  • Service will run in main thread.So try IntentService instead of Service because IntentService will run in seperate thread – koti Feb 15 '13 at 10:38
  • Will using IntentService instead of service will effect the performance of my app ? As I am using bindService for playing music and also using .aidl , so for using IntentService instead of Service, do I need to make other changes in my Current Service class or I can continue with the same class by just replacing the base Service class with IntentService .. ? – Dinesh Sharma Feb 15 '13 at 10:43
  • No i think it won't decrease the performance.See some samples on IntentService – koti Feb 15 '13 at 11:32
  • ok but As I am using service with Binder so I don't think that's possible with IntentService ... !!! – Dinesh Sharma Feb 15 '13 at 11:54
  • Show us the code where you popup the progressBar and start the AsyncTask. – yorkw Feb 17 '13 at 20:29
  • @yorkw I have updated my code , please check it and let me know if I made some mistake in this code. – Dinesh Sharma Feb 18 '13 at 05:21
  • What music player are you talking about? Is it one your wrote? – Justin Breitfeller Feb 19 '13 at 17:29
  • @JustinBreitfeller yes, I am playing music in background when users chooses any song from the list of song . – Dinesh Sharma Feb 19 '13 at 17:46
  • How are you playing the music? Are you using an AsyncTask that is long running? – Justin Breitfeller Feb 19 '13 at 17:50
  • 1
    try adding android:process=":remote" to your service and check whether asynctask is called, if you run service in a different process then this case might not arise – nandeesh Feb 20 '13 at 14:44

7 Answers7

2

Sometimes you will want more control over your service's lifecycle than what IntentService gives you, in those cases you can just create a thread in the service and run your background code in that. Actually, to be more specific, create a HandlerThread which includes a Looper so you can use the standard android method for communication (messages) between your main thread and the background thread.

Answered here

Community
  • 1
  • 1
Aashish Bhatnagar
  • 2,595
  • 2
  • 22
  • 37
1

I think the problem is starting another GetData AsyncTask before the previous one has been finished. Before executing another task make sure that previous one is complete. To do this use following code:

// make sure we don't collide with another pending AsyncTask
if (getDataTask == null || getDataTask.getStatus() == AsyncTask.Status.FINISHED || getDataTask.isCancelled()) {
    getDataTask= new GetData();
    getDataTask.execute();
} 

Also make sure that you have a reference for running tasks. You can use subclass of Application class for doing this while your application is running or override onSaveInstanceState(Bundle outState) and receive a reference to it in onCreate(Bundle savedInstanceState).

1

Read all the problem and Answers which has been posted here. correct me if i am wrong your scenario is you are parsing the xml and getting the list of songs and when user select any song you want that to be played with service right?

if the Scenario is correct then we can implement it in the much simpler way.

  1. In the Activity, onResume() method parse the XML file and get the list of songs and update the list view(do not start anything related to service here)
  2. when user click on the song then pass the particular key/string to the service with intent and start the service
  3. In the service's OnStartCommand() method get the identifier and start the song as with normal media APIs

That will actually do the work for you.

Regarding the problem of

if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
    new Test().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
    new Test().execute();
}

This is for different behavior of the AsyncTask on Different version of the Android. Looking at your code what is being done is in the Activity you are initializing the service hence the service is running in the background without doing anything fruitful. and when user click on play you are calling play function of service which created problme here.

so to call the function of service from Activity you should right AIDL which you have not mentioned. and if you have wrote so it should be perfect.

but here recommendation is pass the song id to service and it should play from service should not call Service's function in activity.

if you want to update the Song List in the onResume of the activity then you must write AIDL and accomplish the scenario

Hope this will help.

Dinesh Prajapati
  • 9,274
  • 5
  • 30
  • 47
  • thanks drax your valuable suggestion, but I have implemeneted the thing using IntentService instead of Service and replaced Async task with Painless thread and things are working quite good :) – Dinesh Sharma Feb 22 '13 at 11:56
  • 1
    I have implemented your scenario in my test project. you can even use AIDL for that reason. if you found the ans pls accept any one ans. – Dinesh Prajapati Feb 22 '13 at 12:00
1

I noticed that sometimes Async task does not work properly , Actually its doInBackground() method does not get called , this happens mostly

You know that there is a limit of AsyncTasks that can be executed at a time? I had once an issue where a task did't start/work properly and this was because I exceeded that number. Check Android AsyncTask threads limits? for more on that topic.

when any service run in background for that activity. For Example , when music runs in background with service, the Async task does not parse XML in background as its doInBackground does not work that time and the progress Dialog or progressBar kept spinning.

Have you checked the possibilities of dead locks (in particular, if you're using wait() and notify())?

Well, I think the problem is because "Service runs in main thread so when it runs, it blocks my AsyncTask to run"... So I think If we can run Service in background thread then that can help . Thats why I

The things you are going to do in a service should run in an own thread anyway. That way you can be sure that nothing is going to be blocked. If you have something to populate you could use a receiver, for instance.

Hope I could help a bit ...

Community
  • 1
  • 1
Trinimon
  • 13,839
  • 9
  • 44
  • 60
1

Here is a hint, How I finally solved my Problem ::

1) I used IntentService instead of Service as Service runs in mainThread while IntentService runs in a separate Thread than mainThread to make sure that my background Service does not effect my current task . Also , I am using AIDL for communication between my UI and background Thread (this was already working for Service , so nothing new in this part).

2) I used painless thread instead of AsyncTask, I interrupt the thread in onDestroy() method to make sure that the Thread does continue indefinitely.

App seems to perform much better than Earlier now.

Hope this will help others too :)

Dinesh Sharma
  • 11,533
  • 7
  • 42
  • 60
  • This is unfair. People suggested all the solutions… –  Feb 25 '13 at 08:32
  • 1
    @user1521536: You are right that people suggested me the solutions but none of them contain both the solutions hint together which i applied, so just to help others i combined them together for a better solution. – Dinesh Sharma Jan 27 '14 at 07:44
0

Per the Threading Rules section of the Android Developer AsyncTask document, the AsyncTask has to be created and launched on the UI thread, so if you are launching it from a background thread in a Service, that would account for the faulty behavior.

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

Brent Hronik
  • 2,357
  • 1
  • 27
  • 43
  • 1
    To whomever downvoted, could I ask for clarification as to why the downvote? From my understanding of the users question he is launching it in an intent service, which doew not run on the UI thread, unless I was just misinterpeting the bottom statements about the Service with a background thread or IntentService. – Brent Hronik Feb 22 '13 at 16:03
-2

You really shouldn't be using AsyncTasks in general :) There is a pretty good explanation here . Think about what will happen if the user rotates the device, while your task is running. The Activity is recreated, but the task runs in the background and holds a reference to the "old" activity. There are ways to get around this, and they are surely still some cases where an AsyncTasks is the correct approach.

However, your really should consider switching to a Loader or (if you feel adventurous) try RoboSpice :)

stoilkov
  • 1,686
  • 1
  • 11
  • 18