当服务在后台运行Android时,异步任务无法正常工作(doInBackground不执行)

时间:2013-02-15 09:46:33

标签: android multithreading service android-asynctask intentservice

我注意到有时Async任务无法正常工作,实际上它的 doInBackground()方法不会被调用,这种情况主要发生在任何服务在该活动的后台运行时。 例如,当音乐在后台运行服务时,Async任务不会在后台解析XML,因为它的doInBackground在那段时间不起作用,并且进度Dialog或progressBar一直在旋转。

我在一些文章中读到 AsyncTask.THREAD_POOL_EXECUTOR 可以帮助解决以下问题:

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

在我的案例中没有帮助。在上述实施后遇到同样的问题。

这里我只提供一些示例代码来了解我在做什么::

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

一般来说效果很好但是当服务在后面运行时挂起(我的意思是当音乐在后面播放时)。

我没有得到Async任务问题背后的确切原因。 在这种情况下,mannual线程实现会有帮助...... ??

嗯,我认为问题是因为“服务在主线程中运行所以当它运行时,它会阻止我的AsyncTask运行”......所以我想如果我们可以在后台线程中运行Service那么可以帮助。这就是为什么我尝试使用IntentService在单独的线程中运行服务但是我有疑问...如果IntentService可以无限期地运行,类似于Service ...而且IntentService也会阻止AsyncTask几次。 所以我不认为它是这种问题的100%完美解决方案。

任何人都可以帮我解决这个问题,并了解完整的情况。

提前致谢。

7 个答案:

答案 0 :(得分:3)

有时您会希望更多地控制服务的生命周期而不是IntentService为您提供的服务,在这种情况下,您可以在服务中创建一个线程并在其中运行您的后台代码。实际上,更具体地说,创建一个包含Looper的HandlerThread,这样您就可以使用标准的android方法在主线程和后台线程之间进行通信(消息)。

Answered here

答案 1 :(得分:1)

我认为问题是在上一个问题完成之前开始另一个GetData AsyncTask。在执行另一个任务之前,请确保先前的任务完成。为此,请使用以下代码:

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

还要确保您有运行任务的参考。在应用程序运行或覆盖Application时,您可以使用onSaveInstanceState(Bundle outState)类的子类来执行此操作 并在onCreate(Bundle savedInstanceState)中收到对它的引用。

答案 2 :(得分:1)

阅读此处发布的所有问题和答案。纠正我,如果我错了你的情况是你正在解析xml并获得歌曲列表,当用户选择你希望用服务播放的任何歌曲时?

如果方案是正确的,那么我们可以用更简单的方式实现它。

  1. 在活动中,onResume()方法解析XML文件并获取歌曲列表并更新列表视图(不要在此处启动与服务相关的任何内容)
  2. 当用户点击歌曲然后将特定的键/字符串传递给具有意图的服务并启动服务
  3. 在服务的OnStartCommand()方法中获取标识符并像使用普通媒体API一样启动歌曲
  4. 这实际上是为你做的工作。

    关于

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

    这适用于不同版本的Android上AsyncTask的不同行为。 查看代码正在进行的操作是在初始化服务的Activity中,因此服务在后台运行而不做任何有益的事情。 当用户点击播放时,你正在调用服务的播放功能,这里创建了问题。

    所以要从Activity调用服务功能,你应该对你没有提到的AIDL。如果你写的那么它应该是完美的。

    但是这里的建议是将歌曲ID传递给服务,它应该从服务中播放,不应该在活动中调用服务的功能。

    如果要更新活动的onResume中的歌曲列表,则必须编写AIDL并完成场景

    希望这会有所帮助。

答案 3 :(得分:1)

  

我注意到有时异步任务无法正常工作   它的doInBackground()方法不会被调用,这主要发生在

您知道可以一次执行AsyncTasks的限制吗?我曾经遇到一个问题,即任务没有开始/正常工作,这是因为我超过了这个数字。有关该主题的更多信息,请查看Android AsyncTask threads limits?

  

当任何服务在该活动的后台运行时。例如 ,   当音乐在后台运行时,Async任务不会   在后台解析XML,因为它的doInBackground不起作用   并且进度Dialog或progressBar一直在旋转。

您是否检查过死锁的可能性(特别是,如果您使用的是wait()notify())?

  

嗯,我认为问题是因为“服务在主线程中运行所以   当它运行时,它会阻止我的AsyncTask运行“......所以我想如果可以的话   然后在后台线程中运行Service可以提供帮助。那就是为什么我

您在服务中要做的事情无论如何都应该在自己的线程中运行。这样你就可以确定什么都不会被阻止。例如,如果您要填充某些内容,则可以使用接收器。

希望我能帮上一点......

答案 4 :(得分:1)

这是一个提示,我如何最终解决了我的问题::

1)我使用 IntentService而不是Service ,因为Service在mainThread中运行,而IntentService在一个单独的线程中运行而不是mainThread,以确保我的后台服务不会影响我当前的任务。此外,我正在使用AIDL在我的UI和后台线程之间进行通信(这已经在服务中工作,所以这部分没什么新内容。)

2)我使用无痛线程而不是AsyncTask ,我在 onDestroy()方法中断线程,以确保线程无限期地继续。

App似乎比现在早得多。

希望这也有助于其他人:)

答案 5 :(得分:0)

根据Android Developer AsyncTask文档的线程规则部分,必须在UI线程上创建并启动AsyncTask,因此如果您从服务中的后台线程启动它,那将占用错误的行为。

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

答案 6 :(得分:-2)

你真的不应该一般使用AsyncTasks :)有一个非常好的解释here。想一想当用户在您的任务运行时旋转设备会发生什么。重新创建活动,但任务在后台运行并保留对“旧”活动的引用。有办法解决这个问题,他们肯定仍然是AsyncTasks是正确方法的一些情况。

但是,您真的应该考虑转换为Loader或(如果您有冒险精神)尝试RoboSpice:)