public class PreviewDownload extends AsyncTask<String, Void, String> {
public static final String TAG = "PreviewDownload";
public String inputPath = null;
public String outputFolder = null;
public IRIssue issue = null;
#Override
protected String doInBackground(String... parms) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
issue = Broker.model.issueDataStore.getIRIssue(parms[0]);
outputFolder = IRConstant.issueFolder(issue.year, issue.month, issue.day, issue.pubKey);
try {
inputPath = IRConstant.downloadFile(issue.year, issue.month, issue.day, issue.pubKey, "preview", "0");
URL url = new URL(inputPath);
Log.d (TAG,"input: " + inputPath);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
return null;
// return "Server returned HTTP " + connection.getResponseCode()
// + " " + connection.getResponseMessage();
// download the file
input = connection.getInputStream();
output = new FileOutputStream(outputFolder + "/preview.zip");
Log.d (TAG,"output: " + output);
byte data[] = new byte[1024];
int count;
while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
}
} catch (Exception e) {
// return e.toString();
return null;
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return outputFolder;
}
#Override
protected void onPostExecute(String outputFolder) {
// TODO Auto-generated method stub
super.onPostExecute(outputFolder);
if (outputFolder != null) {
File zipFile = new File (outputFolder + "/preview.zip");
if (Utils.unzip(outputFolder,outputFolder + "/preview.zip" )) {
zipFile.delete();
issue.isThumbDownloaded = 1;
} else {
issue.isThumbDownloaded = 0;
}
} else {
Toast.makeText(Broker.launcherActivity.getBaseContext(), R.string.wordCantDownload, Toast.LENGTH_LONG).show();
issue.isThumbDownloaded = 0;
}
issue.updateProgress(issue.progress);
}
}
Here is the downloader I implemented , the problem is , when the network lost, the output become null and show error message, however, if I would like to retry two times before showing error message, are there any way to do this? If I perfer not to pass in an object instead of string ,is it not recommended? thanks
What prevents you from re-instanciating and re-executing a "Downloader" from your catch blocks in case of errors ?
You could use a single common shared object between dowloader instances to count the attempts, or better, pass a parameter to each of them. In the catch block, you would then retry if you didn't reach the limit, and increase the value passed to a new downloader... Something recursive.
int expectedLength = connection.getContentLength();
can you compare with the expectedLength & downloaded length and retry?
Related
I just implemented a HTTP Downloader. It has 4 button to do some operation: start, pause, resume, cancel download. When pressing pause or cancel button, I use AsyncTask.cancel() to cancel the download AsyncTask and disable all UI widget temporarily. When AsyncTask onCancelled triggers, I enable the UI widget.
Here's a question: I found inputStram.close() somehow is very slow sometimes. Cause it is called before onCancelled(), it will block UI for a while. I found some article discussed about it but none of their answer really work. It confuses me so bad...
Related questions:
Sometimes HttpURLConnection.getInputStream executes too slowly
InputStream won't close, or takes forever to
Below is my code in AsyncTask. Wish someone give some help. I will appreciate that a lot.
#Override
protected String doInBackground(URL... urls) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection httpURLConnection = null;
try {
URL url = urls[0];
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(CONNECT_TIMEOUT);
httpURLConnection.setInstanceFollowRedirects(true);
httpURLConnection.setRequestProperty("Range", "bytes=" + mDownloadedBytes + "-");
httpURLConnection.setUseCaches(false);
httpURLConnection.setReadTimeout(5000);
httpURLConnection.setRequestProperty("Connection", "close");
System.setProperty("http.keepAlive", "false");
httpURLConnection.connect();
if (!(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK // 200
|| httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_CREATED // 201
|| httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_ACCEPTED // 202
|| httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_AUTHORITATIVE // 203
|| httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_NO_CONTENT // 204
|| httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_RESET //205
|| httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_PARTIAL)) { //206
return "Download fail, server returned HTTP " + httpURLConnection.getResponseCode()
+ " " + httpURLConnection.getResponseMessage();
}
String fileName = getFileName();
String fileExtension = getFileExtension(httpURLConnection);
if(mDownloadFile == null) {
mDownloadFile = getDownloadFile(fileName, fileExtension);
output = new FileOutputStream(mDownloadFile);
} else {
if(mDownloadFile.exists()) {
output = new FileOutputStream(mDownloadFile, true);
} else {
cancel(true);
return null;
}
}
int fileLength = httpURLConnection.getContentLength();
if(sTotalFileLength == -1 && fileLength != -1){
sTotalFileLength = fileLength;
}
// update download state depending on fileLength
updateUI(fileLength);
// check free space if server respond this value
if(fileLength != -1){
if(!isFreeSpaceEnough(fileLength)){
return "Download fail, you don't have enough free space to save the file";
}
}
// download the file
input = httpURLConnection.getInputStream();
byte data[] = new byte[BUFFER_SIZE];
int count;
while ((count = input.read(data)) != -1) {
if (isCancelled()) {
return null;
}
mDownloadedBytes += count;
if(sTotalFileLength > 0){
int progress = (int)(mDownloadedBytes * 100 / sTotalFileLength);
publishProgress(progress);
}
try {
output.write(data, 0, count);
} catch (IOException e){
return "No enough free space to save file!";
} catch (IndexOutOfBoundsException e){
return "Write to file error";
}
}
// write a record to Download DB after download complete
// just record image in DownloadDb
if(!fileExtension.equals("") && isInImageExtensionList(fileExtension)) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mDbRow = new DownloadDbRow(dateFormat.format(new Date()), fileName+"."+fileExtension);
mDb.insert(mDbRow);
}
// Tell system to scan for media file change
mMediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(mDownloadFile);
mMediaScanIntent.setData(contentUri);
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null) {
output.flush();
output.close();
}
/////////////////////
// //
// problems here!! //
// //
/////////////////////
if (input != null) {
input.close();
}
} catch (IOException e) {
return e.toString();
}
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
return DOWNLOAD_SUCCESSFULLY;
}
protected void doDownload(final String urlLink, final String fileName) {
Thread dx = new Thread() {
public void run() {
File root = android.os.Environment.getExternalStorageDirectory();
File dir = new File (root.getAbsolutePath() + "/Content2/");
if(dir.exists()==false) {
dir.mkdirs();
}
//Save the path as a string value
try
{
URL url = new URL(urlLink);
Log.i("FILE_NAME", "File name is "+imageFile);
Log.i("FILE_URLLINK", "File URL is "+url);
URLConnection connection = url.openConnection();
connection.connect();
// this will be useful so that you can show a typical 0-100% progress bar
int fileLength = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(dir+"/"+imageFile);
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
}
catch (Exception e)
{
e.printStackTrace();
Log.i("ERROR ON DOWNLOADING FILES", "ERROR IS" +e);
}
}
};
dx.start();
}
through this, I cannot download the file from the server.
How to solve this problem?
First of all you should use Async-Task.
Here is how you can do this
final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");
// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> {
private Context context;
public DownloadTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/file_name.extension");
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
return null;
}
total += count;
}
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return null;
}
#Override
protected void onPostExecute(String result) {
if (result != null)
Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
else
Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
}
i follow more explain in this site for download mp3 or picture from URL , I follow more method and try to write my method but when i run application it stop.
I make method to query download when click
also put permission for INTERNET & WRITE_EXTERNAL_STORAGE
put the problem is still
this method is download
public static void downloadMain(){
File fileToSave = null;
String scrPath ="http://***";
BufferedInputStream bis;
BufferedOutputStream bos;
fileToSave = new File(Environment.getExternalStorageDirectory().getPath() +"/"+ "A"+"/");
if (!fileToSave.exists())
fileToSave.mkdirs();
fileToSave = new File(Environment.getExternalStorageDirectory().getPath() +"/"+ "A" +"/" + "h"+"/");
if (!fileToSave.exists())
fileToSave.mkdirs();
File file = new File (fileToSave,"***.mp3");
try{
URL url = new URL(scrPath+"***.mp3");
URLConnection ucon = url.openConnection();
ucon.connect();
bis=new BufferedInputStream(ucon.getInputStream());
bos = new BufferedOutputStream(new FileOutputStream(file));
bis=new BufferedInputStream(url.openStream());
byte[] data = new byte[1024];
int a =0;
while(true){
int k = bis.read(data);
if(k==-1){
bis.close();
bos.flush();
bos.close();
break;
}
bos.write(data, 0, k);
a+=k;
}
}catch(IOException e){}
}
I have three main perplexity about your program:
Do you run the following code in an asynctask? (this must run asincronusly otherwise it will block)
Why it loop infinitly?
You couldn't open an url or a file named with a '*' inside of it
Edit:
You must run the download method asincronusly otherwise it wouldn't work, interaction with filesystem and network couldn't be done in the main thread
Edit2:
AsyncTask should be something like this
private class DownloadTask extends AsyncTask<String, Integer, String> {
private Context context;
public DownloadTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
// download the file
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/file_name.extension");//put here your path and your mkdirs
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return null;
}
#Override
protected void onPostExecute(String result) {
if (result != null)
Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
else
Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
}
}
And you shoould call it like this
DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");
You could also have a look at this answer
You can see that I'm appending tvStatus (TextView) in onPostExecute and after remove my progressDialog box. When I debug my code I can see that the value is set in tvStatus but it doesn't show on the screen.
Also my progressDialog stops rotating after the onPostExecute function is called.
Does any one know why and how to solve?
This is set in the onCreate method:
tvStatus = (TextView) this.findViewById(R.id.tvStatus);
Code:
public class TcpTask extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
try {
//set up a Connection
Socket s = new Socket("88.26.249.133", TCP_SERVER_PORT);
InputStream inputstream = (s.getInputStream());
DataInputStream in = new DataInputStream(inputstream);
DataOutputStream out = new DataOutputStream(s.getOutputStream());
s.setSoTimeout(20*1000);
//prepare output message
outBuffer[0] = 48;
outBuffer[1] = 51;
outBuffer[2] = 49;
outBuffer[3] = 49;
outBuffer[4] = 0;
outBuffer[5] = 0;
//send output message
out.write(outBuffer);
out.flush();
//To check in logCat
Log.i("TcpTask", "sent: " + outBuffer);
//check # available data
//and use it as byte length
avail = in.available();
byte[] inBuffer = new byte[avail];
//accept server response
while ((nob = in.read(inBuffer)) != -1) {
}
//close stream
in.close();
for (int i = 7; i < avail-7; i += 2) {
lowByte = inBuffer[i];
highByte = inBuffer[i+1];
if (lowByte < 0) {
result = lowByte + 256 + (highByte * 256);
} else {
result = lowByte + (highByte * 256);
}
}
//close connection
s.close();
//To Check in logCat
Log.i("TcpTask", "received: " + inBuffer);
// if the host name could not be resolved into an IP address.
} catch (UnknownHostException e) {
e.printStackTrace();
Log.i("myStatus", "TcpClient: Host name could not be resolved");
// if an error occurs while creating the socket.
} catch (IOException e) {
e.printStackTrace();
Log.i("myStatus", "TcpClient: ERROR");
} finally {
Log.i("TcpTask", "TCPClient: Finished");
}
return result;
}
#Override
protected void onPostExecute(Integer result) {
tvStatus.append(Integer.toString(result) + System.getProperty("line.separator"));
if (myStatus.this.progDialog != null) {
myStatus.this.progDialog.dismiss();
}
}
}
tvStatus.setText(tvStatus.getText().toString+(Integer.toString(result) + System.getProperty("line.separator")));
This is how you set the Text value to the textView
use
tsStatus.setText(result+" "+ System.getProperty("line.separator");
I'm downloading a file from a server and for some reason i can't determine, the downloaded file size doesn't match the original file size. Here's my code.
private class dl extends AsyncTask<String,Integer,Void>
{
int size;
#Override
protected Void doInBackground(String... arg0) {
// TODO Auto-generated method stub
try{
URL myFileUrl = new URL("http://10.0.2.2:8080/testdlapps/chrome-beta.zip");
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setConnectTimeout(5000);
conn.connect();
InputStream is = conn.getInputStream();
size = conn.getContentLength();
Log.v("INFO---------------------", "size is " +size);
FileOutputStream fout1 = new FileOutputStream(Environment.getExternalStorageDirectory()+"/"+"xyz.zip");
BufferedOutputStream bos = new BufferedOutputStream(fout1);
byte[] b = new byte[1024]; int i=0, count=0;
while((count = is.read(b)) != -1)
{
bos.write(b,0,count);
i+=count;
publishProgress(i);
Log.v("INFO----------------------------",""+count);
}
fout1.close();
}catch(Exception e){
Log.v("INFO--------------------------","Error!!");
Log.v("INFO--------------------------",e.getMessage());
e.printStackTrace();
}
return null;
}
protected void onProgressUpdate(Integer... progress) {
tv.setText("downloaded " + progress[0] + "/" + size ); //tv is a TextView
}
}
When i run the app, after the download completes, count and size are the same but the actual file size i.e /mnt/sdcard/xyz.zip is always less than size. Any ideas what going wrong?
override onPostExecute and check if actually it finishes, perhaps here a code to download with resume support,
pay attention because if you press back the download may still run:
if (isCancelled())
return false;
in the loop is needed because the close() on the socket will hang on exit without you noticeing it
here is the code:
class DownloaderTask extends AsyncTask<String, Integer, Boolean>
{
private ProgressDialog mProgress;
private Context mContext;
private Long mFileSize;
private Long mDownloaded;
private String mDestFile;
public DownloaderTask(Context context, String path)
{
mContext = context;
mFileSize = 1L;
mDownloaded = 0L;
mDestFile = path;
}
#Override
protected void onPreExecute()
{
mProgress = new ProgressDialog(mContext);
mProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgress.setMessage("Downloading...");
mProgress.setCancelable(true);
mProgress.setCanceledOnTouchOutside(false);
mProgress.setOnCancelListener(new DialogInterface.OnCancelListener()
{
#Override
public void onCancel(DialogInterface dialog)
{
DownloaderTask.this.cancel(true);
}
});
mProgress.show();
}
#Override
protected void onProgressUpdate(Integer... percent)
{
mProgress.setProgress(percent[0]);
}
#Override
protected Boolean doInBackground(String... urls)
{
FileOutputStream fos = null;
BufferedInputStream in = null;
BufferedOutputStream out = null;
AndroidHttpClient mClient = AndroidHttpClient.newInstance("AndroidDownloader");
try
{
HttpResponse response = null;
HttpHead head = new HttpHead(urls[0]);
response = mClient.execute(head);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
return false;
Boolean resumable = response.getLastHeader("Accept-Ranges").getValue().equals("bytes");
File file = new File(mDestFile);
mFileSize = (long) Integer.parseInt(response.getLastHeader("Content-Length").getValue());
mDownloaded = file.length();
if (!resumable || (mDownloaded >= mFileSize))
{
Log.e(TAG, "Invalid size / Non resumable - removing file");
file.delete();
mDownloaded = 0L;
}
HttpGet get = new HttpGet(urls[0]);
if (mDownloaded > 0)
{
Log.i(TAG, "Resume download from " + mDownloaded);
get.setHeader("Range", "bytes=" + mDownloaded + "-");
}
response = mClient.execute(get);
if ((response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) && (response.getStatusLine().getStatusCode() != HttpStatus.SC_PARTIAL_CONTENT))
return false;
if (mDownloaded > 0)
publishProgress((int) ((mDownloaded / mFileSize) * 100));
in = new BufferedInputStream(response.getEntity().getContent());
fos = new FileOutputStream(file, true);
out = new BufferedOutputStream(fos);
byte[] buffer = new byte[8192];
int n = 0;
while ((n = in.read(buffer, 0, buffer.length)) != -1)
{
if (isCancelled())
return false;
out.write(buffer, 0, n);
mDownloaded += n;
publishProgress((int) ((mDownloaded / (float) mFileSize) * 100));
}
} catch (Exception e)
{
e.printStackTrace();
return false;
} finally
{
try
{
mClient.close();
if (in != null)
in.close();
if (out != null)
out.close();
if (fos != null)
fos.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
return true;
}
#Override
protected void onCancelled()
{
finish();
}
#Override
protected void onPostExecute(Boolean result)
{
if (mProgress.isShowing())
mProgress.dismiss();
if (result)
// done
else
// error
}
}
If it is a chunked response, the content-length in the header will be a guess at best.