自定义异步任务的实现不起作用

时间:2019-05-05 12:07:08

标签: android multithreading android-asynctask handler

我正在尝试创建自己的android Asynctask实现。为此,我创建了一个扩展Thread类的抽象类。我声明了onPreExecute,onPostExecute,onProgressUpdate和doInBackground的方法。

我正在通过从主线程的Looper创建一个处理程序来运行doInBackground方法。但是我无法在onProgressUpdate()方法中修改UI元素,但可以在onPostExecute()方法中修改UI元素。

这是我尝试过的。

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

    }

这是我的MainActivity。它具有进度条和progressText以显示进度。

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秒钟设置一次assgn1,assgn2等的progressText。但是在onProgressUpdate()期间它不会为progressText设置任何文本,而是在onPostExecute()方法中设置“所有处理”。

如果我在这里错过了什么,有人可以帮我吗?

1 个答案:

答案 0 :(得分:1)

在实现自己的AsyncTask

之前,您需要了解一些规则。
  

AsyncTask允许正确且轻松地使用UI线程。这个班   允许您执行后台操作并在   UI线程,而无需操纵线程和/或处理程序。

  1. AsyncTask将产生至少一个后台线程来完成其工作。
  2. doInBackground()将在此后台线程上运行,因为如果它在UI线程上运行,您的应用将冻结甚至崩溃。
  3. onPreExecute()onPostExecute()onProgressUpdate()将在UI线程上运行。

在您的代码中,由于doInBackground()中的代码在UI线程上运行,因此您的应用被冻结,直到到达doInBackground()方法的最后一行为止。

这是我的解决方法:

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

注意:我只是提供了一种简单快捷的解决方案,实际上,您需要编写更多代码来处理某些情况,例如处理异常,取消后台任务等。