如何使用 Runnable 回调替换 AsyncTask onProgressUpdate()

问题描述

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

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

它有效,但我无法弄清楚如何正确复制 publishProgress()onProgressUpdate()AsyncTask 的行为以显示实际进度而不是不确定的行为

解决方法

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

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