I'm making an app with a download process, it will download a certain file. If I turn off the Wi-Fi when the file is downloading, the app crashes.
This is the log: recvfrom failed: ETIMEDOUT (Connection timed out)
I have a conditional, but it seems not to work. If I debug the code, it seems to enter the conditional.
else {
Thread.sleep(4000); //doesn't work, doesn't sleep
downloadresult = false;
}
I want the download process to pause when I turn off the Wi-Fi. Is there any way of doing this?
Thanks in advance.
All code
protected String doInBackground(String... f_url) {
try {
long total = 0;
URL url = new URL(f_url[0]);
HttpURLConnection conection = (HttpURLConnection) url.openConnection();
int lenghtOfFile = conection.getContentLength();
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file));
conection.connect();
BufferedInputStream input = new BufferedInputStream(conection.getInputStream());
byte data[] = new byte[8192];
int lastcount = 0;
while ((count = input.read(data)) != -1) {
if (isCanceled) { // this code waiting the click button :)
file.delete();
downloadresult = false;
break;
}
if (intCheck()) { // check internet and download
total += count;
downloadresult = true;
int ProgBarCount = (int) ((total * 100) / lenghtOfFile);
if (ProgBarCount > lastcount) {
lastcount = ProgBarCount;
publishProgress(Integer.toString(ProgBarCount));
}
output.write(data, 0, count);
}
else {
Thread.sleep(4000); //doesn't work, doesn't sleep
downloadresult = false;
}
}
output.flush();
output.close();
input.close();
}
catch (Exception e) {
e.printStackTrace();
exmessage = e.getMessage().toString();
downloadresult = false;
}
return null;
}
If I debug the code, it works perfectly. If the app can't dowload the file, I want the app to wait 4000ms and then try again, but if I run the app, it crashes.
How can i pause/resume the download process. Thank You
I fixed the problem :)
Thanks for all respond, I love it <3
Code:
protected String doInBackground(String... f_url) {
try {
long total = 0;
URL url = new URL(f_url[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
/* if (file.exists())
{
connection.setAllowUserInteraction(true);
connection.setRequestProperty("Range", "bytes=" + lenghtOfFile + "-");
}*/
if(file.exists()){
deneme = file.length();
connection.setRequestProperty("Range", "bytes="+(file.length())+"-");
}
else{
connection.setRequestProperty("Range", "bytes=" + deneme + "-");
}
String connectionField = connection.getHeaderField("content-range");
if (connectionField != null)
{
String[] connectionRanges = connectionField.substring("bytes=".length()).split("-");
deneme = Long.valueOf(connectionRanges[0]);
}
if (connectionField == null && file.exists())
file.delete();
connection.setConnectTimeout(14000);
connection.setReadTimeout(20000);
connection.connect();
long lenghtOfFile = connection.getContentLength() + deneme;
RandomAccessFile output = new RandomAccessFile(file,"rw");
BufferedInputStream input = new BufferedInputStream(connection.getInputStream());
output.seek(deneme);
byte data[] = new byte[1024];
int lastcount = 0;
while ((count = input.read(data,0,1024)) != -1) {
if (isCanceled) { // this code waiting the click button :)
file.delete();
downloadresult = false;
break;
}
if (intCheck()) { // check internet and download
total += count;
downloadresult = true;
int ProgBarCount = (int) ((total * 100) / lenghtOfFile);
if (ProgBarCount > lastcount) {
lastcount = ProgBarCount;
publishProgress(Integer.toString(ProgBarCount));
}
output.write(data, 0, count);
}
}
// output.flush();
output.close();
input.close();
}
catch (Exception e) {
e.printStackTrace();
exmessage = e.getMessage().toString();
downloadresult = false;
}
return null;
}
Don't pause background tasks. When anything goes wrong cancel the task. Remember your app was smart enough to start a background task. It will be smart enough to restart it again later. If your going to pause a background task it should be paused only at the users bequest.
Related
I have app for download file apk 20 MB from the server, but problem download process stops at 50% or 60% some time and file get the wrong size and can't install app . any help ? I have tried some solutions like adding
set Connect Timeout .
this my code
public DownloadService() {
super("DownloadService");
}
#Override
protected void onHandleIntent(Intent intent) {
String urlToDownload = intent.getStringExtra("url");
ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
try {
URL url = new URL(urlToDownload);
String fileExtenstion = MimeTypeMap.getFileExtensionFromUrl(String.valueOf(url));
String name_file = URLUtil.guessFileName(String.valueOf(url), null, fileExtenstion);
URLConnection connection = url.openConnection();
connection.connect();
int fileLength = connection.getContentLength();
InputStream input = new BufferedInputStream(connection.getInputStream());
OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory()+"/Appt/" + name_file);
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
Bundle resultData = new Bundle();
resultData.putInt("progress" ,(int) (total * 100 / fileLength));
receiver.send(UPDATE_PROGRESS, resultData);
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
Bundle resultData = new Bundle();
resultData.putInt("progress" ,100);
receiver.send(UPDATE_PROGRESS, resultData);
}
I'm trying to download files in java in a multi-segment way (i.e., dividing it to several parts and downloading each part in a separate thread parallelly) but when I use the code below, it seems each thread is downloading the whole file instead of just a part of it but when it finishes, file is downloaded correctly.
note that "downloadedSizeCombined" is sum of all bytes which are downloaded by all the threads and ArrayList "downloadedSize" keeps track of bytes which are downloaded by a single thread.
this method is in class Download which extends SwingWorker.
public Void doInBackground() {
ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < MAX_NUMBER_OF_PARTS; i++) {
int numOfThePart = i;
es.execute(new Runnable() {
#Override
public void run() {
RandomAccessFile file = null;
InputStream stream = null;
try {
while (Download.this.getStatus() == WAITINGLIST) {
Thread.sleep(1);
}
// Open connection to URL.
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
// Specify what portion of file to download.
int startByte = numOfThePart * sizeOfFile / MAX_NUMBER_OF_PARTS;
int endByte = ((numOfThePart + 1) * sizeOfFile / MAX_NUMBER_OF_PARTS) - 1;
if (numOfThePart == MAX_NUMBER_OF_PARTS)
endByte = ((numOfThePart + 1) * sizeOfFile / MAX_NUMBER_OF_PARTS);
connection.setRequestProperty("Range",
"bytes=" + ((startByte + downloadedSize.get(numOfThePart))) + "-" + endByte);
// Connect to server.
connection.connect();
// Check for valid content length.
int contentLength = connection.getContentLength();
if (contentLength < 1) {
System.out.println("1");
}
/* Set the size for this download if it
hasn't been already set. */
if (sizeOfFile == -1) {
sizeOfFile = contentLength;
}
file = new RandomAccessFile(new File(s.getCurrentDirectory(), getFileName(url)),
"rw");
file.seek(startByte + downloadedSize.get(numOfThePart));
fileLocation = new File(s.getCurrentDirectory(), getFileName(url));
stream = connection.getInputStream();
while (status == CURRENT) {
file.seek(startByte + downloadedSize.get(numOfThePart));
byte buffer[];
buffer = new byte[MAX_BUFFER_SIZE];
// Read from server into buffer.
int read = stream.read(buffer);
if (read == -1)
break;
// Write buffer to file.
file.write(buffer, 0, read);
downloadedSizeCombined += read;
downloadedSize.set(numOfThePart, downloadedSize.get(numOfThePart) + read);
publish(numOfThePart);
while (status == PAUSED) {
Thread.sleep(1);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Close file.
if (file != null) {
try {
file.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// Close connection to server.
if (stream != null) {
try {
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
});
}
return null;
}
Thanks in advance.
Can't we use UDP connection? So if we use DatagramSocket class, it will anyways send the data in packets. Try this.
Will get back on this soon..
I'm working on an Android project that requires FTP download to be paused/resumed.
Here is the code I use for FTP connection:
ftpClient.setConnectTimeout(25000);
ftpClient.login("login", "password");
ftpClient.changeWorkingDirectory("/audio");
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
then I start download:
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(localFile));
byte[] bytesArray = new byte[4096];
int bytesRead = -1;
totalRead = 0;
if (localFileSize > 0) {
ftpClient.setRestartOffset(localFileSize);
ftpClient.restart(localFileSize);
}
InputStream inputStream = ftpClient.retrieveFileStream(fileName);
while ((bytesRead = inputStream.read(bytesArray)) != -1) {
totalRead += bytesRead;
outputStream.write(bytesArray, (int) localFileSize, bytesRead);
}
success = ftpClient.completePendingCommand();
and I try to pause using abort like this:
if (ftpClient.abort()) {
//connection aborted!;
}
But it seems that abort doesn't work while there is an active download as mentioned here: https://issues.apache.org/jira/browse/NET-419
Is there any way I can perform pause/resume for FTP downloads in Android?
If you really want to pause the download only (as opposite to abort/reconnect/resume), then all you need to do, is temporarily pause the while loop that writes to the data connection stream.
See How to pause/resume thread in Android?
I used the same AsyncTask for connect, download and abort operations:
protected Void doInBackground(Integer... params) {
int command = params.length > 0 ? params[0] : 0;
switch (command) {
case CONNECT:
connect();
break;
case DOWNLOAD:
download();
break;
case PAUSE:
abortConnection();
break;
}
return null;
}
To make sure there is only one task running each time I used Singleton design pattern
public static FtpConnectTask getInstance(FTPClientWrapper ftpClient) {
if (instance != null) {
if (instance.getStatus().name().toLowerCase().equals("running"){
instance.cancel(true);
}
if (instance.getStatus().name().toLowerCase().equals("finished")) {
// task finished!
}
}
instance = new FtpConnect(uiListener, ftpClientW);
return instance;
}
This is code of download() method:
we look for local file size each time the download starts, then we use this size as starting point
//create local file
File localFile = new File(outDir, FILE_NAME));
// get file size if the file exists
long localFileSize = localFile.length();
//retrieve file from server
try {
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(localFile, true));
byte[] bytesArray = new byte[4096];
int bytesRead;
int totalRead = (int) localFileSize;
ftpClient.restart(localFileSize);
InputStream inputStream = ftpClient.retrieveFileStream(REMOTE_FILE);
while ((bytesRead = inputStream.read(bytesArray)) != -1) {
totalRead += bytesRead;
outputStream.write(bytesArray, 0, bytesRead);
// break the loop when AsyncTask is cancelled
if(isCancelled()){
break;
}
}
if (ftpClient.completePendingCommand()) {
// Task completed!
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
This is code of abortConnection()
if (ftpClient.isConnected()) {
try {
if (ftpClient.abort()) {
// Connection aborted!
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
// Not connected!
}
To resume your download just call download() again.
I have an async downloader in my app, but sometimes the connection is lost, especially when I'm on a mobile connection and if the file is a large one (>10 MB).
Is there a way to catch when a download stops and then force it to resume with the result of completing the download?
This is the async task doInBackground:
protected String doInBackground(String... aurl) {
int count;
try {
URL url = new URL(aurl[0]);
URLConnection conexion = url.openConnection();
// conexion.setRequestProperty("Range", "bytes=" + downloaded + "-");
conexion.connect();
int lenghtOfFile = conexion.getContentLength();
pesoVideo = lenghtOfFile / 1048576;
output = "/sdcard/" + folderString + "/" + nomeFile + ".mp3";
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(
VideoDownloaderBrowserActivity.this.output);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
publishProgress("" + (int) ((total * 100) / lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
}
return null;
}
This is the onProgressUpdate:
protected void onProgressUpdate(String... progress) {
if (Integer.parseInt(progress[0]) > progresso) {
...
}
}
Here is a thread discussing resumable downloading in Android below API 9. Otherwise DownloadManager is a good option too for newer versions.
Basically you need to enable byte serving on your server to allow for the resumable downloading.
I am building an Android Application and I need to download a file from a url, which is 33 MB large.
Here the download task:
try {
int MAX_BUFFER_SIZE = 4096;
URL mUrl = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
connection.setRequestMethod("GET");
long length = connection.getContentLength(), downloaded = 0;
int read;
byte [] buffer = new byte[(((int)length) > MAX_BUFFER_SIZE) ? MAX_BUFFER_SIZE : (int)length];
String filename = getFilename(mUrl);
File file = new File (SDCARD_ROOT);
if (!file.exists() || !file.isDirectory()){
file.mkdir();
}
this.filename = filename;
file = new File (SDCARD_ROOT + this.filename);
FileOutputStream fos = new FileOutputStream (file);
//Start downloading
InputStream stream = connection.getInputStream();
while ((read=stream.read(buffer)) > -1){
fos.write(buffer, 0, read);
downloaded += read;
publishProgress((int) ((float) downloaded/length * 100));
}
fos.close();
return 1;
} catch (Exception e){
Log.e("REV-PARTS", "Revolver parts error in DownloadTask: " + e.getMessage());
return 2;
}
It works right with small files (1-15 MB), but it will return a "unexpected end of stream" exception with large files.
Setting a chunk size seemed to work for me.
connection.setChunkedStreamingMode(1048576);
For large files you need to set the connection time out manually by using the following code.
I have set the time out to 3 minutes
connection.setConnectTimeout(180000);
connection.setReadTimeout(180000);
While you catch the exception, I try the method downContinue(). I can show my code:
private void downloadApk() {
thread1 = new Thread() {
public void run() {
File oFile = null;
try {
URL url = new URL(PQGLApplication.resrootURL + "apk/PQGLMap.apk");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
ReadableByteChannel channel =
Channels.newChannel(urlConnection.getInputStream());
oFile =
new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/" + "hy_ht_new/" + "test2" + ".apk");
oFile.setWritable(true);
oFile.setReadable(true);
if (oFile.exists()) {
oFile.delete();
}
FileOutputStream fos = new FileOutputStream(oFile);
fileSize = urlConnection.getContentLength();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int noOfBytes = 0;
byte[] data = null;
sendApkMessage(0, 0);
while ((noOfBytes = channel.read(buffer)) > 0) {
data = new byte[noOfBytes];
System.arraycopy(buffer.array(), 0, data, 0, noOfBytes);
buffer.clear();
fos.write(data, 0, noOfBytes);
downLoadFileSize += noOfBytes;
sendApkMessage(1, downLoadFileSize);
}
fos.flush();
fos.close();
channel.close();
sendApkMessage(2, oFile.getAbsolutePath());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
downContinue();
}
};
};
thread1.start();
}
private void downContinue() {
continueTime++;
try {
if (continueTime == 3) {
continueTime = 0;
sendApkMessage(4, 0);
Log.e("what is the continuetime", "continueTime" + continueTime);
} else {
URL url = new URL(PQGLApplication.resrootURL + "apk/PQGLMap.apk");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
File oFile =
new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/"
+ "hy_ht_new/" + "test2" + ".apk");
RandomAccessFile oSavedFile = new RandomAccessFile(oFile, "rw");
FileOutputStream fos = new FileOutputStream(oFile);
ReadableByteChannel channel = Channels.newChannel(urlConnection.getInputStream());
// oSavedFile.seek(nPos);
ByteBuffer buffer = ByteBuffer.allocate(1024);
byte[] data = null;
int temp = 0;
sendApkMessage(3, oFile.getAbsolutePath());
while ((temp = channel.read(buffer)) > 0) {
data = new byte[temp];
System.arraycopy(buffer.array(), 0, data, 0, temp);
buffer.clear();
fos.write(data, 0, temp);
}
fos.flush();
fos.close();
oSavedFile.close();
sendApkMessage(2, oFile.getAbsolutePath());
continueTime = 0;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("what is the exception", e.toString() + continueTime);
downContinue();
}
}
This downContinue method is used to solve this problem. At least, the file is downloaded successfully!