11

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

我在几篇文章中读到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 
        }   
    }
}

这通常工作正常,但当服务在后台运行时挂起(我的意思是当音乐在后台播放时)。

我没有得到这个异步任务问题背后的确切原因。在这种情况下,手动线程实现会有所帮助吗...??

好吧,我认为问题是因为“服务在主线程中运行,所以当它运行时,它会阻止我的 AsyncTask 运行”......所以我认为如果我们可以在后台线程中运行服务,那么这会有所帮助。这就是为什么我尝试 IntentService 在单独的线程中运行服务,但我怀疑......如果 IntentService 可以像 Service 一样无限期运行......并且 IntentService 也会阻塞 AsyncTask 几次。所以我不认为它对这类问题的 100% 完美解决方案。

谁能帮我解决这个问题并理解完整的场景。

提前致谢。

4

7 回答 7

3

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

在这里回答

于 2013-02-22T10:50:50.850 回答
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).

于 2013-02-21T17:30:26.930 回答
1

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

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

  1. 在Activity中,onResume()方法解析XML文件并获取歌曲列表并更新列表视图(这里不要启动任何与服务相关的东西)
  2. 当用户点击歌曲然后将特定的键/字符串传递给服务并启动服务
  3. 在服务的OnStartCommand()方法中获取标识符并像使用普通媒体 API 一样启动歌曲

这实际上会为您完成工作。

关于问题

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

这是针对不同AsyncTask版本的 Android 的不同行为。查看您的代码正在执行的操作是在您正在初始化服务的 Activity 中,因此该服务在后台运行而没有做任何有成效的事情。并且当用户单击播放时,您正在调用在此处创建问题的服务的播放功能。

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

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

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

希望这会有所帮助。

于 2013-02-22T11:19:52.210 回答
1

我注意到有时 Async 任务无法正常工作,实际上它的 doInBackground() 方法没有被调用,这种情况大多发生

你知道一次可以执行的 AsyncTask 是有限制的吗?我曾经遇到过一个任务无法启动/正常工作的问题,这是因为我超过了这个数字。检查Android AsyncTask 线程限制?有关该主题的更多信息。

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

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

好吧,我认为问题是因为“服务在主线程中运行,所以当它运行时,它会阻止我的 AsyncTask 运行”......所以我认为如果我们可以在后台线程中运行服务,那么这会有所帮助。这就是为什么我

无论如何,您要在服务中执行的操作都应该在自己的线程中运行。这样你就可以确定没有任何东西会被阻止。例如,如果你有一些东西要填充,你可以使用接收器。

希望我能帮助一点...

于 2013-02-23T18:46:44.427 回答
1

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

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

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

应用程序现在的性能似乎比早期要好得多。

希望这对其他人也有帮助:)

于 2013-02-25T07:35:01.983 回答
0

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

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

于 2013-02-22T04:42:16.663 回答
-2

一般来说,你真的不应该使用 AsyncTasks :)这里有一个很好的解释。想想如果用户在你的任务运行时旋转设备会发生什么。Activity 被重新创建,但任务在后台运行并持有对“旧”活动的引用。有一些方法可以解决这个问题,而且在某些情况下,AsyncTasks 肯定是正确的方法。

但是,您真的应该考虑切换到装载机或(如果您喜欢冒险)尝试RoboSpice :)

于 2013-02-22T09:04:54.013 回答