【问题标题】:How to replace AsyncTask onProgressUpdate() using Runnable callbacks如何使用 Runnable 回调替换 AsyncTask onProgressUpdate()
【发布时间】:2021-04-26 14:02:00
【问题描述】:

我试图在不使用 Kotlin Coroutines 或其他库的情况下替换已弃用的 AsyncTask,所以我有

MyTask 具有以下结构的对象

public abstract class MyTask<R> implements MyCallable<R> {
    @Override
    public void setUiForLoading() {
       //runs on ui
    }

    @Override
    public void setDataAfterLoading(R result) {
        //runs on ui
    }

    @Override
    public R call() throws Exception {
        //runs in background
        return null;
    }
}

MyCallable只是一个简单的界面

public interface MyCallable<R> extends Callable<R>{
    void setDataAfterLoading(R result);
    void setUiForLoading();
}

并使用这个MyTaskRunner 来执行它们

public class MyTaskRunner {

    private final Handler handler = new Handler(Looper.getMainLooper());
    private final Executor executor = Executors.newCachedThreadPool();

    public <R> void executeAsync(MyCallable<R> callable) {
        try {
            callable.setUiForLoading();
            executor.execute(new RunnableTask<R>(handler, callable));
        } catch (Exception e) {
            
        }
    }

    public static class RunnableTask<R> implements Runnable{
        private final Handler handler;
        private final MyCallable<R> callable;

        public RunnableTask(Handler handler, MyCallable<R> callable) {
            this.handler = handler;
            this.callable = callable;
        }

        @Override
        public void run() {
            try {
                final R result = callable.call();
                handler.post(new RunnableTaskForHandler(callable, result));
            } catch (Exception e) {
               
            }
        }
    }

    public static class RunnableTaskForHandler<R> implements Runnable{

        private MyCallable<R> callable;
        private R result;

        public RunnableTaskForHandler(MyCallable<R> callable, R result) {
            this.callable = callable;
            this.result = result;
        }

        @Override
        public void run() {
            callable.setDataAfterLoading(result);
        }
    }
}

它有效,但我不知道如何正确复制AsyncTaskpublishProgress()onProgressUpdate() 的行为,以显示实际进度而不是不确定

【问题讨论】:

  • 我用Thread替换了Asynctask,但进度不确定
  • publishProgress 只是一种在 mainThread 上发布 Runnable 的方法。您可以使用类似的方法并在主线程处理程序上发布。即使使用AsyncTask,您也必须计算进度。查看AsyncTask源代码doInBackground
  • @ADM 我知道这只是一个在 mainThread 上发布的方法,但我还不清楚在调用运行期间如何执行此操作,因为其中的代码块位于后台线程和 onUpade应该在返回的主线程中运行,例如在 publishProgress(56) 中传递的 int 不会阻塞主线程。如果你能发布一个样本会很有帮助。尝试使 AsyncTask 代码实现本身适应我的代码看起来过于复杂。

标签: java android callback android-asynctask java.util.concurrent


【解决方案1】:

我无法提供与您相同的代码,但希望您能理解。 一切都在代码中自我解释。

import android.app.*;
import android.graphics.*;
import android.os.*;
import android.widget.*;
import java.lang.ref.*;

public class MainActivity extends Activity
{
    private static final class HeavyJob implements Runnable
    {
        private final WeakReference<Handler> handler;
        private final Thread thread;
        private boolean isAlive;
        private boolean state;
        private int progress;

        public final HeavyJob(final Handler handler)
        {
            this.handler = new WeakReference<Handler>(handler);
            thread = new Thread(this);
            isAlive = true;
            thread.setPriority(Thread.NORM_PRIORITY);
            thread.start();
        }

        @Override
        public final void run()
        {
            while(isAlive) {
                try {
                    synchronized(this) {
                        while(!state) this.wait();
                    }
                    Thread.sleep(200L); //Let say this a heavy job which takes 200 m/s each round.
                    progress += 10;
                    final Handler hanRef = handler.get();
                    if(hanRef == null) {
                        isAlive = false;
                        handler.clear();
                        break;
                    }
                    final Message msg = Message.obtain();
                    msg.what = 0;
                    msg.arg1 = progress;
                    hanRef.sendMessageAtTime(msg, SystemClock.uptimeMillis()); //Update its progress each round.
                } catch(final InterruptedException e) {}
            }
            //Finished ???
            final Handler hanRef = handler.get();
            if(hanRef != null) {
                final Message msg = Message.obtain();
                msg.what = 1;
                msg.arg1 = progress; //Make your progress is 100% completed and updated.
                //msg.obj = bitmap;
                hanRef.sendMessageAtTime(msg, SystemClock.uptimeMillis());
            }
        }

        public final synchronized void resume()
        {
            if(isAlive) {
                state = true;
                this.notify();
            }
        }

        public final void suspend()
        {
            state = false;
            thread.interrupt();
        }

        public final void stop()
        {
            isAlive = false; // In case interrupt() does nothing (Thread was not in sleep nor wait mode).
            thread.interrupt();
            handler.clear();
        }
    }

    private static final class UIHandler extends Handler
    {
        private final WeakReference<MainActivity> activity;

        public final UIHandler(final MainActivity activity)
        {
            super(Looper.getMainLooper());
            this.activity = new WeakReference<MainActivity>(activity);
        }

        @Override
        public final void handleMessage(final Message msg)
        {
            final MainActivity referent = activity.get();
            if(referent != null) {
                switch(msg.what) {
                    case 0: referent.onProgress(msg.arg1); break;
                    case 1: referent.onPostExecute(msg.arg1, (Bitmap)msg.obj); break;
                }
            }
        }
    }
    
    private ProgressBar pb;
    private ImageView iv;
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        pb = findViewById(R.id.pb);
        iv = findViewById(R.id.next);
        
        UIHandler handler = new UIHandler(this);
        //Initilize the object but will not run yet.
        HeavyJob hj = new HeavyJob(handler);
        
        //Run the job
        hj.resume();
        //Pause the job
        hj.suspend();
        //Resume the job
        hj.resume();
        //Stop the job
        hj.stop();
        
        //Multiple jobs
        for(int i=0; i<10; i++) {
            new HeavyJob(handler);
        }
    }
    
    public final void onProgress(final int progress) {
        pb.setProgress(progress);
    }
    
    public final void onPostExecute(final int progress, Bitmap bitmap)
    {
        pb.setProgress(progress);
        if(bitmap != null) iv.setImageBitmap(bitmap);
    }
    
}

【讨论】:

    【解决方案2】:

    我创立的最佳做法是:

    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class MainActivity extends AppCompatActivity {
    
        Button btn_start;
        TextView text;
        ProgressBar progressBar1, progressBar2;
        int num = 0;
        ExecutorService service;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            text = findViewById(R.id.textHello);
            btn_start = findViewById(R.id.btn_start);
            progressBar1 = findViewById(R.id.progressbar1);
            progressBar2 = findViewById(R.id.progressBar2);
            btn_start.setOnClickListener(v -> toDo());
    
        }
    
        private void toDo() {
            service = Executors.newSingleThreadExecutor();
            service.execute(() -> {
    
                runOnUiThread(() -> {
                    // onPreExecute method of AsyncTask
                    progressBar1.setVisibility(View.VISIBLE);
                    progressBar2.setVisibility(View.VISIBLE);
    
                });
    
                // doInBackground of AsyncTask
                for (int i = 1; i <= 10000; i++) {
                    num = i;
                    runOnUiThread(() -> {
                        // onProgressUpdate method of AsyncTask
                        progressUpdate(num);
                    });
                }
    
                runOnUiThread(() -> {
                    // onPostExecute method of AsyncTask
                    progressBar1.setVisibility(View.GONE);
                    progressBar2.setVisibility(View.GONE);
                });
    
            });
    
        }
    
        public void progressUpdate(Integer i) {
            text.setText(String.valueOf(i));
            progressBar2.setProgress(i);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多