am writing a downloadManager and i need a hint. there i could create an event an fire it when ever i wanted. but i cant seem to find how to do that in java. what i want to do is i want to create an event for my class and then fire it inside one of the classes' member methods. now when ever this Class is called and sees that the download is finish(i.e. some variable has reached 100 for example) it fires an event indicating the situation. how can i create that in java?
public class DownloadManager
{
static Queue<AvailableGame> downloadQueue;
static Integer currenProgress;
static String currentDownload;
static Boolean isRunning;
/**
* Start download
*/
public void startDownloading()
{
AsyncTask task = new AsyncTask()
{
#Override
protected Object doInBackground(Object[] objects)
{
downloadNextFile();
return null;
private static String downloadFile(String downloadUrl)
{
String toDownload = downloadUrl;
String fileName = getFileNameFromUrl(toDownload);
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
PowerManager pm = (PowerManager)
MainActivity.getContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"DownloadManager");
wl.acquire();
try
{
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try
{
URL url = new URL(toDownload);
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();
}
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/" + fileName);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1)
{
total += count;
// publishing the progress....
if (fileLength > 0)
{
currenProgress = ((int) (total * 100 / fileLength));
currentDownload = "Downloading " + fileName;
}
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;
}
}
How can i save information when my download is finish,the second probleem is how to a
First I think you should be using Android's DownloadManager for this. If you are, you can register a BroadcastReceiver that detects when a download is finished.
There is a full example you can download and run on your phone with full source code for you to see how this can be done: https://github.com/commonsguy/cw-omnibus/tree/master/EmPubLite/T16-Update
Check specifically the files DownloadCheckService.java and DownloadCompleteReceiver.java.
Hope it helps.
Related
I followed the instruction on the Retrofit page to download an image, however, without the #Streaming tag, the inputstream.read(buffer) would be equal -1 immediately, rendering the file empty. (the image is quite small, only a few hundred kb)
Even when I use the #Streaming tag, the app would keep crashing when I use the inputstream due to IllegalStateException
I tried HttpConnection and I could download the image just fine. However, I really want to make it work with Retrofit
public static String downloadImage(String bearer, long pictureId,Context context){
String path = "";
NetworkAPI apiService = NetworkClient.getClient().create(NetworkAPI.class);
//Call<ResponseBody> downloadCall = apiService.downloadImage(bearer,pictureId);
Call<ResponseBody> downloadCall = apiService.downloadFileWithDynamicUrlSync("https://androidtutorialpoint.com/api/RetrofitAndroidImageResponse");
try {
Response<ResponseBody> response = downloadCall.execute();
if(response.isSuccessful()) {
Log.d(TAG, "success download" + response.body().string());
Log.d("DownloadImage", "Reading and writing file");
InputStream in = null;
OutputStream out = null;
try {
in = response.body().byteStream();
File file = PictureUtil.createImageFile(context);
Uri photoURI = FileProvider.getUriForFile(context,
"vn.com.wk.bradleyaudit.fileprovider",
file);
out = new FileOutputStream(file);
long fileSize = response.body().contentLength();
long downloadedSize = 0;
Log.d("DownloadImage", "size"+fileSize);
byte[] buffer = new byte[4096];
while (true) {
int bufferLength = in.read(buffer);
Log.d("DownloadImage", "buffer Length"+bufferLength);
if (bufferLength == -1) {
break;
}
out.write(bufferLength);
out.write(buffer, 0, bufferLength);
downloadedSize += bufferLength;
}
out.flush();
path = photoURI.toString();
Log.d("DownloadImage", "path"+path);
}
catch (IOException e) {
Log.d("DownloadImage",e.toString());
}
finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return path;
}
Try this,
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
also add the dependancy;
compile 'com.squareup.picasso:picasso:2.5.2'
So I have an app which downloads certain files, dedicated to a client of mine who is hosting his files on a remote location, and i'm doing so using the code below:
public class DownloadService extends IntentService {
private int result = Activity.RESULT_CANCELED;
public DownloadService() {
super("DownloadService");
}
#Override
protected void onHandleIntent(Intent intent) {
String urlPath = intent.getStringExtra(URL);
String fileName = intent.getStringExtra(FILENAME);
File output = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
fileName);
if (output.exists()) {
output.delete();
}
URLConnection streamConnection = null;
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
streamConnection = url.openConnection();
stream = streamConnection.getInputStream();
streamConnection.connect();
long lengthofFile = streamConnection.getContentLength();
InputStream reader = stream;
bis = new BufferedInputStream(reader);
fos = new FileOutputStream(output.getPath());
int next = -1;
int progress = 0;
int bytesRead = 0;
byte buffer[] = new byte[1024];
while ((bytesRead = bis.read(buffer)) > 0) {
fos.write(buffer, 0, bytesRead);
progress += bytesRead;
int progressUpdate = (int)((progress * 100) / lengthofFile);
Intent testIntent = new Intent(".MESSAGE_INTENT");
testIntent.putExtra(PERCENTAGE, progressUpdate);
sendBroadcast(testIntent);
}
result = Activity.RESULT_OK;
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
publishResults(output.getAbsolutePath(), result);
}
private void publishResults(String outputPath, int result) {
Intent intent = new Intent(".MESSAGE_INTENT");
intent.putExtra(FILEPATH, outputPath);
intent.putExtra(RESULT, result);
sendBroadcast(intent);
}
}
and to call this service i would use:
Intent intent = new Intent(MainActivity.getAppContext(), DownloadService.class);
intent.putExtra(DownloadService.FILENAME, downloadFileName[item]);
intent.putExtra(DownloadService.URL, urlDownload[item]);
MainActivity.getAppContext().startService(intent);
now this allows user to download one file at a time, however if the user downloads another file, the second file will have to wait till the first file is done downloading.
now what is happening in my case is:
1- First download FILE_1 is downloading, and in the status is says FILE_1.
2- User clicks a new file download, the status changes the first file name to the second file name, and waits till FILE_1 finishes download to start with FILE_2 however the active download is changed from FILE_1 to FILE_2.
questions:
is there a way to call DownloadService multiple times for multiple files?
is it possible to fix the problem i'm facing? treating download intent services as two different intents?
UPDATE
I managed to solve this issue by assigning a unique Int ID per file, each ID will point to a position in the listview which displays the files being downloaded or queued, then i work with each file on it's own.
Following code uses commons-io-2.4.jar library to make your work easy by handling low level data movements as you would focus on method in hand
URL someUrl = new URL("your url String"); //
File someFile = new File("your file, where you want to save the data");
FileUtils.copyURLToFile(someUrl, someFile );
if you want to call this statement few time to download different files from the server following code might give you an idea what you might want to do, but you will have to write it's equivalent code to run in android which you want to probably AsyncTask
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.io.FileUtils;
public class DownloadTest {
public static void main(String[] args) {
Thread thread = new Thread(){
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
dowanloadFile(new URL("some url"), new File("some file"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
thread.start();
}
private static void dowanloadFile(URL url, File file){
try {
FileUtils.copyURLToFile(url, file );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Trying to download about 38 video files from a server with the code below and for some reason it keeps stopping at different points during the download, I'm mostly getting a
java.net.SocketException: Connection timed out
I'd like to know how I can perform this with less errors
My code below
private class DownloadFile extends AsyncTask<String, Integer, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.show();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
mProgressDialog.setProgress(progress[0]);
mProgressDialog.setMessage("Downloading "+(i+1)+" of "+downloadURL.length);
}
#Override
protected String doInBackground(String... sUrl) {
try {
for(int i = 0; i < sUrl.length; i++){
URL url = new URL("http://myvideo.info/videos/"+sUrl[i]);
URLConnection connection = null;
try {
connection = url.openConnection();
connection.setConnectTimeout(15000);
connection.setReadTimeout(15000);
} catch (java.net.SocketTimeoutException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
connection.connect();
// this will be useful so that you can show a typical 0-100% progress bar
int fileLength = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream("/sdcard/"+file_rename[i]);
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
}
} catch (Exception e) {
Log.e("PP", "PP", e);
}
return null;
}
protected void onPostExecute(String jsonResult) {
mProgressDialog.dismiss();
}
}
Are you sure the server is responding in less then 15 sec?(that is the timeout I've seen that you have set). If the files are big you should be downloading them separately, take a look at Downloader manager, you can use it to download big files easy.
What download manager are you using?
And I'd suggest changing your timeout to the maximum. Personally your code seems fine. I think it would be your download manager and timeout. Hope this helps.
i've an activity with a button and a label.
On button click my app must download several files ( about 9000 ).
If user clicks again on button, the download must stop and on another click it must start from the beginning.
So this is what i do:
In activity:
file.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Button b = (Button)v;
if(canFile){
b.setText("Stop download");
changeLabelInfo("Getting file list...");
labelFile.setVisibility(View.VISIBLE);
fileTask.start();
}else{
b.setText("Download files");
if(fileTask.isAlive()){
fileTask.interrupt();
fileTask = null;
fileTask = new UpdateFilesThread(this);
}
labelFile.setVisibility(View.INVISIBLE);
Kernel.setManualUpdate("file",false);
}
canFile = !canFile;
}
});
The thread that must download files is UpdateFilesThread:
public class UpdateFilesThread extends Thread{
private MainActivity activity;
private final String rootPath = "/mnt/local/";
public UpdateFilesThread(MainActivity activity){
this.activity = activity;
}
public void run(){
String json = getFilesURL();
JSONObject a = (JSONObject)JSONValue.parse(json);
boolean isZip = false,canDownload = true;
String[] keys = new String[]{"key1","key2","key3","key4"};
for(String key:keys){
Object folder = (Object)a.get(key);
if(folder instanceof JSONObject){
JSONObject fold = (JSONObject)folder;
for(Object path_o:fold.keySet()){
path = path_o.toString().replace(" ", "%20");
if(local.endsWith(".php")){
isZip = true;
try {
Jsoup.connect(mywebserviceURL).data("path",path).timeout(0).post(); // If php generate zip containing php file
} catch (IOException e) {
canDownload = false;
}
}
if(canDownload){
try{
if(downloadFromUrl(path,isZip))
//SAVE URL DOWNLOADED
}catch(Exception e){
e.printStackTrace();
}
}
canDownload = true;
isZip = false;
}
}
}
a.remove(key);
}
private String getFilesURL(){
try {
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("type", new StringBody("all"));
HttpPost post = new HttpPost("mywebserviceURL");
post.setEntity(entity);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(post);
return EntityUtils.toString(response.getEntity());
} catch (UnsupportedEncodingException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (ClientProtocolException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (ParseException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (IOException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
}
}
public boolean downloadFromUrl(String path,boolean isZip){
InputStream is = null;
FileOutputStream fos = null;
String localFilename = rootPath+path;
String local = isZip?rootPath+"tmp.zip":localFilename;
boolean return_ = false;
try {
URL url = new URL(isZip?mywebserviceURLZip:mywebserviceURLZip+path);
URLConnection urlConn = url.openConnection();
urlConn.setReadTimeout(0);
is = urlConn.getInputStream();
fos = new FileOutputStream(local);
byte[] buffer = new byte[51200];
int len;
while ((len = is.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
is.close();
if(isZip){
ZipFile zip = new ZipFile(local);
zip.extractAll(rootPath);
new File(local).delete();
}
return_= true;
}catch(Exception e){
e.printStackTrace();
return false;
}
return return_;
}
}
My problem borns when user clicks two time the button ( stop downloading and start again ).
The prompt error says that the thread is already startend and in running.. how can i solve it? I know that asyncTask should be better but i've problem cause in my application there are so many thread running and the device is so poorly peforming..
It's possible to stop definitelly a thread? are there other better solution?
Try implementing an AsyncTask. When the user first taps the button call the task's execute (Params... params). On the second tap call the task's cancel (boolean mayInterruptIfRunning). Put the download functionality in the task's doInBackground (Params... params)
Your run thread needs to occasionally check isInterrupted() and exit if it returns true. Otherwise the thread will never be canceled.
I think your entire architecture is wrong though. Downloading 9000 files onto a mobile phone? Even if each file is only 1KB, that's a huge amount of memory for a mobile app. And at the very least you ought to zip up that data and download a zip, for your own sanity.
I'm trying to download a large file from my Yahoo! web site server which apparently is setup (not by me) to disconnect downloads if they are not completed within 100 seconds. The file is small enough to usually successfully transfer. On the occasions when the data rate is slow and the download gets disconnected, is there a way to resume the URLConnection at the file offset where the disconnection occurred? Here's the code:
// Setup connection.
URL url = new URL(strUrl[0]);
URLConnection cx = url.openConnection();
cx.connect();
// Setup streams and buffers.
int lengthFile = cx.getContentLength();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(strUrl[1]);
byte data[] = new byte[1024];
// Download file.
for (total=0; (count=input.read(data, 0, 1024)) != -1; total+=count) {
publishProgress((int)(total*100/lengthFile));
output.write(data, 0, count);
Log.d("AsyncDownloadFile", "bytes: " + total);
}
// Close streams.
output.flush();
output.close();
input.close();
Try using a "Range" request header:
// Open connection to URL.
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Specify what portion of file to download.
connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
// here "downloaded" is the data length already previously downloaded.
// Connect to server.
connection.connect();
Having done that, you can seek at a given point (just before the length of your download data, say X) and start writing the newly downloaded data there. Be sure to use the same value X for the range header.
Details about 14.35.2 Range Retrieval Requests
More details and source code can be found here
Here's an example code that you can use:
import java.io.*;
import java.net.*;
public class HttpUrlDownload {
public static void main(String[] args) {
String strUrl = "http://VRSDLSCEN001:80//DLS//lib//clics.jar";
String DESTINATION_PATH = "clics.jar";
int count = 0;
while (true) {
count++;
if (download(strUrl, DESTINATION_PATH) == true || count > 20) {
break;
}
}
}
public static boolean download(String strUrl, String DESTINATION_PATH) {
BufferedInputStream in = null;
FileOutputStream fos = null;
BufferedOutputStream bout = null;
URLConnection connection = null;
int downloaded = 0;
try {
System.out.println("mark ... download start");
URL url = new URL(strUrl);
connection = url.openConnection();
File file=new File(DESTINATION_PATH);
if(file.exists()){
downloaded = (int) file.length();
}
if (downloaded == 0) {
connection.connect();
}
else {
connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
connection.connect();
}
try {
in = new BufferedInputStream(connection.getInputStream());
} catch (IOException e) {
int responseCode = 0;
try {
responseCode = ((HttpURLConnection)connection).getResponseCode();
} catch (IOException e1) {
e1.printStackTrace();
}
if (responseCode == 416) {
return true;
} else {
e.printStackTrace();
return false;
}
}
fos=(downloaded==0)? new FileOutputStream(DESTINATION_PATH): new FileOutputStream(DESTINATION_PATH,true);
bout = new BufferedOutputStream(fos, 1024);
byte[] data = new byte[1024];
int x = 0;
while ((x = in.read(data, 0, 1024)) >= 0) {
bout.write(data, 0, x);
}
in.close();
bout.flush();
bout.close();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
}
}
if (bout != null) {
try {
bout.close();
} catch (IOException e) {
}
}
if (connection != null) {
((HttpURLConnection)connection).disconnect();
}
}
}
}