App slows down with calculation of length in seconds of WAV file - android

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]);
}

Related

Writing to storage from handler

I'm trying to write the stream of my array that is coming from Bluetooth module and read from (HandleRead), to the internal storage directly. Is that possible in the first place?
Note that I am reading 100 samples per second. That means the file will fill up quickly. I am not familiar with storage, and my code isn't executed as I expected.
public class MainActivity extends ActionBarActivity implements SensorEventListener {
File Root = Environment.getExternalStorageDirectory();
File Dir = new File (Root.getAbsolutePath()+"/myAppFile");
File file = new File(Dir,"Message.txt");
#Override
protected void onCreate(Bundle savedInstanceState){
String state;
state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)){
if (!Dir.exists()){
Dir.mkdir();
}
}
private void handleRead(Message msg) {
byte[] readBuf = (byte[]) msg.obj;
String readMessage = new String(readBuf);
ByteBuffer buffer = ByteBuffer.wrap(readBuf, 0, readBuf.length);
buffer.order(ByteOrder.BIG_ENDIAN);
buffer.clear();
final String[] strNumbers = readMessage.split("\n");
for (int j = 1; j <= strNumbers.length - 2; j++) {
pressure = Integer.parseInt(readMessage2);
MyFinalPressure = (float) (9.677 +0.831 * pressure);
// trying to store directly to internal sotrage
activity.save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
FileOutputStream fileOutputStream = new FileOutputStream(activity.file);
fileOutputStream.write((int) MyFinalPressure);
fileOutputStream.close();
Toast.makeText(activity.getApplicationContext(),"Message saved ", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
}
}
It appears you are not setting the FileOutputStream to 'append' (you need to add 'true' as 2nd parameter in constructor.)
This would write over the file from the file-start every time
also your 'setOnClickListener' is INSIDE your loop. This doesn't do anything for you as far as I can tell.
I recommend always setting up UI elements in a private void setupUI() {...} method that onCreate calls. The public void onClick(View v) {buttonForSavingPresssed()} where buttonForSavingPressed(){...} is the 'logic' of your onClick() method.
This will help you clean up the class and not have stray onClickListener assignments, etc.
My guess is that either your multiple assignments is very inefficient, since clickListeners aren't cheap, or... the clickListener might not even work at all because of a timing issue (if your loop is long running and you press the button and the listener has already been swapped for a new one)
I've cleaned up your code some, There are some suggestions and some log statements that should help you figure out what is going on.
// this is inside your onCreate()
...
activity.save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { buttonPressed();}
});
...
// Here is where you would put your logic when the button is presssed
public void buttonPressed(){
Toast.makeText(activity.getApplicationContext(),"Button Pressed ",
Toast.LENGTH_SHORT).show();
}
// you should make 'helper' functions that consolidate separate pieces of logic like this,
// that way you can more easily track what is happening in each method.
// Plus it helps keep each method shorter for ease of understanding, etc.
public void writeToFile(float finalPressure){
Log.d(LOG_TAG // where LOG_TAG is the String name of this class
"writeToFile(float) called." );
try{
// true here for 'append'
FileOutputStream fileOutputStream = new
FileOutputStream(activity.file, true);
fileOutputStream.write((int) finalPressure);
fileOutputStream.close();
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// now back to your handleRead, is this method called async wenever
// a message is read? Then wouldn't this be called a lot? I'm lost as to why
// you had the button in here at all.
private void handleRead(Message msg) {
Log.d(LOG_TAG // where LOG_TAG is the String name of this class
"handleRead(Message) called." );
byte[] readBuf = (byte[]) msg.obj;
String readMessage = new String(readBuf);
ByteBuffer buffer = ByteBuffer.wrap(readBuf, 0, readBuf.length);
buffer.order(ByteOrder.BIG_ENDIAN);
buffer.clear();
final String[] strNumbers = readMessage.split("\n");
Log.d(LOG_TAG // where LOG_TAG is the String name of this class
"strNumbers length: " + strNumbers.length );
for (int j = 1; j <= strNumbers.length - 2; j++) {
pressure = Integer.parseInt(readMessage2);
MyFinalPressure = (float) (9.677 +0.831 * pressure);
// trying to store directly to internal sotrage
writeToFile(MyFinalPressure);
}
}

Re-Download the file every time I open the app

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..

Android: Asynctask's doInBackground method is called after a long delay

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

How to run CountDownTimer when I'm not in the main thread

I am trying to download a file from a URL. If the download fails (regardless of the reason) I want the application to retry an hour later.
Since the download is in it's own thread (not the main thread), I can't seem to start a new CountDownTimer.
I don't want to block the download thread so I'm trying to use the CountDownTimer.
Is there another way to do this?
Thanks in advance!
private class Downloader extends AsyncTask<Object, Void, File>
{
#Override
protected File doInBackground(Object... params)
{
Context context = (Context) params[0];
String strUrl = (String) params[1];
String strFileName = (String) params[2];
return download(context, strUrl, strFileName);
}
/**
* Downloads files in a separate thread. Adds notification of download to status bar.
*/
public File download(final Context context, final String url, final String fileName)
{
boolean isVideoLoaded=false;
try
{
URL urlObj = new URL(url);
URLConnection con = urlObj.openConnection();
BufferedInputStream bis = new BufferedInputStream(con.getInputStream(), BUFFER_SIZE);
FileOutputStream fos = new FileOutputStream(retFile);
byte[] bArray = new byte[BUFFER_SIZE];
int current = 0;
int read = 0;
while(current != -1)
{
fos.write(bArray,0,current);
current = bis.read(bArray, 0, BUFFER_SIZE);
read = read + current;
}
fos.close();
bis.close();
isVideoLoaded = true;
strFileName = retFile.getAbsolutePath();
}
catch(Exception ioe)
{
Log.d("Downloader.download", "Error: " + ioe.toString(), ioe);
}
}
if (!isVideoLoaded) // if video is still not loaded
{
// sleep then try again
new CountDownTimer(15000, 2000)
{
public void onFinish()
{
Downloader dh = new Downloader();
Object params[] = new Object[3];
params[0] = context;
params[1] = url;
params[2] = fileName;*/
dh.execute(params);
}
#Override
public void onTick(long millisUntilFinished) {
// TODO Auto-generated method stub
}
}.start();
}
return retFile;
}
protected void onPostExecute(File file) {
// display downloaded file
}
You can create a Timer that will start a download on your UI thread.
In your UI class, use this function
private StartOneHourTimer()
{
new CountDownTimer(10000 * 3600, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
m_downloader = new Downloader(..);
m_downloader.execute(..);
}
}.start();
}
In your Downloader onPostExecute(),
start a new Timer that will expire in 1 hour.
protected void onPostExecute(File file)
{
if (!isVideoLoaded)
startOneHourTimer();
else
//Call your normal UI code here
}
Change your onPostExecute so that it calls back out to the main activity to signify that the download failed (should be able to get to it by MyMainActivity.this.someMethod().) The main activity can then make a new AsyncTask (you can't reuse the old one) and signify that it should delay start.
One option for doing this is to add a constructor to your AsyncTask so you can pass a delay parameter to it, then your AsyncTask can use the delay parameter as part of the doInBackground method.
Inside doInBackground simply wait with a Thread.sleep()

Download multiple photos within a loop in android?

I want to download multiple images from different URLs.
My problem is Not all photos are loaded
This problem appears in emulator and mobile version 2.2
If I want to download 6 photos there only 5 while the app. running.
If I want to download 25 photos there only 12 ,16 or 20 while the app. running.
each time I run the emulator there is a different result :S
This run correctly on 2.3 emulator ..
.java
public class DownloadPhotos extends Activity{
Context context;
// Progress dialog --> shows that something is loading
ProgressDialog dialog;
// the layout where we insert the loaded pictures
LinearLayout linlayout;
// where we put all bitmaps after download
ArrayList<Bitmap> photos = new ArrayList<Bitmap>();
// URLs of photos we want to download
String [] urls = {
"http://www.flowersegypt.net/upload/Flowers-Egypt-6.jpg","http://www.kabloom.com/images/product_images/KB_11100.jpg"
,"http://faisal-saud.com/wp/wp-conteant/uploads/2010/09/QuilledFlowers.jpg",
"http://i3.makcdn.com/wp-content/blogs.dir/144387/files//2009/11/wedding-flowers1.jpg",
"http://www.funonthenet.in/images/stories/forwards/flowers/Blue-Bell-Tunicate.jpg",
"http://flowersfast.com/f4322dl.jpg"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
// Setting the layout of the page to "downloadphoto.xml" layout
setContentView(R.layout.downloadphoto);
// Bind the previously defined layout with the lyout in the xml
linlayout = (LinearLayout) findViewById(R.id.linearLayout1);
this.context=this;
//Checking if Internet is connected
if(CheckConnection())
{
// Starts in Threads
new THREAD1().execute("");
}
}
//========== Threads ============
//===============================
private class THREAD1 extends AsyncTask<String, Bitmap, Void>
{
// This function shows the progress dialog
// and it works on foreground
// while the needed data is loaded
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dialog = ProgressDialog.show(context , "",
"Loading. Please wait...", true);
}
// This function is responsible for loading the data
// and it works in the background
#Override
protected Void doInBackground(String... params) {
// TODO Auto-generated method stub
//get all bitmaps of the predefined URLs
for(int i=0 ;i<urls.length;i++)
{
Bitmap tmp = Networking.getimage(urls[i]);
if(tmp != null)
{
photos.add(tmp);
// This line calls the function "onProgressUpdate" for each loaded bitmap
publishProgress(tmp);
}
}
return null;
}
//this function is called in ech time
#Override
protected void onProgressUpdate(Bitmap... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
ImageView image = new ImageView(context);
image.setImageBitmap(values[0]);//ba3red el bitmap
image.setScaleType(ScaleType.CENTER);
image.setClickable(true);
image.setPadding(10,10, 10,10);
linlayout.addView(image);
dialog.cancel();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}
// This function returns true if Internet connected otherwise returns false
public Boolean CheckConnection()
{
ConnectivityManager conMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
boolean connected=( conMgr.getActiveNetworkInfo() != null &&
conMgr.getActiveNetworkInfo().isAvailable() &&
conMgr.getActiveNetworkInfo().isConnected() );
return connected;
}
}
Functions I used to download a photo
1.
public static Bitmap getimage(String URL)
{
Bitmap bitmap=null;
InputStream in=null;
try {
// all spaces must be replaced by 20%
String tmp = URL.replaceAll(" ", "20%");
in = OpenHttpConnection(tmp);
BitmapFactory.Options options=new BitmapFactory.Options();
// deh mas2ola enha trag3 1/2 el image
options.inSampleSize = 2 ;
options.inScaled = true;
bitmap = BitmapFactory.decodeStream(in, null, options);
in.close();
} catch (Exception e) {
// TODO: handle exception
}
return bitmap;
}
You're completely misunderstandind the AsyncTask idea. There are three parameter types used in AsyncTask: input type, progress type and output type. In your case the input type should be String since you have an array of URI's. The progress type should be Integer if you want to show the current progress to your users, or Void if you don't. And the output type is Bitmap, cause the result of the AsyncTask is actually an array of downloaded Bitmaps. Your main problem is your AsyncTask's design. Try to correct it and run your application again, there is a high probability that it will work since then. Hope this helps.

Categories

Resources