问题描述
我试图在不使用 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);
}
}