【问题标题】:ASynchTask sleep in doinbackground locking the UI thread异步任务在 doinbackground 中休眠,锁定 UI 线程
【发布时间】:2012-02-14 22:40:53
【问题描述】:

编辑:已解决。对不起,伙计们,我突然想到,虽然我的数据加载是在后台线程中发生的,但解析数据的回调却没有。数据的解析花费了很长时间,这就是锁定我的线程的原因。

编辑:我注意到我的首要问题(ProgressDialog 不再旋转)可能是由我使用 ProgressDialog 的问题引起的,而不是 UI 线程被阻塞。如果是这种情况,我该如何解决?

编辑:澄清一下,这不会永远锁定整个程序。加载完所有内容后,将关闭进度对话框,并启动新活动。我的问题是,在加载时,整个 UI 被锁定(即进度对话框停止旋转)

TL;DR:doInBackground() 中的 Thread.sleep() 正在锁定 UI 线程

我有一个应用程序,当打开特定活动时,它开始从我的后端在后台加载大量数据,例如,与计划相关的大量数据。此信息不会立即使用,但可能会在用户尝试访问时使用(即通过单击计划按钮并启动计划活动)。

如果用户在单击计划按钮之前稍等片刻,则会加载所有数据,计划活动将打开,并显示所有内容。我的问题是如果他们在数据加载之前点击按钮。

我的解决方案是创建一个显示 ProgressDialog 的 ASyncTask,同时定期检查数据是否已完成加载,否则会进入休眠状态。它通过一些应用程序范围的布尔变量知道数据已完成加载。我的问题是,即使 Thread.sleep() 在 doinbackground() 中运行,它仍然会锁定 UI 线程。

我正在使用自定义 ASyncTask,定义如下:

public class LoadWithProgressDialog extends AsyncTask<Void, Void, Boolean>{
    private ProgressDialog pd; //the progress dialog
    private String title; //the title of the progress dialog
    private String  message; //the body of the progress dialog
    private Runnable task; //contains the code we want to run in the background
    private Runnable postTask; //execute when the task ends
    private Context c;


    public LoadWithProgressDialog(Context context,String t, String m,Runnable r, Runnable postR){
        super();
        c = context;
        task = r;
        postTask = postR;
        title = t;
        message = m;
    }

    @Override
    protected void onPreExecute(){
        pd = ProgressDialog.show(c,title, message, false, false);
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        task.run();
        return true;
    }


    @Override
    protected void onPostExecute(Boolean result) {
        pd.dismiss();
        if(postTask != null)
            postTask.run();
    }

并通过(例如)调用它:

if(loadingSchedule){

            LoadWithProgressDialog lwpd = new LoadWithProgressDialog(thisClass,"Loading","Loading Schedule", new Runnable() {
                public void run(){
                    while(loadingSchedule){
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

                    }
                }
            },new Runnable() {
                public void run(){

                    Intent i= new Intent(thisClass, Schedule.class);
                    i.putExtra("numberIneed",index);
                    startActivity(i); 
                }
            });
            lwpd.execute();

(我将全局变量的访问缩短为“loadingSchedule”以使其更易于阅读)

如何使这个不锁定 UI 线程?

【问题讨论】:

    标签: android locking android-asynctask sleep ui-thread


    【解决方案1】:

    doInBackground() 中的 Thread.sleep() 正在锁定 UI 线程

    doInBackground() 中的Thread.sleep() 不会锁定UI 线程,顾名思义,任务在后台异步执行。

    您的 UI 线程没有被锁定。它实际上是在 AsyncTask 启动之前弹出的 ProgressDialog(在 onPreExecute() 方法中)并一直显示在前面并在 AsyncTask 执行期间阻止用户与底层活动交互(在 doInBackground() 方法中)。最后在 AsyncTask 完成后解散。 (在 onPostExecute() 方法中)

    我有一个应用程序,当特定活动打开时,它开始从我的后端在后台加载大量数据

    这是一个常见的用例,创建一个在后台加载数据的 AsyncTask 实现会更有效,而不是创建一个显示 ProgressDialog 的 ASyncTask,同时定期检查数据是否已完成加载,否则会休眠。

    查看 API here,它包含如何正确使用它的好例子。

    【讨论】:

    • 1) 我知道 ProgressDialog 会弹出并阻止用户与底层活动的交互。我的问题是 PD 没有旋转。我已经意识到这可能表示也可能不表示 UI 线程被阻止。 2)我在后台加载数据。这个进度对话框是如果他们在数据准备好之前尝试访问数据,所以我需要用户等到它完成加载。
    • 对于旋转问题,看看this是否有帮助?
    • @yorkw 我遇到了对话框阻塞用户界面的问题,那么如何处理呢?!!如您所知,它首先必须在主线程中运行
    【解决方案2】:

    您的代码看起来正确,不应阻塞主线程。

    所以使用调试器!在doInBackground、Thread.sleep、onPostExecute、lwpd.execute之后设置断点,你就会知道代码在哪里以及何时到达。

    尝试找到“UI线程究竟在哪里阻塞”的答案。

    【讨论】:

    • 对不起,请参阅我的编辑以进行澄清。后台加载完成后,一切都会再次运行。它只是在持续时间内被锁定(ProgressDialog 不旋转)。我不知道如何识别 UI 何时锁定​​,因为除了应该保持进度对话框旋转(我没有写)之外没有运行任何代码
    猜你喜欢
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多