I am using a service to download files and extract them if they are archived.
The extraction method is wrapped as a asynctask to improve performance of the extraction process.
My problem is that when I run the app on the virtual device, all is fine and the extraction process is really fast but as soon as I test it on a real device (Nexus 9 tablet, Android 6x) the extraction process is really slow and takes minutes to complete.
Is there anything I can do, to speed up the extraction process?
I execute the asynctask with: new UnRarTask(targetAppName).execute();
Below the piece of code which is relevant:
public class DownloadTask implements Runnable {
private DownloadService service;
private DownloadManager downloadManager;
protected void init(DownloadService service, Intent intent) {
this.service = service;
downloadManager = (DownloadManager) MyApp_.getInstance().
getSystemService(Activity.DOWNLOAD_SERVICE);
DownloadRequest downloadRequest = intent.getParcelableExtra(DownloadService
.DOWNLOAD_REQUEST);
}
private class UnRarTask extends AsyncTask<Void, Integer, String> {
String rarPath = null;
int countRar = 0;
long copiedbytes = 0, totalbytes = 0;
Archive archive = null;
FileHeader fileHeader = null;
File archiveFile;
List<FileHeader> headers;
UnRarTask(String one) {
this.archiveFile = new File(one);
}
#Override
protected String doInBackground(Void... params) {
try {
archive = new Archive(new FileVolumeManager(archiveFile));
} catch (RarException | IOException e) {
e.printStackTrace();
}
String fileName = archiveFile.getName();
String absolutePath = archiveFile.getAbsolutePath();
String archiveDirectoryFileName = absolutePath.substring(0, absolutePath.indexOf(fileName));
if (archive != null) {
fileHeader = archive.nextFileHeader();
headers = archive.getFileHeaders();
for (FileHeader fh : headers) {
totalbytes = totalbytes + fh.getFullUnpackSize();
}
}
while (fileHeader != null) {
BufferedInputStream inputStream;
try {
inputStream = new BufferedInputStream(archive.getInputStream(fileHeader));
String extractedFileName = fileHeader.getFileNameString().trim();
String fullExtractedFileName = archiveDirectoryFileName + extractedFileName;
File extractedFile = new File(fullExtractedFileName);
FileOutputStream fileOutputStream = new FileOutputStream(extractedFile);
BufferedOutputStream flout = new BufferedOutputStream(fileOutputStream, BUFFER_SIZE);
if (extractedFile.getName().toLowerCase().endsWith(".mp3")
|| extractedFile.getName().toLowerCase().endsWith(".epub")
|| extractedFile.getName().toLowerCase().endsWith(".pdf")
|| extractedFile.getName().toLowerCase().endsWith(".mobi")
|| extractedFile.getName().toLowerCase().endsWith(".azw3")
|| extractedFile.getName().toLowerCase().endsWith(".m4b")
|| extractedFile.getName().toLowerCase().endsWith(".apk")) {
rarPath = extractedFile.getPath();
countRar++;
}
int len;
byte buf[] = new byte[BUFFER_SIZE];
while ((len = inputStream.read(buf)) > 0) {
//fileOutputStream.write(buf, 0, len);
copiedbytes = copiedbytes + len;
int progress = (int) ((copiedbytes / (float) totalbytes) * 100);
if (progress > lastProgress) {
lastProgress = progress;
service.showUpdateProgressNotification(downloadId, appName, progress,
"Extracting rar archive: " + lastProgress + " % completed", downloadStart);
}
}
archive.extractFile(fileHeader, flout);
flout.flush();
flout.close();
fileOutputStream.flush();
fileOutputStream.close();
inputStream.close();
fileHeader = archive.nextFileHeader();
} catch (RarException | IOException e) {
e.printStackTrace();
}
}
if (countRar == 0) {
filePath = "Error";
broadcastFailed();
}
if (copiedbytes == totalbytes) {
if (archive != null)
archive.close();
}
return null;
}
}
}
I am trying to cancel downloading task with id.
I get id from
DownloadManager manager = (DownloadManager) getApplicationContext().getSystemService(Context.DOWNLOAD_SERVICE);
downloadId = manager.enqueue(req);
I want to stop download when on user button click, but I tested to stop download after 10% of being downloaded in this test code.
the code "manager.remove(downloadId);" is working perfect to clear downloading noti and stopping the task with requested ID. But it also stop the app too, app error also occur after that code. please how can I solve the problem.
new Thread(new Runnable() {
#Override
public void run() {
boolean downloading = true;
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
cursor = manager.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
final int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
}
final int dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);
String finalDl_size;
int dl_size = (int) (bytes_total/(1024*1024));
finalDl_size = Integer.toString(dl_size)+" MB";
if(dl_size>1000){dl_size=(int) (bytes_total/(1024*1024*1024));
finalDl_size = Integer.toString(dl_size)+" GB";}
final String finalDl_size1 = finalDl_size;
runOnUiThread(new Runnable() {
#Override
public void run() {
btndownload.setText("Downloading "+Integer.toString(dl_progress)+"% , "+ finalDl_size1);
if(dl_progress==100){
btndownload.setBackgroundColor(Color.GREEN);
btndownload.setText("Download Completed");
}
else if(dl_progress>10){
try{
manager.remove(downloadId); ///// Stop after 10%
}
catch (Exception e){}
}
}
});
cursor.close();
}
}
}).start();
Logcat Output
Please Kindly help me. Thank you in advance.
Try this
if (cursor.getCount() > 0)
manager.remove(downloadId); ///// Stop after 10%
I try to perform downloading the file using DownloadManager. Everything works fine except LG devices. Here is my code:
private void downloadFile(FileInfo fileInfo) {
private DownloadManager manager = (DownloadManager) MyApp.getSingleton().
getApplicationContext().getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse("https://"
+ MyPreference.getInstance().getBaseUrl()
+ "/api/v3/files/"
+ fileId
+ "/get"));
request.setDescription(MyApp.getSingleton().getApplicationContext().getString(R.string.downloading));
request.setTitle(fileInfo.getmName());
request.addRequestHeader("Authorization", "Bearer " + MyPreference.getInstance().getAuthToken());
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
File dir = new File(FileUtil.getInstance().getDownloadedFilesDir());
if(!dir.exists()){
dir.mkdirs();
}
request.setDestinationUri(Uri.fromFile(new File(FileUtil.getInstance().getDownloadedFilesDir() + File.separator + fileInfo.getmName())));
downloadId = manager.enqueue(request);
new Thread(() -> {
boolean downloading = true;
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
Cursor cursor = manager.query(q);
cursor.moveToFirst();
int bytes_downloaded = 0;
long bytes_total = 0;
try {
bytes_downloaded = cursor.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
bytes_total = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
} catch (CursorIndexOutOfBoundsException e) {
e.printStackTrace();
cursor.close();
break;
} catch (IllegalArgumentException e){
e.printStackTrace();
cursor.close();
break;
}
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_FAILED) {
downloading = false;
cursor.close();
onDownloadFail();
break;
} else if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
cursor.close();
break;
}
if (bytes_total > 0) {
final int dl_progress = (int) ((bytes_downloaded * 100L) / bytes_total);
onProgress(dl_progress);
}
cursor.close();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
On LG devices line
bytes_total = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
returns -1.
Download notification appears in notification bar and disappears immediately after few milliseconds. No one exception, no one enter this code section
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_FAILED) {
downloading = false;
cursor.close();
onDownloadFail();
break;
}
else if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
cursor.close();
break;
}
Just nothing. So internal while() cycle work forever.
Tested on devices LG D802 and LG G3 S. Both devices show the same behavior.
I faced the same issue and found the solution for this. You need to make sure all the directories exists before init Download Manager.
Example: in my case the path to my File is
/storage/emulated/0/MyFolder/n.jpeg
so I have to make sure MyFolder directory exists before init Download Manager.
I'm trying to show the download progress of DownloadManager in percentage as shown in the notification bar.
I've read up some answer here.
However, the method provided is using the Thread.
As my understanding,Thread is not a good way.
Is there any alternative way to do the same thing?
Or using Thread is just fine in this case?
Edit 1:
Added in the code in my project.
new Thread(new Runnable() {
#Override
public void run() {
boolean downloading = true;
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
Cursor cursor = downloadManager.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
}
final int dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);
((Activity) mContext).runOnUiThread(new Runnable() {
#Override
public void run() {
holder.mTextView.setText(String.valueOf(dl_progress) + "%");
}
});
cursor.close();
}
}
}).start();
I am using .net web services and I am able to download the file in sd card, But I want to show progress bar when particular file start download and complete and then I want to show options like view and cancel.
Click event Class:
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
LazyAdapter ca = (LazyAdapter)parent.getAdapter();
FolderList item_name = (FolderList)ca.getItem(position);
FolderList DocumentID = (FolderList)ca.getItem(position);
FolderList type = (FolderList)ca.getItem(position);
Intent mIntent = new Intent();
mIntent.putExtra("item_name", item_name.folder_name);
mIntent.putExtra("item_id", DocumentID.ID);
mIntent.putExtra("item_type", type.type);
mIntent.getStringExtra("item_name");
String Type = mIntent.getStringExtra("item_type");
Log.i("Type", Type);
if {
// Some code here...
} else {
Intent i = new Intent(getApplicationContext(), Display_image.class);
i.putExtra("item_name", item_name.folder_name);
i.putExtra("ID", DocumentID.ID);
i.putExtra("item_type", type.type);
i.putExtra("User_ID",User_ID);
i.getStringExtra("item_name");
Id = i.getStringExtra("ID");
i.getStringExtra("item_type");
startActivity(i);
}
}
My Code: I want to use download manager
SoapPrimitive DocumentResponse = (SoapPrimitive)Envelope.getResponse();
Log.i("DocumentResponse", DocumentResponse.toString());
String DocAsString = DocumentResponse.toString();
byte[] decodedString = Base64.decode(DocAsString, Base64.DEFAULT);
File direct = new File(Environment.getExternalStorageDirectory() + "/MyFolder");
if(!direct.exists())
{
direct.mkdir();
}
File photo = new File(Environment.getExternalStorageDirectory() + "/MyFolder", Name);
if (photo.exists())
{
photo.delete();
}
try {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(Name));
request.setDescription("Have Fun ;)");
request.setTitle("Downloading...");
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
FileOutputStream fos=new FileOutputStream(photo.getPath());
fos.write(decodedString);
fos.close();
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
ContentValues values= new ContentValues();
System.out.println(values);
}
catch (java.io.IOException e)
{
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
Please suggest how to use download manager into it??? thanks
You could use a ProgressBar to accomplish this.
First, add a progressbar to your interface like this:
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#android:style/Widget.ProgressBar.Small"/>
Then in your code update your method like this:
protected ProgressBar mProgressBar;
protected long downloadId;
protected DownloadManager manager;
public void startdownload() {
//<SET UP DOWNLOAD MANAGER HERE>
downloadId = manager.enqueue(request);
mProgressBar = findViewById(R.id.progress_bar);
Timer myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
Cursor cursor = manager.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
cursor.close();
int dl_progress = (bytesDownloaded * 1f / bytesTotal) * 100;
runOnUiThread(new Runnable(){
#Override
public void run(){
mProgressbar.setProgress((int) dl_progress);
}
});
}
}, 0, 10);
}
Use Follow Method
private NotificationManager mNotifyManager;
case R.id.btnSubmit:
mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(context);
mBuilder.setContentTitle("BuyMixTapes")
.setContentText("Download in progress")
.setSmallIcon(R.drawable.appiconmain);
new DownloadFile().execute(vv);
public class DownloadFile extends AsyncTask<String, String, String> {
/**
* Before starting background thread
* Show Progress Bar Dialog
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
//context.showDialog(progress_bar_type);
mBuilder.setProgress(100, 0, false);
mNotifyManager.notify(id, mBuilder.build());
}
protected String doInBackground(String... f_url) {
int count;
try {
for (int i = 0; i < f_url.length; i++) {
Log.e("0url",""+f_url[0]);
Log.e("1url",""+f_url[1]);
// Log.e("1url",""+f_url[1]);
URL url = new URL(f_url[i]);
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/"+f_url[i]);
OutputStream output = new FileOutputStream(
"/sdcard/" +i + "buymix.mp3");
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
*/
/**
* After completing background task
* Dismiss the progress dialog
**/
#Override
protected void onProgressUpdate(String... values) {
// Update progress
mBuilder.setProgress(100, Integer.parseInt(values[0]), false);
mNotifyManager.notify(id, mBuilder.build());
super.onProgressUpdate(values);
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
mBuilder.setContentText("Download complete");
// Removes the progress bar
String imagePath = Environment.getExternalStorageDirectory()
.toString() + "/downloaded.mp3";
mBuilder.setProgress(0, 0, false);
mNotifyManager.notify(id, mBuilder.build());
}
}
Update 2021:
Add a ProgressBar in your layout (TextView is just for showing more information):
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/progressBar"
android:text="Hello World!" />
Then before onCreate:
DownloadManager downloadManager;
long downloadReference;
TextView text1;
ProgressBar progressBar;
Timer progressTimer;
Afterwards, in onCreate:
text1 = (TextView) findViewById(R.id.textView1);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
Then after setting up download manager:
// <Some codes which setup download manager>
downloadReference = downloadManager.enqueue(request); // enqueue a new download
// update progressbar
progressTimer = new Timer();
progressTimer.schedule(new TimerTask() {
#Override
public void run() {
DownloadManager.Query downloadQuery = new DownloadManager.Query();
downloadQuery.setFilterById(downloadReference);
Cursor cursor = downloadManager.query(downloadQuery);
if (cursor.moveToFirst()) { // this "if" is crucial to prevent a kind of error
final int downloadedBytes = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
final int totalBytes = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); // integer is enough for files under 2GB
cursor.close();
final float downloadProgress = downloadedBytes * 100f / totalBytes;
if(downloadProgress > 99.9) // stop repeating timer (it's also useful for error prevention)
progressTimer.cancel();
runOnUiThread(new Runnable() {
#Override
public void run() {
text1.setText(downloadedBytes + "\n" + totalBytes + "\n" + downloadProgress + "%");
progressBar.setProgress((int) downloadProgress);
}
});
}
}
}, 0, 1000);
Some tips:
If your file is larger than 2GB, you should use another type instead of int such as double etc.
You can stop timer somewhere else for example, in BroadcastReceiver if you have.
Task executions is every 1000 milliseconds (every 1 second) which is obviously changable.