I am trying to download an Image and then display it to my imageView component.
To download I have to use Asyntask and display a progress bar to inform a user. Problem is after going through a loop to get the calculated progress value I get 0 from inputStream.
Log.d("is", "" + inputStream.available()); // ---> will have a value
byte[] buffer = new byte[contentLenght];
while ((read = inputStream.read(buffer)) != -1) {
counter += read;
publishProgress(counter);
outputStream.write(buffer,0,read);
}
Log.d("is", "" + inputStream.available()); // -----> will return 0
bmp = BitmapFactory.decodeStream(inputStream); // bmp will be empty
Is there a way to get the calcuated value for progress bar and not get a 0 value at the end in input stream?
I am using Asyntask here.
Clarification
bmp will have a value and when I do this
imageView.setImageBitmap(bmp); it will work ONLY IF i remove the the loop and just call bmp = BitmapFactory.decodeStream(inputStream);
However if I put a loop before doing this
bmp = BitmapFactory.decodeStream(inputStream);
the imageView will show nothing
Here is my Full Asynctask Code Including the networking connection
int progressCounter;
int contentLenght;
int counter;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected Boolean doInBackground(String... params) {
return ConnectToInternet(params[0]);
}
#Override
protected void onPostExecute(Boolean aVoid) {
//Log.d("buff",bmp.toString());
progressBar.setVisibility(View.GONE);
imageView.setImageBitmap(bmp);
}
#Override
protected void onProgressUpdate(Integer... values) {
progressCounter =(int) (((double) values[0] / contentLenght) * 100);
progressBar.setProgress(progressCounter);
}
boolean ConnectToInternet(String url){
boolean sucessfull = false;
URL downloadURL = null;
HttpURLConnection connection = null;
InputStream inputStream = null;
try {
downloadURL = new URL(url);
connection = (HttpURLConnection) downloadURL.openConnection();
inputStream = connection.getInputStream();
contentLenght = connection.getContentLength();
Log.d("is", "" + inputStream.available());
int read = -1;
byte[] buffer = new byte[contentLenght];
while ((read = inputStream.read(buffer)) != -1) {
counter += read;
publishProgress(counter);
}
Log.d("is", "" + inputStream.available());
bmp = BitmapFactory.decodeStream(inputStream);
sucessfull = true;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
connection.disconnect();
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sucessfull;
}
thanks
The while statement is consuming the inputStream entirely, so nothing will be left for decoding in BitmapFactory.decodeStream(inputStream).
Try this:
boolean ConnectToInternet(String url){
// ...
int read;
// contentLength may be too big,
// so read stream in smaller chunks.
//
// there's a typo in contentLenght :)
byte[] buffer = new byte[4096];
// Object for storing partially downloaded image.
ByteArrayOutputStream imageBaos = new ByteArrayOutputStream();
// Initialize counter.
counter = 0;
while ((read = inputStream.read(buffer)) != -1) {
counter += read;
publishProgress(counter);
// Store downloaded chunk.
imageBaos.write(buffer, 0, read);
}
// Obtain bitmap from downloaded chunks.
bmp = BitmapFactory.decodeByteArray(imageBaos.toByteArray(), 0, imageBaos.size());
// ...
}
Related
Hi have implemented programatically downloading of file using inputstream and cipheroutputstream(for encryption). The download is happening very slow. Whereas if i try to download via download manager, it is very fast. What can i do to improve my code and increase the download speed of the file. Below is my code.
private void saveFileUsingEncryption(String aMineType, long length) throws Exception {
int bufferSize = 1024*4;
//byte[] buffer = new byte[1024];
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
long totalRead = 0;
FileOutputStream outStream = null;
File f = new File(Constants.DWLPATH);
if (!f.exists()) {
f.mkdirs();
}
try {
Cipher aes = Cipher.getInstance("ARC4");
aes.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("mykey".getBytes(), "ARC4"));
if(contDisp==null || contDisp.length()==0) {
// downloadFileName = downloadFileName.replaceAll("[^a-zA-Z0-9_]+", "");
downloadFileName = downloadFileName + "." + getFileExtension(aMineType);
}
outStream = new FileOutputStream(Constants.DWLPATH + downloadFileName,true);
CipherOutputStream out = new CipherOutputStream(outStream, aes);
while ((bytesRead = inputStream.read(buffer, 0, bufferSize)) >= 0) {
out.write(buffer, 0, bytesRead);
try{
// Adjust this value. It shouldn't be too small.
Thread.sleep(50);
}catch (InterruptedException e){
TraceUtils.logException(e);
}
totalRead += bytesRead;
sb=sb.append("\n Total bytes Read:"+totalRead);
Log.e("--",sb.toString());
/* if (this.length > 0) {
Long[] progress = new Long[5];
progress[0] = (long) ((double) totalRead / (double) this.length * 100.0);
publishProgress(progress);
}*/
if (this.isCancelled()) {
if (conn != null)
conn.disconnect();
conn = null;
break;
}
}
Log.e("Download completed","success");
out.flush();
//Utils.putDownloadLogs(requestUrl,mimeType,length, downloadFileName,"Download is Successful",sb.toString(), context);
outStream.close();
buffer = null;
} catch (Exception e) {
TraceUtils.logException( e);
file_newsize = storedFileSizeInDB + totalRead;
if (totalFileSize == 0)
totalFileSize = length;
callback.onRequestInterrupted(file_newsize,totalFileSize);
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
// Utils.putDownloadLogs(requestUrl,mimeType,length,downloadFileName,"failure---" + errors.toString(),sb.toString(), context);
throw e;
} finally {
if (outStream != null)
outStream.close();
outStream = null;
}
}
You can use default download manager to download the file because its very easy to implement and provide better features like respond to the internet connection , provide accessibility to add notification in status bar , by running the query on download manager object you can find the total bytes and remaining bytes so you can calculate the progress and after completion of download by tapping the notification one can perform the desired operation.
And also there are many libraries are available for to achieve this like
PRDOWNLOADER
FetchDownloader
This libraires provide you the feature of pause,download, resume download , tracking the progress and cancel download
Also you can customize it as per your need.
Here is the DownloadAndEncryptFileTask.class to download with encryption
public class DownloadAndEncryptFileTask extends AsyncTask<Void, Void, Void> {
private String mUrl;
private File mFile;
private Cipher mCipher;
InputStream inputStream;
FileOutputStream fileOutputStream;
CipherOutputStream cipherOutputStream;
public DownloadAndEncryptFileTask(String url, File file, Cipher cipher) {
if (url == null || url.isEmpty()) {
throw new IllegalArgumentException("You need to supply a url to a clear MP4 file to download and encrypt, or modify the code to use a local encrypted mp4");
}
mUrl = url;
mFile = file;
mCipher = cipher;
}
private void downloadAndEncrypt() throws Exception {
URL url = new URL(mUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (mFile.length() > 0) {
connection.setRequestProperty("Range", "bytes=" + mFile.length() + "-");
}
connection.connect();
Log.e("length", mFile.length() + "");
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException("server error: " + connection.getResponseCode() + ", " + connection.getResponseMessage());
}
inputStream = connection.getInputStream();
if (mFile.length() > 0) {
//connection.connect();
fileOutputStream = new FileOutputStream(mFile, true);
} else {
fileOutputStream = new FileOutputStream(mFile);
}
CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, mCipher);
byte buffer[] = new byte[1024 * 1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
Log.d(getClass().getCanonicalName(), "reading from http...");
cipherOutputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
cipherOutputStream.close();
connection.disconnect();
}
#Override
protected Void doInBackground(Void... params) {
try {
downloadAndEncrypt();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
Log.d(getClass().getCanonicalName(), "done");
}
}
Call this class
new DownloadAndEncryptFileTask(
myFeedsModel.getVideo().getVideo360(),
new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), myFeedsModel.getFile_name()),
OBJECT OF YOUR CIPHER
I want to download an image via AsyncTask and want to display it in an ImageView I am able to do it normally but I also want to show the progress to the user and do all this without having to store the file in the SDcard.
Here is what I have done so far.
class DownloadFileFromURL extends AsyncTask<String, String, String> {
/**
* Before starting background thread
* Show Progress Bar Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
showDialog(progress_bar_type);
}
/**
* Downloading file in background thread
* */
#Override
protected String doInBackground(String... f_url) {
int count;
try {
URL url = new URL(f_url[0]);
URLConnection conection = url.openConnection();
conection.connect();
// getting file length
int lenghtOfFile = conection.getContentLength();
// input stream to read file - with 8k buffer
InputStream input = new BufferedInputStream(url.openStream(), 8192);
// Output stream to write file
OutputStream output = new FileOutputStream("/sdcard/downloadedfile.jpg");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
// After this onProgressUpdate will be called
publishProgress(""+(int)((total*100)/lenghtOfFile));
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
return null;
}
/**
* Updating progress bar
* */
protected void onProgressUpdate(String... progress) {
// setting progress percentage
pDialog.setProgress(Integer.parseInt(progress[0]));
}
/**
* After completing background task
* Dismiss the progress dialog
* **/
#Override
protected void onPostExecute(String file_url) {
// dismiss the dialog after the file was downloaded
dismissDialog(progress_bar_type);
// Displaying downloaded image into image view
// Reading image path from sdcard
String imagePath = Environment.getExternalStorageDirectory().toString() + "/downloadedfile.jpg";
// setting downloaded into image view
my_image.setImageDrawable(Drawable.createFromPath(imagePath));
}
}
If you don't want to download image locally, you should use ByteArrayOutputStream instead of FileOutputStream.
And this is the key code:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
publishProgress(""+(int)((total*100)/lenghtOfFile));
outputStream.write(data, 0, count);
}
//after downloading the image
byte[] imageData = outputStream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
my_image.setImageBitmap(bitmap);
I didn't test it, but I believe this can help you.
You can use Glide instead:
Glide.with(this).load("http://server.com/image.jpg").into(imageView);
reference Best method to download image from url in Android
private Bitmap downloadBitmap(String url) {
HttpURLConnection urlConnection = null;
try {
URL uri = new URL(url);
urlConnection = (HttpURLConnection) uri.openConnection();
int statusCode = urlConnection.getResponseCode();
if (statusCode != HttpStatus.SC_OK) {
return null;
}
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
}
} catch (Exception e) {
Log.d("URLCONNECTIONERROR", e.toString());
if (urlConnection != null) {
urlConnection.disconnect();
}
Log.w("ImageDownloader", "Error downloading image from " + url);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
Hi I need to show summary progress of AsyncTask. I want to show ProgressBar or ProgressDialog of Downloading, but I have know idea what to do, I know how to show dialog, but only when I download one file, and how do when I have a lot of files to download. Can somebody help????
Here is My AyncTaskClass
public class DownloadProgramTask extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
String path = sUrl[1];
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(path);
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;
// publishing the progress....
if (fileLength > 0) // only if total length is known
publishProgress((int) (total * 100 / fileLength));
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;
}
}
And I create new instance of that class for every execute,
File voiceFile = new File(dirVoice, a.getPose_id() + ".mp3");
if (!voiceFile.exists()) {
voiceList.add(a.getVoice());
new DownloadProgramTask().execute(MYurl.BASE_URL + a.getVoice(), voiceFile.getPath());
Log.e("LINK", MYurl.BASE_URL + a.getVoice());
Log.e("Path voice", "" + voiceFile.getPath());
}
File imgLargeFile = new File(dirImageLarge, a.getId() + ".png");
if (!imgLargeFile.exists()) {
imgLargeList.add(a.getVoice());
new DownloadProgramTask().execute(MYurl.BASE_URL + "/" + a.getImgLarge(), imgLargeFile.getPath());
}
you can use the overridden method OnProgressUpdate of Async Task. call publishProgress in doingBackground of asynctask with interger
something like this..
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.i("makemachine", "onProgressUpdate(): " +
percentBar.setProgress((values[0] * 2) + "%");
}
This is my doInBackground method:
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
HttpURLConnection conection = null;
BufferedOutputStream bout = null;
FileOutputStream fos = null;
int downloaded = 0;
try {
URL url = new URL(sUrl[0]);
conection = (HttpURLConnection)url.openConnection();
int lenghtOfFile = conection.getContentLength();
if(STATUS) {
File file = new File(Environment.getExternalStorageDirectory().getPath() + "/myapp.apk");
if (file.exists()) {
downloaded = (int) file.length();
conection.setRequestProperty("Range", "bytes=" + (file.length()) + "-");
}
}
else {
conection.setRequestProperty("Range", "bytes=" + downloaded + "-");
}
conection.setDoInput(true);
conection.setDoOutput(true);
conection.connect();
input = new BufferedInputStream(url.openStream(), 8192);
fos=(downloaded==0)? new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/myapp.apk"): new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/myapp.apk",true);
bout = new BufferedOutputStream(fos, 1024);
byte data[] = new byte[1024];
long total = 0;
int count = 0;
while ((count = input.read(data, 0, 1024)) >= 0) {
if (isCancelled()) {
input.close();
return null;
}
bout.write(data, 0, count);
downloaded += count;
publishProgress((int)(downloaded * 100/ lenghtOfFile) );
total += count;
}
bout.flush();
input.close();
fos.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
if (fos != null)
fos.close();
if (bout != null)
bout.close();
} catch (IOException ignored) {
}
if (conection != null)
conection = null;
}
return null;
}
I start download task with this code (resume flag is false -> STATUS = FALSE):
dt = new DownloadTask(DownloadsActivity.this, false);
dt.execute("myurl.something.apk");
then when downloaded completely I launch apk file and all thing work correctly and apk installed correctly. But when pause my download with this code:
dt.cancel(true);
and then resume it with this code (resume flag is true-> STATUS = TRUE):
dt = new DownloadTask(DownloadsActivity.this, true);
dt.execute("myurl.something.apk");
This time apk size is equal to last downloaded before pause + apk total size, therefore my apk file is corrupted. Which means connection.setRequestProperty() not working for me. What is my code problem? Thanks in advance.
i have a following code to download an image , show a progress bar and return its bitmap. but the bitmap always returns null.. once i remove the while loop, the bitmap has value, but i dont get a progress bar.
#Override
protected Bitmap doInBackground(String... params) {
bitmap = null;
try {
URL url = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
connection.connect();
int lenghtOfFile = connection.getContentLength();
InputStream input = connection.getInputStream();
OutputStream output = new FileOutputStream(Environment
.getExternalStorageDirectory().toString()
+ "/DCIM/downloadedfile.jpg");
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
publishProgress((int) ((total * 100) / lenghtOfFile));
output.write(data, 0, count);
}
Bitmap bitmap = BitmapFactory.decodeStream(input);
return bitmap;
} catch (IOException e) {
Log.e("could not load ", e.getMessage());
e.printStackTrace();
return null;
}
}
protected void onProgressUpdate(Integer... progress) {
pDialog.setProgress(progress[0]);
}
public void onPostExecute(Bitmap result) {
pDialog.dismiss();
listener.onTaskCompleted(result);
}
enter code here
an InputStream can only read one time. you need to change your code to :
while ((count = input.read(data)) != -1) {
total += count;
publishProgress((int) ((total * 100) / lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
String pathName=Environment
.getExternalStorageDirectory().toString()
+ "/DCIM/downloadedfile.jpg";
Bitmap bitmap = BitmapFactory.decodeFile(pathName);
you don't need interface because asynctask can return bitmap.
private class DownloadFilesTask extends AsyncTask<String, Integer, Bitmap> {
protected Bitmap doInBackground(String... params) {
return downloadBitmap();
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
}
When you call task you must use get();
Bitmap bitmap = new DownloadFileTask().execute().get();