ASynchTask спит в doinbackground, блокирующем поток пользовательского интерфейса - PullRequest
0 голосов
/ 15 февраля 2012

РЕДАКТИРОВАТЬ: решено.Извините, ребята, мне пришло в голову, что в то время как моя загрузка моих данных происходила в фоновом потоке, обратного вызова, который анализировал данные, не было.Анализ данных занял очень много времени, и это было тем, что блокировало мою нить.

РЕДАКТИРОВАТЬ: До меня дошло, что моя всеобъемлющая проблема (ProgressDialog больше не вращается) может быть вызвана проблемой с использованием ProgressDialog, а не блокирования потока пользовательского интерфейса.Если это так, как я могу это исправить?

РЕДАКТИРОВАТЬ: чтобы уточнить, это не блокирует всю программу навсегда.Как только все загружено, диалоговое окно хода выполнения закрывается, и начинается новое действие.Моя проблема заключается в том, что во время загрузки весь пользовательский интерфейс блокируется (т. Е. Прогрессиалог прекращает вращаться)

TL; DR: Thread.sleep () в doInBackground () блокирует поток пользовательского интерфейса

У меня есть приложение, которое при открытии определенного действия начинает загружать много данных в фоновом режиме из моего бэкэнда, например, большой объем данных, связанных с расписанием.Эта информация не будет использоваться сразу, но может использоваться, если пользователь пытается получить к ней доступ (т. Е. Нажав кнопку расписания и запустив действие по расписанию).

Если пользователь немного подождет, прежде чем нажать кнопкуКнопка Расписание, все данные загружаются, открывается график действий, и отображает все отлично.Моя проблема в том, что они нажимают кнопку до загрузки данных.

Мое решение здесь состояло в том, чтобы создать ASyncTask, который отображает ProgressDialog, периодически проверяя, закончили ли данные загрузку, и спя в противном случае.Он знает, что данные закончили загрузку через некоторые логические переменные всего приложения.Моя проблема в том, что, хотя Thread.sleep () запускается в doinbackground (), он все еще блокирует поток пользовательского интерфейса.

Я использую пользовательский 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», чтобы было легче читать)

Как мне сделатьэто не заблокировать поток пользовательского интерфейса?

Ответы [ 2 ]

5 голосов
/ 15 февраля 2012

Thread.sleep () в doInBackground () блокирует поток пользовательского интерфейса

Thread.sleep () в doInBackground () не блокирует поток пользовательского интерфейса, как указано в его имени, задачаделать в фоновом режиме асинхронно.

Ваш поток пользовательского интерфейса не блокируется.На самом деле, это всплывающее окно ProgressDialog до запуска AsyncTask (в методе onPreExecute ()), которое продолжает отображаться вперед и блокирует взаимодействие пользователя с основным действием во время выполнения AsyncTask (в методе doInBackground ()).и, наконец, уволен после окончания AsyncTask.(в методе onPostExecute ())

У меня есть приложение, которое при открытии определенного действия начинает загружать много данных в фоновом режиме из моего бэк-энда

Это распространенный вариант использования, более эффективно будет создать реализацию AsyncTask, которая загружает данные в фоновом режиме, вместо того, чтобы создавать ASyncTask, который показывает ProgressDialog при периодической проверке, закончилась ли загрузка данных, и спящем в противном случае.

Проверьте API здесь , он содержит хороший пример того, как правильно его использовать.

0 голосов
/ 15 февраля 2012

Ваш код выглядит правильно и не должен блокировать основной поток.

Так что используйте отладчик! Поместите точку останова в doInBackground, Thread.sleep, onPostExecute, после lwpd.execute, и вы будетеузнайте, куда и когда попадает код.

Попробуйте найти ответ на вопрос "где именно заблокирован поток пользовательского интерфейса".

...