如何在 Android 中取消 AsyncTask

How to cancle AsyncTask in Android

在我的应用程序中,我有 2 个 AsyncTask 方法,我想在 activity 转到 onPause 时取消此 AsyncTasks 并在 onResume 从头开始.
我写了下面的代码,我按下主页按钮,应用程序转到 onPause 并再次从最近的应用程序
打开这个应用程序 我的意思是调用 onPauseonResume !

但是当再次应用运行时(来自最近的应用),调用onResume但不会从头开始AsyncTask

我的代码:

@Override
protected void onResume() {
    super.onResume();
    new Handler(getMainLooper()).postDelayed(() -> {
        //Get compress or upload
        if (bundle == null) {
            //Get video from file
            getLoadOriginalVideos();
            testIsSendPlans = testId;
        }
    }, 500);
}

@Override
protected void onPause() {
    super.onPause();
    new GetOriginalVideosAsync().cancel(true);
    new GetCompressedVideosAsync().cancel(true);
}

private void getLoadOriginalVideos() {
    if (videoList.isEmpty()) {
        File directory = new File(Environment.getExternalStorageDirectory() + File.separator + APPDIR);
        ArrayList<File> filesList = new ArrayList<File>();
        if (directory.isDirectory() && directory.exists()) {
            filesList.addAll(Arrays.asList(getOriginalVideos(directory.listFiles())));
        }
        new GetOriginalVideosAsync().execute(filesList.toArray(new File[filesList.size()]));
    }
}

@SuppressLint("StaticFieldLeak")
class GetOriginalVideosAsync extends AsyncTask<File[], Integer, ArrayList<Video>> {
    File[] files;
    ContentResolver resolver;

    GetOriginalVideosAsync() {
        resolver = context.getContentResolver();
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(ArrayList<Video> videos) {
        Collections.sort(videos, Collections.reverseOrder());
        getLastOriginalVideo(addVideos(videos));
    }

    private ArrayList<Video> addVideos(ArrayList<Video> videos) {
        return new ArrayList<>(videos);
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

    }

    @Override
    protected ArrayList<Video> doInBackground(File[]... arg) {
        files = arg[0];
        for (File file : files) {
            if (!file.isDirectory() && isVideoFile(file.getPath())) {
                videoList.add(new Video(file.getName(), file, new Date(file.lastModified())));
            }
        }
        return videoList;
    }
}

@SuppressLint("StaticFieldLeak")
class GetCompressedVideosAsync extends AsyncTask<File[], Integer, ArrayList<Video>> {
    File[] files;
    ContentResolver resolver;

    GetCompressedVideosAsync() {
        resolver = context.getContentResolver();
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(ArrayList<Video> videos) {
        Collections.sort(videos, Collections.reverseOrder());
        getLastCompressedVideo(addVideos(videos));
    }

    private ArrayList<Video> addVideos(ArrayList<Video> videos) {
        return new ArrayList<>(videos);
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

    }

    @Override
    protected ArrayList<Video> doInBackground(File[]... arg) {
        files = arg[0];
        for (File file : files) {
            if (!file.isDirectory() && isVideoFile(file.getPath())) {
                videoListCompressed.add(new Video(file.getName(), file, new Date(file.lastModified())));
            }
        }
        return videoListCompressed;
    }
}

我该如何修复它并在 onResume 从头开始 这个 AsyncTasks ?

当你取消asynctask时,虽然它被取消了。您的 asyncTask 将保持 运行 直到 doInBackGround() 完成其工作。

因此,对于您的 GetOriginalVideosAsync,请在 doInBackground 中执行此操作:

@Override
protected ArrayList<Video> doInBackground(File[]... arg) {
files = arg[0];
for (File file : files) {

//add this

if(isCancelled){

return null;

}

if (!file.isDirectory() && isVideoFile(file.getPath())) {
videoList.add(new Video(file.getName(), file, new Date(file.lastModified())));
}

}
return videoList;
}

为了您的 GetCompressedVideosAsync,请在 doInBackground 中执行此操作:

@Override
protected ArrayList<Video> doInBackground(File[]... arg) {
files = arg[0];
for (File file : files) {

//add this    
if(isCancelled){
return null;
}

if (!file.isDirectory() && isVideoFile(file.getPath())) {
videoListCompressed.add(new Video(file.getName(), file, new Date(file.lastModified())));

}

}
return videoListCompressed;
}

更新

在我告诉您的同一位置的两个任务中尝试此操作:

if(isCancelled){
break;
}

更新 2

看你的asyncTaks一定是activity

的成员变量
class MyActivity extends ........{

private GetOriginalVideosAsync orginalTask;
private GetCompressedVideosAsync compressedTask;
.......



}

像这样调用暂停:

@Override
protected void onPause() {

    orginalTask.cancel(true);
    compressedTask.cancel(true);
    super.onPause();

}

private void getLoadOriginalVideos() {
    if (videoList.isEmpty()) {
        File directory = new File(Environment.getExternalStorageDirectory() + File.separator + APPDIR);
        ArrayList<File> filesList = new ArrayList<File>();
        if (directory.isDirectory() && directory.exists()) {
            filesList.addAll(Arrays.asList(getOriginalVideos(directory.listFiles())));
        }
     orginalTask =   new GetOriginalVideosAsync();

    orginalTask.execute(filesList.toArray(new File[filesList.size()]));
    }
}

可以随时通过调用 cancel(boolean) 来取消任务。调用此方法将导致对 isCancelled() 的后续调用为 return true。调用此方法后,在 doInBackground(java.lang.Object[]) returns 之后将调用 onCancelled(java.lang.Object),而不是 onPostExecute(java.lang.Object)。为确保尽快取消任务,您应该始终定期从 doInBackground(java.lang.Object[]) 检查 isCancelled() 的 return 值,如果可能(例如在循环内)。

来源:https://developer.android.com/reference/android/os/AsyncTask

您在代码中遇到的问题是您正在创建一个新实例,而不是使用您创建的同一个实例 ,您可以通过在 class 级别而不是 method/block 级别声明实例 全局可访问 来实现。

问题

    ...
    new GetOriginalVideosAsync().execute(...) 
    new GetCompressedVideosAsync().execute(...)
    ...
    super.onPause();
    new GetOriginalVideosAsync().cancel(true);
    new GetCompressedVideosAsync().cancel(true);
    ...

正确的方法

    ...        
    getOriginalVideosAsync = new GetOriginalVideosAsync(); // Declare this in class level
    getOriginalVideosAsync.execute(...) // replace old execute code with the instance
    getCompressedVideosAsync = new GetCompressedVideosAsync(); // Declare this in class level
    getCompressedVideoAsync.execute(...) // replace old execute code with the instance
    ...
    super.onPause();
    getOriginalVideosAsync().cancel(true);
    getCompressedVideosAsync().cancel(true);
    ...

再看看"java global variable vs local variable",希望解释有帮助,干杯。