如何中断AsyncTaskLoader后台线程?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何中断AsyncTaskLoader后台线程?相关的知识,希望对你有一定的参考价值。

当我打电话给AsyncTaskLoader时,有没有办法打断loadInBackground()cancelLoad()线程?我相信AsyncTask.cancel()这样做,但任务变量是私有的,无法访问。

答案

使用stopLoading()abandon()reset()

文章:https://plus.google.com/117981280628062796190/posts/8b9RmQvxudb

另一答案

添加该功能相对简单,这是它的Gist

public abstract class InterruptibleAsyncTaskLoader<D> extends AsyncTaskLoader<D> {
    private volatile Thread thread;

    public InterruptibleAsyncTaskLoader(Context context) {
        super(context);
    }

    public boolean isLoadInBackgroundRunning() {
        return thread != null;
    }

    @Override
    public void cancelLoadInBackground() {
        Thread t = thread;
        if (t != null) t.interrupt();
    }

    @Override
    public final D loadInBackground() {
        try {
            thread = Thread.currentThread();
            return doLoadInBackground();
        } catch (InterruptedException e) {
            OperationCanceledException oce = new OperationCanceledException(e.toString());
            oce.initCause(e);
            throw oce;
        } finally {
            Thread.interrupted();
            thread = null;
        }
    }

    public abstract D doLoadInBackground() throws InterruptedException;
}
另一答案

我检查了可用的方法,似乎没有真正中断在后台运行的线程。

看一下代码,似乎AsyncTask正在被引用。我已经尝试找到一个可以用来中断asyncTask的“漏洞”,但我找不到(除非你对反射很好)。我认为你可以制作自己的装载机,它具有这种功能。

我认为您可以根据需要修改代码。也许添加“forceCancel”,它将检查asyncTask的值,如果它不为null,则在其上调用“cancel(true)”。这是我看过的代码:

A sync task loader.Java

package android.support.v4.content;

import android.content.Context;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.util.TimeUtils;
import android.util.Log;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.concurrent.CountDownLatch;

/**
 * Static library support version of the framework's {@link android.content.AsyncTaskLoader}.
 * Used to write apps that run on platforms prior to Android 3.0.  When running
 * on Android 3.0 or above, this implementation is still used; it does not try
 * to switch to the framework's implementation.  See the framework SDK
 * documentation for a class overview.
 */
public abstract class AsyncTaskLoader<D> extends Loader<D> {
    static final String TAG = "AsyncTaskLoader";
    static final boolean DEBUG = false;

    final class LoadTask extends ModernAsyncTask<Void, Void, D> implements Runnable {

        D result;
        boolean waiting;

        private CountDownLatch done = new CountDownLatch(1);

        /* Runs on a worker thread */
        @Override
        protected D doInBackground(Void... params) {
            if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
            result = AsyncTaskLoader.this.onLoadInBackground();
            if (DEBUG) Log.v(TAG, this + "  <<< doInBackground");
            return result;
        }

        /* Runs on the UI thread */
        @Override
        protected void onPostExecute(D data) {
            if (DEBUG) Log.v(TAG, this + " onPostExecute");
            try {
                AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
            } finally {
                done.countDown();
            }
        }

        @Override
        protected void onCancelled() {
            if (DEBUG) Log.v(TAG, this + " onCancelled");
            try {
                AsyncTaskLoader.this.dispatchOnCancelled(this, result);
            } finally {
                done.countDown();
            }
        }

        @Override
        public void run() {
            waiting = false;
            AsyncTaskLoader.this.executePendingTask();
        }
    }

    volatile LoadTask mTask;
    volatile LoadTask mCancellingTask;

    long mUpdateThrottle;
    long mLastLoadCompleteTime = -10000;
    Handler mHandler;

    public AsyncTaskLoader(Context context) {
        super(context);
    }

    /**
     * Set amount to throttle updates by.  This is the minimum time from
     * when the last {@link #onLoadInBackground()} call has completed until
     * a new load is scheduled.
     *
     * @param delayMS Amount of delay, in milliseconds.
     */
    public void setUpdateThrottle(long delayMS) {
        mUpdateThrottle = delayMS;
        if (delayMS != 0) {
            mHandler = new Handler();
        }
    }

    @Override
    protected void onForceLoad() {
        super.onForceLoad();
        cancelLoad();
        mTask = new LoadTask();
        if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
        executePendingTask();
    }

    /**
     * Attempt to cancel the current load task. See {@link android.os.AsyncTask#cancel(boolean)}
     * for more info.  Must be called on the main thread of the process.
     *
     * <p>Cancelling is not an immediate operation, since the load is performed
     * in a background thread.  If there is currently a load in progress, this
     * method requests that the load be cancelled, and notes this is the case;
     * once the background thread has completed its work its remaining state
     * will be cleared.  If another load request comes in during this time,
     * it will be held until the cancelled load is complete.
     *
     * @return Returns <tt>false</tt> if the task could not be cancelled,
     *         typically because it has already completed normally, or
     *         because {@link #startLoading()} hasn't been called; returns
     *         <tt>true</tt> otherwise.
     */
    public boolean cancelLoad() {
        if (DEBUG) Log.v(TAG, "cancelLoad: mTask=" + mTask);
        if (mTask != null) {
            if (mCancellingTask != null) {
                // There was a pending task already waiting for a previous
                // one being canceled; just drop it.
                if (DEBUG) Log.v(TAG,
                        "cancelLoad: still waiting for cancelled task; dropping next");
                if (mTask.waiting) {
                    mTask.waiting = false;
                    mHandler.removeCallbacks(mTask);
                }
                mTask = null;
                return false;
            } else if (mTask.waiting) {
                // There is a task, but it is waiting for the time it should
                // execute.  We can just toss it.
                if (DEBUG) Log.v(TAG, "cancelLoad: task is waiting, dropping it");
                mTask.waiting = false;
                mHandler.removeCallbacks(mTask);
                mTask = null;
                return false;
            } else {
                boolean cancelled = mTask.cancel(false);
                if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled);
                if (cancelled) {
                    mCancellingTask = mTask;
                }
                mTask = null;
                return cancelled;
            }
        }
        return false;
    }

    /**
     * Called if the task was canceled before it was completed.  Gives the class a chance
     * to properly dispose of the result.
     */
    public void onCanceled(D data) {
    }

    void executePendingTask() {
        if (mCancellingTask == null && mTask != null) {
            if (mTask.waiting) {
                mTask.waiting = false;
                mHandler.removeCallbacks(mTask);
            }
            if (mUpdateThrottle > 0) {
                long now = SystemClock.uptimeMillis();
                if (now < (mLastLoadCompleteTime+mUpdateThrottle)) {
                    // Not yet time to do another load.
                    if (DEBUG) Log.v(TAG, "Waiting until "
                            + (mLastLoadCompleteTime+mUpdateThrottle)
                            + " to execute: " + mTask);
 

以上是关于如何中断AsyncTaskLoader后台线程?的主要内容,如果未能解决你的问题,请参考以下文章

Android ListView 由 AsyncTaskLoader 更新

AsyncTaskLoader onLoadFinished 有一个挂起的任务和配置更改

并发基础 java线程的中断机制

浏览器页面关闭后台线程会中断吗

在片段分离时中止加载 AsyncTaskLoader

详细分析Java中断机制-转载