IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android AsyncTask详解 -> 正文阅读

[移动开发]android AsyncTask详解

AsyncTask是Android中用来执行异步执行耗时操作的框架。

在这里插入图片描述

1、AsyncTask使用

继承AsyncTask,并且实现doInBackground方法。其中doInBackground中进行耗时操作,比如网络请求,文件读取等。

class DownloadTask : AsyncTask<URL, Int, Long>() {
    override fun doInBackground(vararg params: URL?): Long {
        //执行background
        return 1000L
    }

    override fun onPreExecute() {
        //执行之前
        super.onPreExecute()
    }

    override fun onPostExecute(result: Long?) {
        //执行之后
        super.onPostExecute(result)
    }

    override fun onProgressUpdate(vararg values: Int?) {
        //更新进度
        super.onProgressUpdate(*values)
    }
}

如下方法执行AsyncTask,execute方法必须在ui线程中进行,

DownloadTask().execute(URL("https://baidu.com"))

2、AsyncTask实现

在这里插入图片描述

从AsyncTask的execute方法进行分析

1、execute

启动AsyncTask的方法,源码如下

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
     //执行时先判断状态,如果当前已在执行,或者已经完成执行,就会抛出异常
    if (mStatus != Status.PENDING) {
        switch (mStatus) {
            case RUNNING:
                throw new IllegalStateException("Cannot execute task:"
                        + " the task is already running.");
            case FINISHED:
                throw new IllegalStateException("Cannot execute task:"
                        + " the task has already been executed "
                        + "(a task can be executed only once)");
        }
    }

    mStatus = Status.RUNNING;
    //调用onPreExecute方法,后台进程执行前可以先操作。
    onPreExecute();

    mWorker.mParams = params;
    //通过exec线程池进行执行。
    exec.execute(mFuture);

    return this;
}

AsyncTask默认的Executor是sDefaultExecutor,看下sDefaultExecutor的源码:


private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static class SerialExecutor implements Executor {
    //创建一个task,用于保存runnable
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;
    //创建一个
    public synchronized void execute(final Runnable r) {
        //先将runnable,放进到队列中,
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    //执行完当前runnable后主动调起栈中下面一个runnable任务
                    scheduleNext();
                }
            }
        });
        //开始时mActive为null,会先从task中拿一个runnable任务进行执行。
        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            //执行mActive 的runnable
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

sDefaultExecutor的实现类是SerialExecutor,SerialExecutor中用task来保存任务,并且通过task中上一个任务执行时完时主动调起下一个任务进行执行,来保证执行顺序。具体的执行任务的是THREAD_POOL_EXECUTOR。

public static final Executor THREAD_POOL_EXECUTOR;

static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>(), sThreadFactory);
    threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

上面创建THEAD_POOL_EXECUTOR,主要看下rejectedExecutionHandler,sRunOnSerialPolicy

private static final RejectedExecutionHandler sRunOnSerialPolicy =
        new RejectedExecutionHandler() {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
        // As a last ditch fallback, run it on an executor with an unbounded queue.
        // Create this executor lazily, hopefully almost never.
        synchronized (this) {
            if (sBackupExecutor == null) {
                sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
                sBackupExecutor = new ThreadPoolExecutor(
                        BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
                        TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
                //核心线程数可以被回收
                sBackupExecutor.allowCoreThreadTimeOut(true);
            }
        }
        sBackupExecutor.execute(r);
    }
};

由上面可见,THEAD_POOL_EXECUTOR是核心线程数为1,最大线程数为20的线程池,当线程池执行rejected的时候会使用sBackupExecutor来执行被reject的任务。sBackupExecutor是核心线程数和最大线程数都为5的线程池,并且核心线程数可以被回收,避免空线程等待。

2、exec.execute(mFuture);

在上面executeOnExecutor方法中执行完onPreExecute后会调用exec.execute(mFuture)这个方法是用来执行后台耗时操作对应AsyncTask中的doInBackground方法,其中mFuture,是一个FutureTask

mFuture = new FutureTask<Result>(mWorker) {
    @Override
    protected void done() {
        try {
            //执行完成后进行postResult操作。
            postResultIfNotInvoked(get());
        } catch (InterruptedException e) {
            android.util.Log.w(LOG_TAG, e);
        } catch (ExecutionException e) {
            throw new RuntimeException("An error occurred while executing doInBackground()",
                    e.getCause());
        } catch (CancellationException e) {
            postResultIfNotInvoked(null);
        }
    }
};

其中mWorker是一个WorkerRunnable,源码如下,doInBackground方法就是在worker的call方法中被调用的。

mWorker = new WorkerRunnable<Params, Result>() {
    public Result call() throws Exception {
        mTaskInvoked.set(true);
        Result result = null;
        try {
            //设置线程优先级
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //调用doInBackground
            result = doInBackground(mParams);
            Binder.flushPendingCommands();
        } catch (Throwable tr) {
            //标记cancel
            mCancelled.set(true);
            throw tr;
        } finally {
            //调用postResult
            postResult(result);
        }
        return result;
    }
};

WorkerRunnable实现Callable接口

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

看下postResultIfNotInvoked方法

private void postResultIfNotInvoked(Result result) {
//先判断是否调起过,如果没调起,那么执行调起
    final boolean wasTaskInvoked = mTaskInvoked.get();
    
    if (!wasTaskInvoked) {
        //postResult
        postResult(result);
    }
}

postResult方法源码如下:

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}
//上面的getHandler就是Looper为MainLooper的handler,会把消息抛到ui线程执行

postResult通过handler把message抛到ui线程中执行,

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
        switch (msg.what) {
            case MESSAGE_POST_RESULT:
                // 调用asyncTask的finish方法
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}
//internalHandler的looper也是主线程中的looper。
private static Handler getMainHandler() {
    synchronized (AsyncTask.class) {
        if (sHandler == null) {
            sHandler = new InternalHandler(Looper.getMainLooper());
        }
        return sHandler;
    }
}

result.mTask.finish方法如下

private void finish(Result result) {
    if (isCancelled()) {
        //如果是cancelled的调用onCancelled方法
        onCancelled(result);
    } else {
        //否则调用onPostExecute方法
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

3、AsyncTask问题

google官方已经把AsyncTask废弃了在AsyncTask源码的官方注释中有说明废弃的原因

 that would cause Context leaks, missed callbacks, or crashes on configuration changes. It also has inconsistent behavior on different
versions of the platform, swallows exceptions from {  @code  doInBackground}, and does not provide
much utility over using {  @link  Executor}s directly. 

1、生命周期问题与内存泄露

AsyncTask会一直执行,直到doInBackground()方法执行完毕。如果AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会持有对Activity的引用,如果在销毁activity的时候没有取消正在运行的AsyncTask,这会导致Activity没法被回收,从而导致内存泄露。

2、结果丢失

屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

3、处理不当容易导致任务阻塞

所以如果一个AsyncTask的doInBackGround方法中存在着一个无限循环没有正确处理,导致这个AsyncTask的doInBackGround方法一直运行,那么这会导致同一个进程中其他的AsyncTask的任务无法执行。

4、其他

1、Future

Future是接口,有如下的方法,子类继承Future接口会重新这些方法,Future的子类有FutureTask.

public interface Future<V> {

boolean cancel(boolean mayInterruptIfRunning);

boolean isCancelled();

boolean isDone();

V get() throws InterruptedException, ExecutionException;

V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

2、Callable

Callable是一个接口,call方法返回值,

public interface Callable<V> {
    /**
* Computes a result, or throws an exception if unable to do so.
*
*  @return  computed result
*  @throws  Exception if unable to compute a result
*/
V call() throws Exception;
}

3、FutureTask

FutureTask 为 Future 提供了基础实现,如获取任务执行结果(get)和取消任务(cancel)等。如果任务尚未完成,获取任务执行结果时将会阻塞。一旦执行结束,任务就不能被重启或取消(除非使用runAndReset执行计算)。FutureTask 常用来封装 Callable 和 Runnable,也可以作为一个任务提交到线程池中执行。除了作为一个独立的类之外,此类也提供了一些功能性函数供我们创建自定义 task 类使用。FutureTask 的线程安全由CAS来保证。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ZyAX1tE-1656827041607)(https://tech-proxy.bytedance.net/tos/images/1656827031432_2b64520346dfeb898d3321bb163a4335)]

FutureTask实现了RunnableFuture的接口,如下

public class FutureTask<V> implements RunnableFuture<V>

public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}

FutureTask可以通过get方法来拿到执行的结果。

val executor = Executors.newFixedThreadPool(
    1
)
val futureTask = FutureTask<String>(object : Callable<String> {
    override fun call(): String {
        //执行其他耗时操作
        return "good good study"
    }
})
executor.execute(futureTask)
//默认自旋等待返回结果。
val s=futureTask.get()
//s值为good good study

创建FutureTask的时候会传入一个Callable对象,executor.execute(futureTask)执行时会调用futureTask的run方法,FutureTask的run方法源码如下:

public void run() {
    if (state != NEW ||
        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                //执行callable.call方法,并且获取返回值
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                //设置result
                set(result);
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

FutureTask的run方法其实调用了Callable.call方法并且拿到result值。然后通过set方法进行设置,set方法代码如下:

protected void set(V v) {
    //对比并且设置state的值为COMPLETING
    if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
        //设置outcome的值为v
        outcome = v;
        U.putOrderedInt(this, STATE, NORMAL); // final state
        finishCompletion();
    }
}

futureTask.get()实现

public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        //自旋等待结果
        s = awaitDone(false, 0L);
    return report(s);
}
//自旋等待结果
private int awaitDone(boolean timed, long nanos)
    throws InterruptedException {
    // The code below is very delicate, to achieve these goals:
    // - call nanoTime exactly once for each call to park
    // - if nanos <= 0L, return promptly without allocation or nanoTime
    // - if nanos == Long.MIN_VALUE, don't underflow
    // - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
    //   and we suffer a spurious wakeup, we will do no worse than
    //   to park-spin for a while
    long startTime = 0L;    // Special value 0L means not yet parked
    WaitNode q = null;
    boolean queued = false;
    for (;;) {
        int s = state;
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;
            return s;
        }
        else if (s == COMPLETING)
            // We may have already promised (via isDone) that we are done
            // so never return empty-handed or throw InterruptedException
            Thread.yield();
        else if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }
        else if (q == null) {
            if (timed && nanos <= 0L)
                return s;
            q = new WaitNode();
        }
        else if (!queued)
            queued = U.compareAndSwapObject(this, WAITERS,
                                            q.next = waiters, q);
        else if (timed) {
            final long parkNanos;
            if (startTime == 0L) { // first time
                startTime = System.nanoTime();
                if (startTime == 0L)
                    startTime = 1L;
                parkNanos = nanos;
            } else {
                long elapsed = System.nanoTime() - startTime;
                if (elapsed >= nanos) {
                    removeWaiter(q);
                    return state;
                }
                parkNanos = nanos - elapsed;
            }
            // nanoTime may be slow; recheck before parking
            if (state < COMPLETING)
                LockSupport.parkNanos(this, parkNanos);
        }
        else
            LockSupport.park(this);
    }
}

参考

1、https://pdai.tech/md/java/thread/java-thread-x-juc-executor-FutureTask.html

2、https://developer.android.com/reference/android/os/AsyncTask

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-07-05 23:36:33  更:2022-07-05 23:37:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 22:25:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码