简体   繁体   中英

How to cancle AsyncTask in Android

In my application i have 2 AsyncTask methods and i want when activity go to onPause cancel this AsyncTask s and in onResume start from the beginning .
I write below codes, i pressed home button and application go to onPause and open again this app from recent apps
My mean is call onPause and onResume !

But when application run again ( from recent app ), call onResume but not start AsyncTask from the beginning!

My codes:

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

How can i fix it and in onResume start from beginning this AsyncTask s?

When you cancel asynctask, although it is canceled. Your asyncTask will keep running until doInBackGround() finishes its work.

So for your GetOriginalVideosAsync do this in 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;
}

And for your GetCompressedVideosAsync do this in 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;
}

update

Try this in both tasks at the same place that I told you to:

if(isCancelled){
break;
}

update 2

Look your asyncTaks must be member variables of the activity

class MyActivity extends ........{

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



}

Call on pause like this:

@Override
protected void onPause() {

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

}

and

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

A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(java.lang.Object), instead of onPostExecute(java.lang.Object) will be invoked after doInBackground(java.lang.Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(java.lang.Object[]), if possible (inside a loop for instance.)

Source: https://developer.android.com/reference/android/os/AsyncTask

The problem you are having in your code is that you are creating a new instance rather than working with the same instance you created , you can do this by making the instance globally accessible by declaring them in the class level rather than in the method/block level.

Problem

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

Correct way

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

Have a look at "java global variable vs local variable" to have more understanding, hope the explanation helps, cheers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM