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

Posted

技术标签:

【中文标题】自定义异步任务的实现不起作用【英文标题】: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 版本。 【参考方案1】:

在实现自己的AsyncTask之前,您需要了解一些规则

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

    AsyncTask 将产生至少一个后台线程来完成其工作。 doInBackground() 将在这个后台线程上运行,因为如果它在 UI 线程上运行,您的应用将冻结甚至崩溃。 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。现在我知道我错过了什么。

以上是关于自定义异步任务的实现不起作用的主要内容,如果未能解决你的问题,请参考以下文章

关闭应用程序时异步任务不起作用

循环中的节点 Grunt 异步任务,闭包不起作用

Android自定义TextView实现跑马灯不起作用

为啥阿波罗服务器自定义指令不起作用?

自定义鼠标指针在 IE11 中不起作用

system :: containerStartTime不起作用