【问题标题】:Implementation of custom async task not working自定义异步任务的实现不起作用
【发布时间】:2019-09-23 07:06:09
【问题描述】:

我正在尝试创建自己的 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 秒后设置 progressText,如 assgn1、assgn2 等。但是它在 onProgressUpdate() 期间没有为 progressText 设置任何文本,而是在 onPostExecute() 方法中设置了“All Processed”。

如果我在这里遗漏了什么,有人可以帮助我吗?

【问题讨论】:

  • 你让MyAsyncTask extends Thread。线程不是 AsyncTask。你需要MyAsyncTask extends AsyncTask&lt;String, String, String&gt;
  • @anatoli 我不想创建 AsyncTask 的子类。我想自己实现一个 AsyncTask 版本。

标签: android multithreading android-asynctask handler


【解决方案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";
    }
}

注意:我只是给出了简单快速的解决方案,实际中需要编写更多的代码来处理一些场景,比如处理异常、取消后台任务等。

【讨论】:

  • 感谢 Nhất Giang。现在我知道我错过了什么。
猜你喜欢
  • 1970-01-01
  • 2013-01-05
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
  • 2015-10-16
  • 1970-01-01
  • 1970-01-01
  • 2017-11-30
相关资源
最近更新 更多