Реализация пользовательской асинхронной задачи не работает - PullRequest
1 голос
/ 05 мая 2019

Я пытаюсь создать свою собственную реализацию Android Asynctask.Для этого я создал абстрактный класс, который расширяет класс Thread.Я объявил методы для onPreExecute, onPostExecute, onProgressUpdate и doInBackground.

Я запускаю метод doInBackground, создавая обработчик из Looper основного потока.Но я не могу изменить элементы пользовательского интерфейса внутри моего метода onProgressUpdate (), но я могу изменить элементы пользовательского интерфейса в методе onPostExecute ().

Вот что я попробовал.

package com.example.myapplication;

import android.os.Handler;
import android.os.Looper;

public abstract class MyAsyncTask extends Thread {
        String[] urls;
        Handler handler;

        abstract protected void onPreExecute();

        abstract protected void onPostExecute(String result);

        abstract protected void onProgressUpdate(String result);

        protected void publishProgress(String progress) {
            onProgressUpdate(progress);
        }

        abstract protected void doInBackground(String... urls);


        protected void execute(String... urls) {
            onPreExecute();
            this.urls = urls;
            start();
        }

        public void run() {
            try {
                handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        doInBackground(urls);
                    }
                });

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

Это моя основная деятельность.Он имеет индикатор выполнения и текст прогресса, чтобы показать прогресс.

package com.example.myapplication;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    ProgressBar bar;
    TextView progressText;
    LinearLayout container;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bar = findViewById(R.id.progress);
        progressText = findViewById(R.id.progressText);
        container = findViewById(R.id.container);
    }

    public void startProcess(View view) {
        String[] assignments = {"assgn1", "assgn2", "assgn3", "assgn4", "assgn5"};

        new ProgressAsync().execute(assignments);
    }

    public void showProgress() {
        container.setVisibility(View.VISIBLE);
    }

    public void hideProgress() {
        container.setVisibility(View.GONE);
    }

    public class ProgressAsync extends MyAsyncTask {

        @Override
        protected void onPreExecute() {
            showProgress();
        }

        @Override
        protected void onPostExecute(String result) {
            progressText.setText("All processed");
            hideProgress();
        }

        @Override
        protected void onProgressUpdate(String result) {
            progressText.setText(result + "  processed");
        }

        @Override
        protected void doInBackground(String... urls) {
            for (int i = 0; i < urls.length; i++) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                publishProgress(this.urls[i]);
            }
            onPostExecute("SUCCESS");
        }
    }


}

Предполагается, что через каждые 2 секунды он должен задавать progressText, например, assgn1, assgn2 и т. Д.Но он не устанавливает никакого текста для progressText во время onProgressUpdate (), но устанавливает «Все обработано» в методе onPostExecute ().

Может ли кто-нибудь помочь мне, если я что-то здесь упустил.

1 Ответ

1 голос
/ 06 мая 2019

Существуют некоторые правила, которые вам необходимо знать перед реализацией собственного AsyncTask

AsyncTask позволяет правильно и легко использовать поток пользовательского интерфейса.Этот класс позволяет выполнять фоновые операции и публиковать результаты в потоке пользовательского интерфейса без необходимости манипулировать потоками и / или обработчиками.

  1. AsyncTask будет порождать хотя бы один фоновый поток для своей работы.
  2. doInBackground() будет работать в этом фоновом потоке, потому что, если он работает в потоке пользовательского интерфейса, ваше приложение будет зависать или даже зависать.
  3. onPreExecute(), onPostExecute(), onProgressUpdate() будет работать в потоке пользовательского интерфейса.

В вашем коде, поскольку код в doInBackground() выполняется в потоке пользовательского интерфейса, поэтому ваше приложение зависает до тех пор, пока оно не достигнет последней строки в doInBackground()method.

Вот мое решение:

MyAsyncTask.java

public abstract class MyAsyncTask extends Thread {
    private String[] mUrls;
    private Handler mMainHandler;

    public MyAsyncTask() {
        // Using this handler to update UI
        mMainHandler = new Handler(Looper.getMainLooper());
    }

    abstract protected void onPreExecute();

    abstract protected void onPostExecute(String result);

    abstract protected void onProgressUpdate(String result);

    protected void publishProgress(final String progress) {
        // This will run in UI thread.
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                onProgressUpdate(progress);
            }
        });
    }

    abstract protected String doInBackground(String... urls);

    protected void execute(String... urls) {
        mUrls = urls;
        start();
    }

    public void run() {
        // This will run in UI thread.
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                onPreExecute();
            }
        });

        String result = null;
        try {
            // This will run in the background thread.
            result = doInBackground(mUrls);
        } finally {
            // This will run in UI thread.
            final String finalResult = result;
            mMainHandler.post(new Runnable() {
                @Override
                public void run() {
                    onPostExecute(finalResult);
                }
            });
        }
    }
}

ProgressAsync.java

public class ProgressAsync extends MyAsyncTask {

    @Override
    protected void onPreExecute() {
        showProgress();
    }

    @Override
    protected void onPostExecute(String result) {
        progressText.setText(result);
        hideProgress();
    }

    @Override
    protected void onProgressUpdate(String result) {
        progressText.setText(result + "  processed");
    }

    @Override
    protected String doInBackground(String... urls) {
        for (String url : urls) {
            publishProgress(url);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return "SUCCESS";
    }
}

Примечание: Я просто даю простое и быстрое решение. На практике вам нужно написать больше кода для обработки некоторых сценариев, таких как обработка исключений, отмена фоновых задач и т. Д.

...