Android-Download-Manager-Pro icon indicating copy to clipboard operation
Android-Download-Manager-Pro copied to clipboard

onDownloadfinished called directly after connectionlost on lolipop 5.0

Open hassan379 opened this issue 8 years ago • 9 comments

hi , thx for this great library but i am facing issue , in lolipop 5.0 ondownloadFinished Called Directly after connectionlost , but on other apis it works fine even on 5.1 , this issue appear only in 5.0 i noticed that an error raised 07-31 16:50:06.941 1670-1804/com.filmov.itech.movies E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-229 Process: com.filmov.itech.movies, PID: 1670 java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.FileInputStream.read(byte[])' on a null object reference at tools.majid.core.chunkWorker.Rebuilder.run(Rebuilder.java:52)

hassan379 avatar Aug 01 '15 07:08 hassan379

I have the same problem when I pause a resumable task: dm.pause(token); it called the sequence : onpause → rebuild → rebuild finish → complete so I can`t resume the download any more

daniaDlbani avatar Aug 05 '15 10:08 daniaDlbani

this happened only with android lolipop 5.0.1 in earlier versions it works perfectly..

daniaDlbani avatar Aug 05 '15 10:08 daniaDlbani

Did you check that on handheld device or on an emulator?

majidgolshadi avatar Aug 05 '15 18:08 majidgolshadi

@majidgolshadi thanks for the fast response, I am working on real device.

daniaDlbani avatar Aug 06 '15 06:08 daniaDlbani

i tested it on real device and emulator and both the same result , please fix this issue your library is very great and i only faced this issue on it

hassan379 avatar Aug 06 '15 15:08 hassan379

after days of hardworking i have found the source of the error , in Asyncworker :

 if (!this.isInterrupted()) {
     observer.rebuild(chunk);
    Log.i("isInterrupted()","yes");
}

for some reason this if statement become true after we call pausedownload , and for this reason observer call rebuild to finish the download , i saw this issue only on 5.0 , i compared this on other apis , the if statement was false when we call pausedownload sorry bad english UPDATE: i notice something that .isInterrupted() return false even after we interrupt every chunk thread , but in other apis return true

hassan379 avatar Aug 09 '15 20:08 hassan379

FIXED : I fixed this issue by adding flag inside AsyncWorker , i name it as "isInturrputed" , the default value of this flag is false and became true when trying to inturrput every thread chunk , the code now became like this AsyncWorker Class :

package tools.majid.core.chunkWorker;

import android.os.Build;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;

import tools.majid.Utils.helper.FileUtils;
import tools.majid.database.elements.Chunk;
import tools.majid.database.elements.Task;

/**
 * Created by Majid Golshadi on 4/14/2014.
 */
public class AsyncWorker extends Thread{

    private final int BUFFER_SIZE = 1024;

    private final Task task;
    private final Chunk chunk;
    private final Moderator observer;
    private byte[] buffer;
    private ConnectionWatchDog watchDog;
    private Boolean isInterrupted=false;

    public boolean stop = false;


    public AsyncWorker(Task task, Chunk chunk, Moderator moderator){
        buffer = new byte[BUFFER_SIZE];

        this.task = task;
        this.chunk = chunk;
        this.observer = moderator;
    }

    public void setInterrupt()
    {
        isInterrupted=true;
    }

    @Override
    public void run() {
        try {

            URL url = new URL(task.url);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(50000);
            connection.setReadTimeout(50000);
            if (chunk.end != 0) // support unresumable links
                connection.setRequestProperty("Range", "bytes=" + chunk.begin + "-" + chunk.end);

            connection.connect();


            File cf = new File(FileUtils.address(task.save_address, String.valueOf(chunk.id)));
            InputStream remoteFileIn = connection.getInputStream();
            FileOutputStream chunkFile = new FileOutputStream(cf, true);

            int len = 0;
            // set watchDoger to stop thread after 1sec if no connection lost
            watchDog = new ConnectionWatchDog(5000, this);
            watchDog.start();

                while (!this.isInterrupted() &&
                        (len = remoteFileIn.read(buffer)) > 0) {

                    watchDog.reset();
                    chunkFile.write(buffer, 0, len);
                    process(len);
                }



            chunkFile.flush();
            chunkFile.close();
            watchDog.interrupt();
            connection.disconnect();

            if(Build.VERSION.SDK_INT==21)
            {

                if(!isInterrupted)
                {
                    observer.rebuild(chunk);
                    Log.i("isInterrupted()","yes");
                }
            }
            else
            {
                if (!this.isInterrupted()) {
                    observer.rebuild(chunk);
                    Log.i("isInterrupted()","yes");
                }

            }


        }catch (SocketTimeoutException e) {
            e.printStackTrace();

            observer.connectionLost(task.id);
            puaseRelatedTask();

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return;
    }

    private void process(int read) {
        observer.process(chunk.task_id, read);
    }

    private void puaseRelatedTask() {
        observer.pause(task.id);
    }

    private boolean flag = true;
    public void connectionTimeOut(){
        if (flag) {
            watchDog.interrupt();
            flag = false;
            observer.connectionLost(task.id);
            puaseRelatedTask();
        }

    }

}

and the block of code that handle inturrputing every thread chunk in Moderator Class became like this :

   List<Chunk> taskChunks =
                    chunksDataSource.chunksRelatedTask(task.id);
            for (Chunk chunk : taskChunks) {
                Thread worker = workerList.get(chunk.id);
                if (worker != null) {
                    worker.interrupt();
                    if(Build.VERSION.SDK_INT==21)
                        ((AsyncWorker)worker).setInterrupt();
                    workerList.remove(chunk.id);
                    Log.i("workerListremove",String.valueOf(chunk.id));
                }
            }

thx to me for fixing this issue :P

hassan379 avatar Aug 13 '15 17:08 hassan379

Send your bug fix with pull request (pr)

majidgolshadi avatar Aug 14 '15 05:08 majidgolshadi

I had a similar bug reported from crashlytics. But I couldn't reproduce this. How can I encounter this with some steps?

nthuat avatar Mar 04 '16 04:03 nthuat