I'm making an Android app where the user can download files from a FTP-server. For the ftp parts I am using apache.org.commons-net package.
When I have connected to server I get a list of the filenames, and then I want to download each file. I start the download routine which runs in a thread of it's own.
The problem I'm experiencing is, that if I have say 6 files on the server, and I run this code on my emulator, it will download the first two files, and then just freeze (with the progressbar hanging on 34 %). When I run it on my phone it will download three files and freeze.
If I debug my way through the code on the emulator it will download all six files just fine and not freeze.
Does anyone have any idea what might be the problem?
Thanks in advance,
LordJesus
This is my code (the client is already initialized):
private void downloadFiles2() {
dialog = new ProgressDialog(this);
dialog.setCancelable(true);
dialog.setMessage("Loading...");
// set the progress to be horizontal
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// reset the bar to the default value of 0
dialog.setProgress(0);
dialog.setMax(DownloadCount);
// display the progressbar
dialog.show();
// create a thread for updating the progress bar
Thread background = new Thread (new Runnable() {
public void run() {
InputStream is = null;
try {
for (String filename : fileNames) {
is = client.retrieveFileStream(filename);
byte[] data = new byte[1024];
int x = 0;
x = is.read(data, 0, 1024);
boolean downloadIsNewer = true;
File fullPath = new File(path + "/" + filename);
Log.d("FTP", "Starting on " + filename);
if (fullPath.exists()) {
downloadIsNewer = checkIfNewer(data, fullPath);
}
if (downloadIsNewer) {
Log.d("FTP", "Need to download new file");
FileOutputStream fos = new FileOutputStream(fullPath);
fos.write(data,0,x);
while((x=is.read(data,0,1024))>=0){
fos.write(data,0,x);
}
fileText += filename + " - downloaded OK." + FileParser.newline;
is.close();
client.completePendingCommand();
fos.flush();
fos.close();
}
else {
Log.d("FTP", "No need to download");
is.close();
fileText += filename + " - own copy is newer." + FileParser.newline;
}
// active the update handler
progressHandler.sendMessage(progressHandler.obtainMessage());
}
client.logout();
client.disconnect();
}
catch (Exception e) {
// if something fails do something smart
}
}
});
// start the background thread
background.start();
}
Handler progressHandler = new Handler() {
public void handleMessage(Message msg) {
dialog.incrementProgressBy(1);
InfoTextView.setText(fileText);
if(dialog.getProgress()== dialog.getMax())
{
dialog.dismiss();
}
}
};
OK, found the problem:
When the boolean downloadIsNewer is false I do not call client.completePendingCommand(). When I add that before the line is.close() it works like a charm.
Related
I have followed some online tutorials and created this code to download the files that i have hosted in dropbox
I am using async task to do this
// AsyncTask to download a file
private class DownloadTask extends AsyncTask<String, Integer, String> {
private Context context;
public DownloadTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... sUrl) {
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
wl.acquire();
try {
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();
// TODO
File file = new File(Environment
.getExternalStorageDirectory().getPath()
+ "/kathmandu.map");
if (file.exists()) {
Log.i("File Exists", "Code Gets here, file exists");
return "exists";
// if (connection.getResponseCode() ==
// HttpURLConnection.HTTP_NOT_MODIFIED) {
//
// return null;
// }
}
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
Log.i("Length", String.valueOf(fileLength));
// download the file
input = connection.getInputStream();
output = new FileOutputStream(Environment
.getExternalStorageDirectory().getPath()
+ "/kathmandu.map");
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled())
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();
}
} finally {
wl.release();
}
return null;
}
I call the download code when the download options menu is clicked.
final DownloadTask downloadTask = new DownloadTask(MapActivity.this);
downloadTask
.execute("https://dl.dropboxusercontent.com/u/95497883/kathmandu-2013-8-12.map");
mProgressDialog
.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
downloadTask.cancel(true);
}
});
The code works fine but at the times the outputstream does not write full file and exits. Everything looks okay. The file is downloaded but it is corrupted.
The getContentLength() also returns -1 so i cannot check if the whole file has been downloaded using the content length. The file is a offline vector map and i need it to display offline maps. The corrupted file causes a runtime exception while trying to access it. Is there is any way to ensure that the file has been downloaded correctly.
Also i would like to provide the data with the app itself. Can i put this in the assets folder of my app. What is the best way to access the files in the assets folder during runtime.
Your assets folder is not writable as it is a part of the apk. you can of course use your application's sandbox storage (using Environment.getDir() ) or external storage (using Environment.getExternalStorageDirectory()) like you have done in your code.
I think using the DownloadManager would be a great idea to achieve exactly what you want please refer : http://developer.android.com/reference/android/app/DownloadManager.html
a short solution
DownloadManager.Request req=new DownloadManager.Request(url);
req.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI
| DownloadManager.Request.NETWORK_MOBILE)
.setTitle("Downloading")
.setDescription("Map is Being Downloaded")
.setDestinationInExternalPublicDir(Environment.getExternalStorageDirectory,
"+/maps_app/something.map");
While uploading multiple image at a time i want to show progress bar which show the progress bar in statusbar notification area with the info 1/5 and 2/5 and so on. where 1 is no of image uploaded and 5 is total no of image to be uploaded.
here i am able show progress bar in notification area. can any one suggest me, how to calculate no of image uploaded(finished) to show in progress bar (like 1/5)update. thanks in advance.
For making more clear
i have a asyntask which upload a single image to server. but i am not able to do
1> calculate size of total image (say for example 5 image)
2>how to find no of image uploaded in total 5 image
private class FileUploadTask extends AsyncTask<Object, Integer,String> {
private ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(context);
dialog.setMessage("Uploading...");
dialog.setIndeterminate(false);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setProgress(0);
dialog.show();
}
#Override
protected String doInBackground(Object... arg0) {
try {
File file = new File("/mnt/sdcard/DCIM/100MEDIA/IMAG0149.jpg");
FileInputStream fileInputStream = new FileInputStream(file);
byte[] bytes = new byte[(int) file.length()];
fileInputStream.read(bytes);
fileInputStream.close();
URL url = new URL("http://android.com.bd/form.php");
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
OutputStream outputStream = connection.getOutputStream();
int bufferLength = 1024;
for (int i = 0; i < bytes.length; i += bufferLength) {
int progress = (int)((i / (float) bytes.length) * 100);
Log.i("progress",progress+"dfdf");
publishProgress(progress);
if (bytes.length - i >= bufferLength) {
outputStream.write(bytes, i, bufferLength);
} else {
outputStream.write(bytes, i, bytes.length - i);
}
}
publishProgress(100);
outputStream.close();
outputStream.flush();
InputStream inputStream = connection.getInputStream();
// read the response
inputStream.close();
return "ok";
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Integer... progress) {
dialog.setProgress(progress[0]);
}
#Override
protected void onPostExecute(String result) {
Log.v("sds", result);
try {
dialog.dismiss();
} catch(Exception e) {
}
}
}
Take a look at this TL;DR blog post/tutorial. You should be able to do something similar. You'll want to use a ProgressDialog, updating its state using an ASyncTask. If you're already using an ASyncTask for your image upload, you already have the pieces in place.
http://toolongdidntread.com/android/android-multipart-post-with-progress-bar/
Also take a look at this SO question - Download a file with Android, and showing the progress in a ProgressDialog. Your question has been answered before. You'll just need to adapt the solution to display the progress bar at 1/5, 2/5, etc by customizing onProgressUpdate. I haven't tested this code, but I'd imagine something along these lines will allow you to display the progress incrementally like you want.
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
if (progress[0] < 20) {
mProgressDialog.setProgress(0);
} else if (progress[0] < 40) {
mProgressDialog.setProgress(20);
}
else if (progress[0] < 60) {
mProgressDialog.setProgress(40);
}
else if (progress[0] < 80) {
mProgressDialog.setProgress(60);
}
else if (progress[0] < 100) {
mProgressDialog.setProgress(80);
}
else if (progress[0] == 100) {
mProgressDialog.setProgress(100);
}
}
Where are your images? you have to do like
File fav = new File(Environment.getExternalStorageDirectory().getPath());
File[] filesav = fav.listFiles();
for (int i = 0; i < filesav.length; i++) {
inside you send your pictures and count
}
the variable i is your image number and filesav.length is your total image number
Well, it really depends on how you download you images ?
What I would advice is to create an instance (singleton) of some DownloadManager class, which would count and manage the number of started and finished download. This instance will be used to create new downloads, and will be notified each time a download is finished. When notified, it could then update the progress bar.
But this is a very generic answer. Cannot do better without more informations on how you currently do the downloads (are they done in separate threads ? Are they sequential or parallel ?...)
I made an app that downloads videos from our server.
The issue is:
When i cancel the downloading i call:
myAsyncTask.cancel(true)
I noticed, that myAsyncTask doesn't stops on calling cancel... my ProgressDialog still goes up and its like jumping from status to status showing me that each time I cancel and start again an AsyncTask by clicking the download button, a new AsyncTask starts...
Each time I click download.. then cancel, then again download a separate AsyncTask starts.
Why is myAsynTask.cancle(true) not cancelling my task ? I don't want it anymore on the background. I just want to completely shut it down if I click cancel.
How to do it ?
E D I T:
Thanks to gtumca-MAC, and the others who helped me did it by:
while (((count = input.read(data)) != -1) && (this.isCancelled()==false))
{
total += count;
publishProgress((int) (total * 100 / lenghtOfFile));
output.write(data, 0, count);
}
Thanks!!!
AsyncTask does not cancel process on
myAsynTask.cancel(true)
For that you have to stop it manually.
for example you are downloading video in doInBackground(..) in while/for loop.
protected Long doInBackground(URL... urls) {
for (int i = 0; i < count; i++) {
// you need to break your loop on particular condition here
if(isCancelled())
break;
}
return totalSize;
}
Declare in your class
DownloadFileAsync downloadFile = new DownloadFileAsync();
then On Create
DownloadFileAsync downloadFile = new DownloadFileAsync();
downloadFile.execute(url);
in Your Background ()
if (isCancelled())
break;
#Override
protected void onCancelled(){
}
and you can kill your AsyncTask by
downloadFile.cancel(true);
When you start a separate thread(AyncTask) it has to finish. You have to manually add a cancel statement to your code inside the AsyncTask.
A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
Checkout more in the documentation: http://developer.android.com/reference/android/os/AsyncTask.html
I have been researching from the last 2 weeks and I don't get to know that how we kill the Async operation manually. Some developers use BREAK; while checking in for loop. But on my scenario I am not using the loop inside of background thread.
But I have got to know how it woks its a stupid logic but works perfectly fine.
downloadFile.cancel(true); //This code wont work in any case.
Instead of canceling and doing so much work on background thread turn off the wifi programmatically
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(false);
where do you want to kill the operation and turn on it where do you need that.
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(true);
What happens is your try block jumps in to the IOException killing the background tasks.
You better use vogella asyncTask library which have a lot of features like priority and canceling background task. And a great tutorial or using it is here
You can use this code. I am downloading a OTA file as follow:
static class FirmwareDownload extends AsyncTask<String, String, String> {
public String TAG = "Super LOG";
public String file;
int lenghtOfFile;
long total;
#Override
protected String doInBackground(String... f_url) {
try {
int count;
Utilies.getInternet();
URL url = new URL(f_url[0]);
URLConnection connection = url.openConnection();
connection.connect();
lenghtOfFile = connection.getContentLength();
mProgressBar.setMax(lenghtOfFile);
InputStream input = new BufferedInputStream(url.openStream(), 8192);
String fileName = f_url[0].substring(f_url[0].lastIndexOf("/"), f_url[0].length());
File root = Environment.getExternalStorageDirectory();
File dir = new File(root.getAbsolutePath() + fileName);
Log.d(TAG, "trying to download in : " + dir);
dir.getAbsolutePath();
OutputStream output = new FileOutputStream(dir);
byte data[] = new byte[1024];
while ((count = input.read(data)) != -1) {
if (isCancelled())
break;
total += count;
mProgressBar.setProgress(Integer.parseInt("" + total));
Log.d("Downloading " + fileName + " : ", " " + (int) ((total * 100) / lenghtOfFile));
mPercentage.post(new Runnable() {
#Override
public void run() {
mPercentage.setText(total / (1024 * 1024) + " Mb / " + lenghtOfFile / (1024 * 1024) + " Mb");
}
});
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
//new InstallHelper().commandLine("mkdir data/data/ota");
File fDest = new File("/data/data/ota/" + fileName);
copyFile(dir, fDest);
FirmwareInstaller fw = new FirmwareInstaller();
fw.updateFirmware();
} catch (Exception a) {
System.out.println("Error trying donwloading firmware " + a);
new InstallHelper().commandLine("rm -r data/data/ota");
dialog.dismiss();
}
return null;
}
}
So, If you want to cancel, just use this code:
fDownload.cancel(true);
I have used with success inside an activity with TextView onclick ...
//inside the doInBackground() ...
try {
while (true) {
System.out.println(new Date());
//should be 1 * 1000 for second
Thread.sleep(5 * 1000);
if (isCancelled()) {
return null;
}
}
} catch (InterruptedException e) {
}
and in my onCreate() ...
//set Activity
final SplashActivity sPlashScreen = this;
//init my Async Task
final RetrieveFeedTask syncDo = new RetrieveFeedTask();
syncDo.execute();
//init skip link
skip_text = (TextView) findViewById(R.id.skip_text);
skip_text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//cancel Async
syncDo.cancel(true);
//goto/start another activity
Intent intent = new Intent();
intent.setClass(sPlashScreen, MainActivity.class);
startActivity(intent);
finish();
}
});
and my xml TextView element ...
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/skip_text"
android:layout_marginTop="20dp"
android:text="SKIP"
android:textColor="#color/colorAccent"/>
I'm downloading sets of images in separated threads and saving them to the SD card. The problem is that when I run two or more downloading threads the saved images are corrupted. If just one thread is running the images are ok. I'm downloading it from the same domain but different url, e.g. www.test.com/set1/img1.jpg, www.test.com/set2/img1.jpg etc.
I'm saving them to different folders by the name of the set. I noticed that mostly larger images are corrupted (over 500 KB), smaller are usually ok, but not always.
Do you have any clue why the files get corrupted when multiple threads are running?
Here's a part of the code I'm using:
protected class DownloadTask extends DownloadRunnable {
#Override
public void run() {
InputStream is = null;
OutputStream os = null;
File bitmapFile = null;
/** some more declarations and preparations are here */
for (int pg=getDownloadedPages(); pg < numPages; ++pg) {
for (char ch='a'; ch <= 'e'; ++ch) {
/* check for pause */
synchronized (pauseLock) {
while (paused && !aborted) {
try {
pauseLock.wait();
} catch (InterruptedException e) {
}
}
}
fileName = "page-" + df.format(pg) + "-" + ch;
url = MainApp.getRestrictedUrl(MainApp.tstcode, urlFile + fileName+ ".jpg");
is = new BufferedInputStream(new URL(url).openStream());
if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
bitmapFile = new File(pathToSave, fileName + MagazinePage.FILE_EXT);
MainApp.encryptToFile(bitmapFile, is);
dwnlSize += bitmapFile.length();
}
is.close();
}
}
}
public static void encryptToFile(File file, InputStream is) throws IOException {
BufferedOutputStream os = null;
try {
if (file.exists()) {
file.delete();
} else {
file.getParentFile().mkdirs();
}
file.createNewFile();
os = new BufferedOutputStream(new FileOutputStream(file));
IkioskContentProvider.getInstance().encrypt(is, os);
} finally {
os.close();
}
}
}
DownloadRunnable is custom abstract class implementing Runnable. And I'm using it in thread the regular way:
protected void downloadIssuePages() {
dwnlTask = new DownloadTask();
new Thread(dwnlTask).start();
}
I'm calling downloadIssuePages() on two different objects to download two sets for example.
Using SDK version 11 (Android 3.0), device Acer Iconia Tab A500 with Android 3.1
I've tried to disable writing for the second thread, only the first thread was saving files to find out if there's a problem in reading from the stream or writing. Apparently writing was the problem as data was correct in this case.
So I decided to use lock around writing to the file and looks like it's working fine:
synchronized (MainApp.fileWritingLockObj) {
while (MainApp.fileWritingLocked) {
try {
MainApp.fileWritingLockObj.wait();
} catch (InterruptedException e) {
}
}
MainApp.fileWritingLocked = true;
if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
bitmapFile = new File(pathToSave, fileName + MagazinePage.FILE_EXT);
MainApp.encryptToFile(bitmapFile, is);
dwnlSize += bitmapFile.length();
}
is.close();
MainApp.fileWritingLocked = false;
MainApp.fileWritingLockObj.notifyAll();
}
I am getting the GUI flicker when reading a file properties and accordingly enabling/disabling checkbox and List value in listbox. when i remove this file reading code the GUI doesnt have flicker.
I am reading the properties before creating the Preferences in OnCreate(). Attached the file write code below for reference.Please let us know is there any other way to read and update the preference staus.
private void SetExtendConf(String key, String strValue)
{
mProperties = new Properties();
try {
File file = new File(FILE_EXT);
if(!file.exists())
file.createNewFile();
file.setWritable(true,false);
FileInputStream fis = new FileInputStream(file);
mProperties.load(fis);
fis.close();
FileOutputStream stream = new FileOutputStream(file);
Log.d(TAG, "Setting Values " + key + ":"+ strValue);
mProperties.setProperty(key, strValue);
mProperties.store(stream,"ext.conf");
stream.close();
} catch (IOException e) {
Log.d(TAG, "Could not open properties file: " + GPS_FILE_EXT);
}
}
-Manoj
Why are you instantiating new Properties objects, re-read and re-write the props file for each operation on properties? If theres no actual reason for doing so, just read them once and write them when needed (taking care of onPause/onResume), and do it in a thread, ie:
final Handler handler = new Handler();
[...]
Runnable writeProps = new Runnable() {
#Override
public void run() {
// do your work here
[...]
// run this if you want to notify something to the UI thread
// handler.post(new Runnable() {public void run() { notifyUI(); }});
}
};
Thread thread = new Thread(writeProps, "writeProps");
thread.start();
[...]