I have been trying to download videos from a url, I have implemented my downloading method in the doInBackground() of asynctask, but the doInBackground method is taking a lot of time to get called(5-10 mins), I am using another asyntask to download image in the activity from which I am directed to download video activity and its working fine. My onPreExecute method is being called on time, but after that doInBackground takes almost 5-7 minutes to start. I will be really grateful for any help provided.
Here is mycode
btnDownloadLQ.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0)
{
try
{
new DownloadVideoTask().execute(videoURL);
}
catch(Exception e)
{
Log.e("Vidit_TAG","I got an error",e);
}
}
});
private class DownloadVideoTask extends AsyncTask<String, String, String>
{
#SuppressWarnings("deprecation")
#Override
protected void onPreExecute() {
super.onPreExecute();
showDialog(DIALOG_DOWNLOAD_PROGRESS);
}
protected String doInBackground(String... urls)
{
int i=0;
try
{
URL url = new URL (urls[0]);
InputStream input = url.openStream();
try {
//The sdcard directory e.g. '/sdcard' can be used directly, or
//more safely abstracted with getExternalStorageDirectory()
String root = Environment.getExternalStorageDirectory().toString();
File storagePath = new File(root + "/vidit");
storagePath.mkdirs();
OutputStream output = new FileOutputStream (new File(storagePath,title+".mp4"));
try
{
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0)
{
output.write(buffer, 0, bytesRead);
}
}
catch(Exception e)
{
Log.e("Vidit_TAG","I got an error",e);
}
finally
{
output.close();
}
}
catch(Exception e)
{
Log.e("Vidit_TAG","I got an error",e);
}
finally
{
input.close();
//tvTitle.setText("Completed");
}
}
catch(Exception e)
{
Log.e("Vidit_TAG","I got an error",e);
}
return null;
}
#SuppressWarnings("deprecation")
#Override
protected void onPostExecute(String unused)
{
dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
alertbox(title);
}
}
make sure no other asyncTasks are running , by cancelling them if needed.
on most android versions , asyncTask runs on a single background thread , and should only run small tasks .
in case the task might take too long (or there are multiple tasks) , consider cancelling them or use an alternative approach (like using executeOnExecutor as described on the API ) .
Late Answer but surely helps
If you are using min API level >=11 try this
//new YourAsyncTask().execute(); -- replace this with following line
new YourAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //use this
I'm facing the same issue in spite of it didnot happen every time.
You could use the tradtional Thread for an alternative and handle the UI changes yourself
Related
My app is depends on PDF files which I download it from URL and unzip it, which works fine.
but it re-download the file.zip every time I open it even if the file is downloaded and existed.
the file size is too big so it make much trouble and hard to use.
I hope you can help
thanks alot
public class MainActivity extends Activity {
String Url="www....zip";
String unzipLocation = Environment.getExternalStorageDirectory() + "/unzipFolder/";
String StorezipFileLocation =Environment.getExternalStorageDirectory() + "/DownloadedZip";
String DirectoryName=Environment.getExternalStorageDirectory() + "/unzipFolder/files/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadZipfile mew = new DownloadZipfile();
mew.execute(Url);
class DownloadZipfile extends AsyncTask<String, String, String>
{
String result ="";
#Override
protected void onPreExecute()
{
super.onPreExecute();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setMessage("Downloading ... ");
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
#Override
protected String doInBackground(String... aurl)
{
int count;
try
{
URL url = new URL(aurl[0]);
URLConnection conexion = url.openConnection();
conexion.connect();
int lenghtOfFile = conexion.getContentLength();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(StorezipFileLocation);
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.close();
input.close();
result = "true";
}
catch (Exception e) {
result = "false"; }
return null;
}
protected void onProgressUpdate(String... progress)
{
Log.d("ANDRO_ASYNC",progress[0]);
mProgressDialog.setProgress(Integer.parseInt(progress[0]));
}
#Override
protected void onPostExecute(String unused)
{
mProgressDialog.dismiss();
if(result.equalsIgnoreCase("true"))
{
try
{
unzip();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
}
}
}
Well, onCreate() is called every time the activity is created, which happens every time you open it. You'll have to set a variable or save in a SharedPreference object whether the app should download or not. For example you could add a field boolean isDownloaded = false and just set that to true once the download has finished from within the AsyncTask.
Alternatively you can check whether the file you want to save already exists, meaning you have already saved it there before (if((new File(path)).exists())) {...}). However, if the download has resulted in a corrupt file, you will always keep this corrupt file if you don't take care of the issue otherwise because doing it like this will not guarantee that the download has completed successfully.
The other option I mentioned would mean to get your default SharedPreferences by calling PreferenceManager.getDefaultSharedPreferences(this) and using this to set and get a boolean field which tells you whether the pdf is downloaded.
The advantage with the second method is that the app will remember whether the file is downloaded even after a reboot or after completely unloading the app from memory.
Check is file exist
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try
{
File file = new File(StorezipFileLocation);
if ( ! file.exists())
{
DownloadZipfile mew = new DownloadZipfile();
mew.execute(Url);
}
}
catch (FileNotFoundException fnfe1)
{
}
The solution is by checking if the file exists .. File(path)
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File f = new File(Environment.getExternalStorageDirectory()+"/unzipFolder/files/");
if(f.exists() == false)
{
DownloadZipfile mew = new DownloadZipfile();
mew.execute(Url);
}
}
thanks to everyone who helped or try to..
In the following code I want don't save incomplete file and delete it, if download was cancelled (e.g. press back or close app).
How can I do it?
This is part of my code:
class DownloadFileFromURL extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
showDialog(progress_bar_type);
}
#Override
protected String doInBackground(String... f_url) {
int count;
try {
URL url = new URL(f_url[0]);
URLConnection conection = url.openConnection();
conection.connect();
int lenghtOfFile = conection.getContentLength();
InputStream input = new BufferedInputStream(url.openStream(), 8192);
OutputStream output = new FileOutputStream("/sdcard/EBKH/samat.mp3");
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) {
Log.e("Error: ", e.getMessage());
}
return null;
}
protected void onProgressUpdate(String... progress) {
pDialog.setProgress(Integer.parseInt(progress[0]));
}
#Override
protected void onPostExecute(String file_url) {
dismissDialog(progress_bar_type);
}
}
Note that, if all is well, an AsyncTask does not get cancelled when a user presses a back button. If I remember correctly, it also does not get cancelled automatically if the activity is destroyed, but only gets cancelled when cancel() is called on the task.
If you want to delete your file if the cancel was called, please don't add unnecessary logic, just override AsyncTask.onCancelled():
#Override
protected void onCancelled(Object Result) {
// If the background task was cancelled, delete the mp3
File file= new File("/sdcard/EBKH/samat.mp3");
file.delete();
}
#Override
protected void onCancelled() {
// Implement this one if you also support API levels lower than 11
}
You could add a isCanceled flag that you will check every time you write to the file :
while ((count = input.read(data)) != -1 && isCanceled)
Also add a :
catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
finaly{
if(isCanceled)
{
// delete file code here
}
}
You will set this flag to true when you want/need to cancel.
set global Boolean flag boolean downloadComplete = false;and in onPostExecute change it to downloadComplete = true;
and overrideonDestroy()method.
then check flag inonDestroy()` whether file is download or not
if(!downloadComplete)
{
//then delete file
}
and when you cancel the download then onPostExecute() will not be called so your flag value remain false
Write below code
#Override
public void onBackPressed() {
super.onBackPressed();
if(DownloadFileFromURL!=null){
if(DownloadFileFromURL.getStatus()==Status.RUNNING||DownloadFileFromURL.getStatus()==Status.PENDING){
DownloadFileFromURL.cancel(true);
DownloadFileFromURL=null;
File file= new File("/sdcard/EBKH/samat.mp3");
file.delete();
}
}
}
In a ListView of sound files in a folder I want to show the length in seconds of the files. The steps that I take:
First I create an ArrayList for the instances of the soundFiles.
Then in a for loop I add the data to the instance by soundFile.setLength(calculateLength(file[i])).
After this I initiate my CustomArrayAdapter and I apply it to my listView.
In my CustomArrayAdapter I apply it: tvFileLength.setText(soundFile.getLength()); (whith a holder though..)
But since I am doing this, my app is slower than a turtle! (having 400 files)
Is there any way I can fix this speed?
private int calculateLength(File yourFile)
throws IllegalArgumentException, IllegalStateException, IOException {
MediaPlayer mp = new MediaPlayer();
FileInputStream fs;
FileDescriptor fd;
fs = new FileInputStream(yourFile);
fd = fs.getFD();
mp.setDataSource(fd);
mp.prepare();
int length = mp.getDuration();
length = length / 1000;
mp.release();
return length;
}
**EDIT**
New code I am having:
Activity
myList = new ArrayList<RecordedFile>();
File directory = Environment.getExternalStorageDirectory();
file = new File(directory + "/test/");
File list[] = file.listFiles();
for (int i = 0; i < list.length; i++) {
if (checkExtension(list[i].getName()) == true) {
RecordedFile q = new RecordedFile();
q.setTitle(list[i].getName());
q.setFileSize(readableFileSize(list[i].length()));
//above is the size in kB, is something else but I
//also might move this to the AsyncTask!
myList.add(q);
}
}
new GetAudioFilesLength(myList).execute();
AsyncTask
List<RecordedFile> mFiles = new ArrayList<RecordedFile>();
public GetAudioFilesLength(List<RecordedFile> theFiles) {
mFiles = theFiles;
}
#Override
protected String doInBackground(Void... params) {
File directory = Environment.getExternalStorageDirectory();
// File file = new File(directory + "/test/");
String mid = "/test/";
for (RecordedFile fileIn : mFiles) {
File file = new File(directory + mid + fileIn.getTitle());
try {
int length = readableFileLengthSeconds(file);
fileIn.setFileLengthSeconds(length);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Do something with the length
// You might want to update the UI with the length of this file
// with onProgressUpdate so that you display the length of the files
// in real time as you process them.
}
return mid;
}
#Override
protected void onProgressUpdate(Void... values) {
}
#Override
protected void onPostExecute(String result) {
// Update the UI in any way you want. You might want
// to store the file lengths somewhere and then update the UI
// with them here
}
/*
* #Override protected void onPreExecute() { }
*/
public int readableFileLengthSeconds(File yourFile)
throws IllegalArgumentException, IllegalStateException, IOException {
MediaPlayer mp = new MediaPlayer();
FileInputStream fs;
FileDescriptor fd;
fs = new FileInputStream(yourFile);
fd = fs.getFD();
mp.setDataSource(fd);
mp.prepare(); // might be optional
int length = mp.getDuration();
length = length / 1000;
mp.release();
return length;
}
Awesome, it works partly, but! I got 2 remaining questions:
Does this looks ok and efficient?
It works for lets say the first 100 elements in my listview, after that it displays 0 s, it has something to do with onProgressUpdate I assume, but I am not sure how I can make this work.
Reading the files in so that MediaPlayer can find the duration is clearly taking some time. Since you are running this on the UI thread, that's going to slow down the entire application.
I don't have any suggestions for how to speed up the process, but you can make your application behave much more smoothly if you do this work in a background thread with AsyncTask. That might look something like this:
private class GetAudioFilesLength extends AsyncTask<Void, Void, Void> {
List<File> mFiles = new ArrayList<File>();
public GetAudioFilesLength(List<File> theFiles){
mFiles = theFiles;
}
#Override
protected String doInBackground(String... params) {
for(File file : mFiles){
int length = calculateLength(file);
// Do something with the length
// You might want to update the UI with the length of this file
// with onProgressUpdate so that you display the length of the files
// in real time as you process them.
}
}
#Override
protected void onPostExecute(String result) {
// Update the UI in any way you want. You might want
// to store the file lengths somewhere and then update the UI
// with them here
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
When you want to start the processing, just call new GetAudioFilesLength(files).execute()
Edit to answer additional questions:
It looks as efficient as your original code. The difference now is that the user will still be able to interact with your application because the work will be done in the background thread. It is possible that there is a more efficient way to read in the length of an audio file, but I don't know what that is. If you knew the sample rate and encoding, I can imagine you could write code that would calculate the length of the audio without loading it into MediaPlayer, which takes longer. Again, though, someone else would have to help with that.
I'm not sure I understand what the problem is, but I think you are asking how to use onProgressUpdate to update the UI and add the lengths to a ListView?
You could change the middle argument to the AsyncTask generation to be a String (or something else) AsyncTask<Void, String, Void>, that tells onProgressUpdate what you will be passing to it. You can then callpublishProgress` from doInBackground to update the UI accordingly.
#Override
protected String doInBackground(Void... params) {
for(File file : mFiles){
int length = calculateLength(file);
// Do something with the length
// You might want to update the UI with the length of this file
// with onProgressUpdate so that you display the length of the files
// in real time as you process them.
publishProgress("The length of " + file.getName() + " is: " + length);
}
}
#Override
protected void onPostExecute(Void result) {
// Update the UI in any way you want. You might want
// to store the file lengths somewhere and then update the UI
// with them here
}
#Override
protected void onProgressUpdate(String... values) {
// You'll have to implement whatever you'd like to do with this string on the UI
doSomethingWithListView(values[0]);
}
I am writing this application where I get live images from a tcp connection and I need to display them on an ImageViev.
What I am doing is calling the asynctask inside the button click. but it seem to create a number of background threads.
this is the code for the button click event
btnLive.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try
{
String name = ((Button)v).getText().toString();
if(name.equalsIgnoreCase("Live"))
{
DataOutputStream dos;
DataInputStream dis;
String reply;
if(config.conn.isConnected())
{
dos = new DataOutputStream(config.conn.getOutputStream());
dos.writeBytes("STREAM-LIVE-IMAGES");
dos.flush();
//dis = new DataInputStream(in);
in = config.conn.getInputStream();
while (true)
{
new myTask().execute(in);
}
}
}
}
catch(Exception ex)
{
Log.d("Live Button ", "Exception " + ex.getMessage() );
}
}
});
and this the code for the asyncTask
class myTask extends AsyncTask<InputStream, Integer, Bitmap> {
protected Bitmap doInBackground(InputStream...in)
{
Bitmap bmp = null;
try
{
//Do some none UI stuff here and return a value *result
byte[] rcvPacket = ReadJpegBinaryAndRemoveDelimiter(in[0]);
bmp = BitmapFactory.decodeByteArray(rcvPacket, 0, rcvPacket.length);
Log.d("Live Image Streaming ", "Recieved Images: " + rcvPacket.length + " " + bmp);
} catch (Exception e) {
e.printStackTrace();
}
return bmp;
}
while (true) {
new myTask().execute(in);
}
because you are executing AsyncTask in loop, in your case in infinite loop, it's not sounds very well, you need to change it.
You need to execute in outside of loop. You shouldn't, musn't do it.
Just call
new myTask().execute(in);
without loop.
I managed to sort it out with a background thread because asynctask wasnt the right option for my issue.
So I created a separate background thread and used a post runnable method on the imageview to update the UI.
I am running remote audio-file-fetching and audio file playback operations in a background thread using AsyncTask. A Cancellable progress bar is shown for the time the fetch operation runs.
I want to cancel/abort the AsyncTask run when the user cancels (decides against) the operation. What is the ideal way to handle such a case?
Just discovered that AlertDialogs's boolean cancel(...); I've been using everywhere actually does nothing. Great.
So...
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
private final ProgressDialog progressDialog;
public MyTask(Context ctx) {
progressDialog = gimmeOne(ctx);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true);
}
});
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
while (running) {
// does the hard work
}
return null;
}
// ...
}
If you're doing computations:
You have to check isCancelled() periodically.
If you're doing a HTTP request:
Save the instance of your HttpGet or HttpPost somewhere (eg. a public field).
After calling cancel, call request.abort(). This will cause IOException be thrown inside your doInBackground.
In my case, I had a connector class which I used in various AsyncTasks. To keep it simple, I added a new abortAllRequests method to that class and called this method directly after calling cancel.
The thing is that AsyncTask.cancel() call only calls the onCancel function in your task. This is where you want to handle the cancel request.
Here is a small task I use to trigger an update method
private class UpdateTask extends AsyncTask<Void, Void, Void> {
private boolean running = true;
#Override
protected void onCancelled() {
running = false;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
onUpdate();
}
#Override
protected Void doInBackground(Void... params) {
while(running) {
publishProgress();
}
return null;
}
}
Simple: don't use an AsyncTask. AsyncTask is designed for short operations that end quickly (tens of seconds) and therefore do not need to be canceled. "Audio file playback" does not qualify. You don't even need a background thread for ordinary audio file playback.
The only way to do it is by checking the value of the isCancelled() method and stopping playback when it returns true.
This is how I write my AsyncTask
the key point is add Thread.sleep(1);
#Override protected Integer doInBackground(String... params) {
Log.d(TAG, PRE + "url:" + params[0]);
Log.d(TAG, PRE + "file name:" + params[1]);
downloadPath = params[1];
int returnCode = SUCCESS;
FileOutputStream fos = null;
try {
URL url = new URL(params[0]);
File file = new File(params[1]);
fos = new FileOutputStream(file);
long startTime = System.currentTimeMillis();
URLConnection ucon = url.openConnection();
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
byte[] data = new byte[10240];
int nFinishSize = 0;
while( bis.read(data, 0, 10240) != -1){
fos.write(data, 0, 10240);
nFinishSize += 10240;
**Thread.sleep( 1 ); // this make cancel method work**
this.publishProgress(nFinishSize);
}
data = null;
Log.d(TAG, "download ready in"
+ ((System.currentTimeMillis() - startTime) / 1000)
+ " sec");
} catch (IOException e) {
Log.d(TAG, PRE + "Error: " + e);
returnCode = FAIL;
} catch (Exception e){
e.printStackTrace();
} finally{
try {
if(fos != null)
fos.close();
} catch (IOException e) {
Log.d(TAG, PRE + "Error: " + e);
e.printStackTrace();
}
}
return returnCode;
}
Our global AsyncTask class variable
LongOperation LongOperationOdeme = new LongOperation();
And KEYCODE_BACK action which interrupt AsyncTask
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
LongOperationOdeme.cancel(true);
}
return super.onKeyDown(keyCode, event);
}
It works for me.
I don't like to force interrupt my async tasks with cancel(true) unnecessarily because they may have resources to be freed, such as closing sockets or file streams, writing data to the local database etc. On the other hand, I have faced situations in which the async task refuses to finish itself part of the time, for example sometimes when the main activity is being closed and I request the async task to finish from inside the activity's onPause() method. So it's not a matter of simply calling running = false. I have to go for a mixed solution: both call running = false, then giving the async task a few milliseconds to finish, and then call either cancel(false) or cancel(true).
if (backgroundTask != null) {
backgroundTask.requestTermination();
try {
Thread.sleep((int)(0.5 * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (backgroundTask.getStatus() != AsyncTask.Status.FINISHED) {
backgroundTask.cancel(false);
}
backgroundTask = null;
}
As a side result, after doInBackground() finishes, sometimes the onCancelled() method is called, and sometimes onPostExecute(). But at least the async task termination is guaranteed.
With reference to Yanchenko's answer on 29 April '10:
Using a 'while(running)' approach is neat when your code under 'doInBackground' has to be executed multiple times during every execution of the AsyncTask. If your code under 'doInBackground' has to be executed only once per execution of the AsyncTask, wrapping all your code under 'doInBackground' in a 'while(running)' loop will not stop the background code (background thread) from running when the AsyncTask itself is cancelled, because the 'while(running)' condition will only be evaluated once all the code inside the while loop has been executed at least once. You should thus either
(a.) break up your code under 'doInBackground' into multiple 'while(running)' blocks or
(b.) perform numerous 'isCancelled' checks throughout your 'doInBackground' code, as explained under "Cancelling a task" at https://developer.android.com/reference/android/os/AsyncTask.html.
For option (a.) one can thus modify Yanchenko's answer as follows:
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
//...
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
// does the hard work
while (running) {
// part 1 of the hard work
}
while (running) {
// part 2 of the hard work
}
// ...
while (running) {
// part x of the hard work
}
return null;
}
// ...
For option (b.) your code in 'doInBackground' will look something like this:
public class MyTask extends AsyncTask<Void, Void, Void> {
//...
#Override
protected Void doInBackground(Void... params) {
// part 1 of the hard work
// ...
if (isCancelled()) {return null;}
// part 2 of the hard work
// ...
if (isCancelled()) {return null;}
// ...
// part x of the hard work
// ...
if (isCancelled()) {return null;}
}
// ...