1

I have a few downloads that are submitted as tasks to a ThreadPoolExecutor. Now, I am creating this ThreadPoolExecutor in a global class that extends Application. I am storing all the submitted tasks in a hashmap with ids.

I have a list view in a fragment. This list view item contains pause and resume buttons. When I click on the list item itself, the download FutureTask is submitted to the global pool executor. Now, when I click on the pause button of the listview item, I want that particular task to pause.

I have the onClick method of the pause button in my list view's custom adapter. So, when I click the button, in my adapter class, I get the future task related to that list item by name and then do .cancel(). When I check for isCancelled() value, it returns true. This means that the task has been cancelled but my download still runs and the file gets completely downloaded. How can I solve this? Any help would be appreciated.

PS: I have also tried submitting threads with runnable passed as argument to the executor. Then, I would get the thread by its name (used a custom ThreadFactory that returns thread with name) and then call thread.wait() until the resume button is pressed again. Does not work either!

Here is the sample code:

My GlobalState Class:

    public class GlobalState extends Application{

        HashMap<String, Future<?>> futureMapMain = new HashMap<String, Future<?>>();

        ThreadPoolExecutor mainExec = new ThreadPoolExecutor(2, 2, 2000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new YourThreadFactory());

        public void submitTaskMain(String name, FutureTask<String> task){
            Future<?> longRunningTaskFuture = mainExec.submit(task);
            futureMapMain.put(name, longRunningTaskFuture);
        }

        public void cancelTaskMain(String name){
            futureMapMain.get(name).cancel(true);
            Log.e("Global State", "task cancelled?: " + futureMapMain.get(name).isCancelled());
            futureMapMain.remove(name);
        }

public void pauseTaskMain(String name){
        paused = true;
        while(paused==true){
        try {
            synchronized(futureMapMain.get(name)){
                futureMapMain.get(name).wait();
            }
        //  Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }
    }

    public void resumeTaskMain(String name){
        paused = false;
        synchronized(futureMapMain.get(name)){
            futureMapMain.get(name).notify();
        }
    }

        public HashMap<String, Future<?>> getFutureMap(){
            return futureMapMain;
        }

        public ThreadPoolExecutor getMainExeutor(){
            return mainExec;
        }

        public class YourThreadFactory implements ThreadFactory {
            public Thread newThread(Runnable r) {
                return new Thread(r, gettName());
            }
        }
    }

My Download Method that is written inside my fragment class. gets executed on list item click:

public void abDownloadTask(){
    FutureTask<String> fTask = new FutureTask<String>(new Callable<String>() {

        @Override
        public String call() throws Exception {
            // TODO Auto-generated method stub
            for(something) {
                /* DOES SOME DOWNLOAD USING url.getcontent() with different urls in a loop and stores files to sd card. */
            }
        }
    }

    mainGs = (GlobalState) getActivity().getApplication();
    mainExec = mainGs.getMainExeutor();
    mainGs.settName(somenameforThread);
    mainGs.submitTaskMain(someNameforThread, fTask);    
}

My custom list Adapter code inside onclick of pause button:

    Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub

                                    needToPause = true;
globalstate.pauseTaskMain(threadname);
            }
        }

I actually prefer pausing and resuming my task using wait() or something like that rather than canceling the task completely. Any help would be appreciated. Thank you!

Shreya
  • 241
  • 1
  • 2
  • 11
  • There is no magic, of course! Your task won't be cancelled if it does not listen for cancellation! You have to check for thread interruption by yourself. – isnot2bad Mar 14 '15 at 18:50
  • @isnot2bad: Please check my edit. I have updated pause and resume methods in Globalstate class. I put a flag called "paused" and while it is true, I am waiting on the thread. Is that not enough? How can I listen for wait or cancel? Thanks! – Shreya Mar 16 '15 at 03:30
  • Your `cancelTaskMain` method seems correct, but cancelling is a cooperative thing, so you task must also "listen" for cancellation and _do something_ to make it work. `pauseTaskMain` is completely wrong. You cannot simply pause a task - all you do there is to pause the thread that is calling `pauseTaskMain`. – isnot2bad Mar 16 '15 at 07:58
  • @isnot2bad: Okay, Maybe I can listen to the isCanceled() value of that task. Is there anyway to pause and resume a task instead of canceling it completely? Thank you! – Shreya Mar 17 '15 at 03:40
  • No! Correct task cancellation is done by checking the interruption state of a task! See http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html or http://www.ibm.com/developerworks/library/j-jtp05236/ for details! – isnot2bad Mar 17 '15 at 09:50

0 Answers0