Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onDownloadfinished called directly after connectionlost on lolipop 5.0 #6

Open
hassan379 opened this issue Aug 1, 2015 · 9 comments

Comments

@hassan379
Copy link

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)

@daniaDlbani
Copy link

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
Copy link

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

@majidgolshadi
Copy link
Owner

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

@daniaDlbani
Copy link

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

@hassan379
Copy link
Author

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
Copy link
Author

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
Copy link
Author

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

@majidgolshadi
Copy link
Owner

Send your bug fix with pull request (pr)

@nthuat
Copy link

nthuat commented Mar 4, 2016

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants