fast download pausing
* fast download pausing * fix UI thread blocking when calling pause() * check running threads before start the download * fix null pointer exception in onDestroy in the download service, without calling onCreate method (android 8)
This commit is contained in:
parent
9f4a7e664f
commit
e2aa36d083
5 changed files with 241 additions and 118 deletions
|
|
@ -14,16 +14,19 @@ import static org.schabi.newpipe.BuildConfig.DEBUG;
|
|||
* Runnable to download blocks of a file until the file is completely downloaded,
|
||||
* an error occurs or the process is stopped.
|
||||
*/
|
||||
public class DownloadRunnable implements Runnable {
|
||||
public class DownloadRunnable extends Thread {
|
||||
private static final String TAG = DownloadRunnable.class.getSimpleName();
|
||||
|
||||
private final DownloadMission mMission;
|
||||
private final int mId;
|
||||
|
||||
private HttpURLConnection mConn;
|
||||
|
||||
DownloadRunnable(DownloadMission mission, int id) {
|
||||
if (mission == null) throw new NullPointerException("mission is null");
|
||||
mMission = mission;
|
||||
mId = id;
|
||||
mConn = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -47,12 +50,7 @@ public class DownloadRunnable implements Runnable {
|
|||
return;
|
||||
}
|
||||
|
||||
while (mMission.errCode == DownloadMission.ERROR_NOTHING && mMission.running && blockPosition < mMission.blocks) {
|
||||
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
mMission.pause();
|
||||
return;
|
||||
}
|
||||
while (mMission.running && mMission.errCode == DownloadMission.ERROR_NOTHING && blockPosition < mMission.blocks) {
|
||||
|
||||
if (DEBUG && retry) {
|
||||
Log.d(TAG, mId + ":retry is true. Resuming at " + blockPosition);
|
||||
|
|
@ -83,8 +81,9 @@ public class DownloadRunnable implements Runnable {
|
|||
|
||||
long start = blockPosition * DownloadMission.BLOCK_SIZE;
|
||||
long end = start + DownloadMission.BLOCK_SIZE - 1;
|
||||
long offset = mMission.getThreadBytePosition(mId);
|
||||
|
||||
start += mMission.getThreadBytePosition(mId);
|
||||
start += offset;
|
||||
|
||||
if (end >= mMission.length) {
|
||||
end = mMission.length - 1;
|
||||
|
|
@ -93,14 +92,21 @@ public class DownloadRunnable implements Runnable {
|
|||
long total = 0;
|
||||
|
||||
try {
|
||||
HttpURLConnection conn = mMission.openConnection(mId, start, end);
|
||||
mConn = mMission.openConnection(mId, start, end);
|
||||
mMission.establishConnection(mId, mConn);
|
||||
|
||||
// check if the download can be resumed
|
||||
if (mConn.getResponseCode() == 416 && offset > 0) {
|
||||
retryCount--;
|
||||
throw new DownloadMission.HttpError(416);
|
||||
}
|
||||
|
||||
// The server may be ignoring the range request
|
||||
if (conn.getResponseCode() != 206) {
|
||||
mMission.notifyError(new DownloadMission.HttpError(conn.getResponseCode()));
|
||||
if (mConn.getResponseCode() != 206) {
|
||||
mMission.notifyError(new DownloadMission.HttpError(mConn.getResponseCode()));
|
||||
|
||||
if (DEBUG) {
|
||||
Log.e(TAG, mId + ":Unsupported " + conn.getResponseCode());
|
||||
Log.e(TAG, mId + ":Unsupported " + mConn.getResponseCode());
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -108,7 +114,8 @@ public class DownloadRunnable implements Runnable {
|
|||
|
||||
f.seek(mMission.offsets[mMission.current] + start);
|
||||
|
||||
is = conn.getInputStream();
|
||||
is = mConn.getInputStream();
|
||||
|
||||
byte[] buf = new byte[DownloadMission.BUFFER_SIZE];
|
||||
int len;
|
||||
|
||||
|
|
@ -121,18 +128,17 @@ public class DownloadRunnable implements Runnable {
|
|||
|
||||
if (DEBUG && mMission.running) {
|
||||
Log.d(TAG, mId + ":position " + blockPosition + " finished, " + total + " bytes downloaded");
|
||||
mMission.setThreadBytePosition(mId, 0L);
|
||||
}
|
||||
|
||||
// if the download is paused, save progress for this thread
|
||||
if (!mMission.running) {
|
||||
mMission.setThreadBytePosition(mId, total);
|
||||
break;
|
||||
}
|
||||
if (mMission.running)
|
||||
mMission.setThreadBytePosition(mId, 0L);// clear byte position for next block
|
||||
else
|
||||
mMission.setThreadBytePosition(mId, total);// download paused, save progress for this block
|
||||
|
||||
} catch (Exception e) {
|
||||
mMission.setThreadBytePosition(mId, total);
|
||||
|
||||
if (e instanceof ClosedByInterruptException) break;
|
||||
if (!mMission.running || e instanceof ClosedByInterruptException) break;
|
||||
|
||||
if (retryCount++ >= mMission.maxRetry) {
|
||||
mMission.notifyError(e);
|
||||
|
|
@ -147,29 +153,43 @@ public class DownloadRunnable implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
try {
|
||||
f.close();
|
||||
} catch (Exception err) {
|
||||
// ¿ejected media storage? ¿file deleted? ¿storage ran out of space?
|
||||
}
|
||||
|
||||
try {
|
||||
if (is != null) is.close();
|
||||
} catch (Exception err) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
try {
|
||||
f.close();
|
||||
} catch (Exception err) {
|
||||
// ¿ejected media storage? ¿file deleted? ¿storage ran out of space?
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "thread " + mId + " exited from main download loop");
|
||||
}
|
||||
|
||||
if (mMission.errCode == DownloadMission.ERROR_NOTHING && mMission.running) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "no error has happened, notifying");
|
||||
}
|
||||
mMission.notifyFinished();
|
||||
}
|
||||
|
||||
if (DEBUG && !mMission.running) {
|
||||
Log.d(TAG, "The mission has been paused. Passing.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interrupt() {
|
||||
super.interrupt();
|
||||
|
||||
try {
|
||||
if (mConn != null) mConn.disconnect();
|
||||
} catch (Exception e) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue