I have an image view , i had written swiping , at that time of swiping,the images are downloading from Internet, so i thought i have to download the images in the background before swiping , for that which i need to use asynctask or Service or IntentService, all these will help in downloading and storing in data/data/mypackages , but still swiping gets slow in my case any idea, also convey me which one is best one, is it i'm calling in a right way
1. asynctask
2. services
3. Intent Service as shown below,
i m confused which one is right method because still my problem not solved
Here's asynctask code sample snippet
public class Demo extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new FirstTask().execute(); // calling Asynctask here
}
}
Async Task code
private class FirstTask extends AsyncTask<Void, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(Catalogue.this);
int temp = 0;
// can use UI thread here
protected void onPreExecute() {
this.dialog.setMessage("Loading...");
this.dialog.setCancelable(false);
//this.dialog.show();
System.gc();
Toast.makeText(Catalogue.this, "My Async Created",
Toast.LENGTH_LONG).show();
}
#Override
protected Void doInBackground(Void... params) {
Looper.prepare();
try {
myddownloadmethod();// calling my download method
} catch (Exception e) {
Util.trace("Error in Async"+e.getMessage());
}
Looper.loop();
return null;
}
protected void onPostExecute(Void result) {
if (this.dialog.isShowing()) {
Toast.makeText(Catalogue.this, "My Async destroyed",
Toast.LENGTH_LONG).show();
Toast.makeText(Catalogue.this, "count" + temp,
Toast.LENGTH_LONG).show();
this.dialog.dismiss();
}
}
}
Here's My Service sinppet
public class MyService extends Service implements Runnable
{ #Override
public void onCreate() {
super.onCreate();
Thread mythread = new Thread(this);
mythread.start();
}
public void run() {
Looper.prepare();
try {
myddownloadmethod();// calling my download method
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Looper.loop();
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
Invoking Service
public class ServicesDemo extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(this, MyService.class));
}
}
Here's IntentService Code
public class Downloader extends IntentService {
public Downloader() {
super("Downloader");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onHandleIntent(Intent i) {
try {
myddownloadmethod();// calling my download method
} catch (Exception e1) {
// TODO Auto-generated catch block
Log.d("Error",e1.getMessage());
}
}
}
Calling IntentService from MyActivity
public class ServicesDemo extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent i1=new Intent(this, Downloader.class);
startService(i1);
}
}
The best way to download it using the service like i have done to download the file from server and put in SD card also use the notification for it.
It is quite long code but i think the perfect one,if did not understand any thing then please go to android developer blog for services.
public class DownloadService extends Service{
SharedPreferences preferences;
private static final String DOCUMENT_VIEW_STATE_PREFERENCES = "DjvuDocumentViewState";
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private NotificationManager mNM;
String downloadUrl;
public static boolean serviceState=false;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
downloadFile();
showNotification(getResources().getString(R.string.notification_catalog_downloaded),"VVS");
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
serviceState=true;
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
HandlerThread thread = new HandlerThread("ServiceStartArguments",1);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("SERVICE-ONCOMMAND","onStartCommand");
Bundle extra = intent.getExtras();
if(extra != null){
String downloadUrl = extra.getString("downloadUrl");
Log.d("URL",downloadUrl);
this.downloadUrl=downloadUrl;
}
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public void onDestroy() {
Log.d("SERVICE-DESTROY","DESTORY");
serviceState=false;
//Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
public void downloadFile(){
downloadFile(this.downloadUrl,fileName);
}
void showNotification(String message,String title) {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = message;
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.icon, "vvs",
System.currentTimeMillis());
notification.flags |= Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(this, HomeScreenActivity.class);
intent.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP);
//The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this.getBaseContext(), 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, title,
text, contentIntent);
// Send the notification.
// We use a layout id because it is a unique number. We use it later to cancel.
mNM.notify(R.string.app_name, notification);
}
public void downloadFile(String fileURL, String fileName) {
StatFs stat_fs = new StatFs(Environment.getExternalStorageDirectory().getPath());
double avail_sd_space = (double)stat_fs.getAvailableBlocks() *(double)stat_fs.getBlockSize();
//double GB_Available = (avail_sd_space / 1073741824);
double MB_Available = (avail_sd_space / 10485783);
//System.out.println("Available MB : " + MB_Available);
Log.d("MB",""+MB_Available);
try {
File root =new File(Environment.getExternalStorageDirectory()+"/vvveksperten");
if(root.exists() && root.isDirectory()) {
}else{
root.mkdir();
}
Log.d("CURRENT PATH",root.getPath());
URL u = new URL(fileURL);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
int fileSize = c.getContentLength()/1048576;
Log.d("FILESIZE",""+fileSize);
if(MB_Available <= fileSize ){
this.showNotification(getResources().getString(R.string.notification_no_memory),getResources().getString(R.string.notification_error));
c.disconnect();
return;
}
FileOutputStream f = new FileOutputStream(new File(root.getPath(), fileName));
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = in.read(buffer)) > 0) {
f.write(buffer, 0, len1);
}
f.close();
File file = new File(root.getAbsolutePath() + "/" + "some.pdf");
if(file.exists()){
file.delete();
Log.d("FILE-DELETE","YES");
}else{
Log.d("FILE-DELETE","NO");
}
File from =new File(root.getAbsolutePath() + "/" + fileName);
File to = new File(root.getAbsolutePath() + "/" + "some.pdf");
} catch (Exception e) {
Log.d("Downloader", e.getMessage());
}
For anyone running into this question later, take a look at the async download mechanism used in the android sample code for the project com.example.android.bitmapfun.ui.ImageGridActivity. It downloads images asynchronously and also caches them for offline display in an ImageView. Folks have wrapped their code around this one and made image loading libraries of their own. These libraries use an AsyncTask instead of a service. Async tasks are expected to wrap up their work within a couple of seconds.
If you are looking to download something larger, I'd recommend the DownloadManager that is available since API 9 instead of using services. There is a lot of code in there that adds resilience to the download.
The download manager is a system service that handles long-running HTTP downloads. Clients may request that a URI be downloaded to a particular destination file. The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots. Instances of this class should be obtained through getSystemService(String) by passing DOWNLOAD_SERVICE. Apps that request downloads through this API should register a broadcast receiver for ACTION_NOTIFICATION_CLICKED to appropriately handle when the user clicks on a running download in a notification or from the downloads UI. Note that the application must have the INTERNET permission to use this class.
You are probably over engineering this. I have implemented swiping with dynamically loading images and I just a use a simple utility class that does it all for me via static method call.
Try this class:
package com.beget.consumer.util;
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ImageView;
public class DrawableLoader {
private final Map<String, Drawable> drawableMap;
private WeakReference<ImageView> imageViewReference;
public DrawableLoader() {
drawableMap = new HashMap<String, Drawable>();
}
public Drawable fetchDrawable(String urlString) {
if (drawableMap.containsKey(urlString)) {
return drawableMap.get(urlString);
}
Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
try {
InputStream is = fetch(urlString);
Drawable drawable = Drawable.createFromStream(is, "src");
drawableMap.put(urlString, drawable);
Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
+ drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
+ drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
return drawable;
} catch (MalformedURLException e) {
Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
return null;
} catch (IOException e) {
Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
return null;
}
}
public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
if (drawableMap.containsKey(urlString)) {
imageViewReference.get().setImageDrawable(drawableMap.get(urlString));
}
final Handler handler = new Handler() {
#Override
public void handleMessage(Message message) {
imageViewReference.get().setImageDrawable((Drawable) message.obj);
}
};
Thread thread = new Thread() {
#Override
public void run() {
//TODO : set imageView to a "pending" image
Drawable drawable = fetchDrawable(urlString);
Message message = handler.obtainMessage(1, drawable);
handler.sendMessage(message);
}
};
thread.start();
}
private InputStream fetch(String urlString) throws MalformedURLException, IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
}
This is all you need. Then when you need to load an image, you call:
fetchDrawableOnThread("http://path/to/your/image.jpg", yourImageViewReference);
That's it.
If you have an URL from a JSON object, parse the URL into your string so:
String url = jsonObj.getString("url");
Then call fetchDrawableOnThread(url, yourImageViewReference);
Use volley.
Using volley network image view you can do this
we use latest architecure components here.We make some observers with live data for some flag that represents download status.In service we download the image and completing we update the live data so that the observers method automatically called
Related
I am trying to write a simple application that gets updated. For this I need a simple function that can download a file and show the current progress in a ProgressDialog. I know how to do the ProgressDialog, but I'm not sure how to display the current progress and how to download the file in the first place.
There are many ways to download files. Following I will post most common ways; it is up to you to decide which method is better for your app.
Use AsyncTask and show the download progress in a dialog
=============================================================
This method will allow you to execute some background processes and update the UI at the same time (in this case, we'll update a progress bar).
Imports:
import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
This is an example code:
// declare the dialog as a member field of your activity
ProgressDialog mProgressDialog;
// instantiate it within the onCreate method
mProgressDialog = new ProgressDialog(YourActivity.this);
mProgressDialog.setMessage("A message");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(true);
// execute this when the downloader must be fired
final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");
mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
downloadTask.cancel(true); //cancel the task
}
});
The AsyncTask will look like this:
// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> {
private Context context;
private PowerManager.WakeLock mWakeLock;
public DownloadTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... sUrl) {
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();
}
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/file_name.extension");
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
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();
}
return null;
}
The method above (doInBackground) runs always on a background thread. You shouldn't do any UI tasks there. On the other hand, the onProgressUpdate and onPreExecute run on the UI thread, so there you can change the progress bar:
#Override
protected void onPreExecute() {
super.onPreExecute();
// 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);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
getClass().getName());
mWakeLock.acquire();
mProgressDialog.show();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
// if we get here, length is known, now set indeterminate to false
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgress(progress[0]);
}
#Override
protected void onPostExecute(String result) {
mWakeLock.release();
mProgressDialog.dismiss();
if (result != null)
Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
else
Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
}
}
For this to run, you need the WAKE_LOCK permission.
<uses-permission android:name="android.permission.WAKE_LOCK" />
Download from Service
========================
The big question here is: how do I update my activity from a service?. In the next example we are going to use two classes you may not be aware of: ResultReceiver and IntentService. ResultReceiver is the one that will allow us to update our thread from a service; IntentService is a subclass of Service which spawns a thread to do background work from there (you should know that a Service runs actually in the same thread of your app; when you extends Service, you must manually spawn new threads to run CPU blocking operations).
Download service can look like this:
public class DownloadService extends IntentService {
public static final int UPDATE_PROGRESS = 8344;
public DownloadService() {
super("DownloadService");
}
#Override
protected void onHandleIntent(Intent intent) {
String urlToDownload = intent.getStringExtra("url");
ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
try {
//create url and connect
URL url = new URL(urlToDownload);
URLConnection connection = url.openConnection();
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(connection.getInputStream());
String path = "/sdcard/BarcodeScanner-debug.apk" ;
OutputStream output = new FileOutputStream(path);
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
Bundle resultData = new Bundle();
resultData.putInt("progress" ,(int) (total * 100 / fileLength));
receiver.send(UPDATE_PROGRESS, resultData);
output.write(data, 0, count);
}
// close streams
output.flush();
output.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
Bundle resultData = new Bundle();
resultData.putInt("progress" ,100);
receiver.send(UPDATE_PROGRESS, resultData);
}
}
Add the service to your manifest:
<service android:name=".DownloadService"/>
And the activity will look like this:
// initialize the progress dialog like in the first example
// this is how you fire the downloader
mProgressDialog.show();
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("url", "url of the file to download");
intent.putExtra("receiver", new DownloadReceiver(new Handler()));
startService(intent);
Here is were ResultReceiver comes to play:
private class DownloadReceiver extends ResultReceiver{
public DownloadReceiver(Handler handler) {
super(handler);
}
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
if (resultCode == DownloadService.UPDATE_PROGRESS) {
int progress = resultData.getInt("progress"); //get the progress
dialog.setProgress(progress);
if (progress == 100) {
dialog.dismiss();
}
}
}
}
2.1 Use Groundy library
Groundy is a library that basically helps you run pieces of code in a background service, and it is based on the ResultReceiver concept shown above. This library is deprecated at the moment. This is how the whole code would look like:
The activity where you are showing the dialog...
public class MainActivity extends Activity {
private ProgressDialog mProgressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
String url = ((EditText) findViewById(R.id.edit_url)).getText().toString().trim();
Bundle extras = new Bundler().add(DownloadTask.PARAM_URL, url).build();
Groundy.create(DownloadExample.this, DownloadTask.class)
.receiver(mReceiver)
.params(extras)
.queue();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
});
}
private ResultReceiver mReceiver = new ResultReceiver(new Handler()) {
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
switch (resultCode) {
case Groundy.STATUS_PROGRESS:
mProgressDialog.setProgress(resultData.getInt(Groundy.KEY_PROGRESS));
break;
case Groundy.STATUS_FINISHED:
Toast.makeText(DownloadExample.this, R.string.file_downloaded, Toast.LENGTH_LONG);
mProgressDialog.dismiss();
break;
case Groundy.STATUS_ERROR:
Toast.makeText(DownloadExample.this, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show();
mProgressDialog.dismiss();
break;
}
}
};
}
A GroundyTask implementation used by Groundy to download the file and show the progress:
public class DownloadTask extends GroundyTask {
public static final String PARAM_URL = "com.groundy.sample.param.url";
#Override
protected boolean doInBackground() {
try {
String url = getParameters().getString(PARAM_URL);
File dest = new File(getContext().getFilesDir(), new File(url).getName());
DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this));
return true;
} catch (Exception pokemon) {
return false;
}
}
}
And just add this to the manifest:
<service android:name="com.codeslap.groundy.GroundyService"/>
It couldn't be easier I think. Just grab the latest jar from Github and you are ready to go. Keep in mind that Groundy's main purpose is to make calls to external REST apis in a background service and post results to the UI with easily. If you are doing something like that in your app, it could be really useful.
2.2 Use https://github.com/koush/ion
Use DownloadManager class (GingerBread and newer only)
=============================================================
GingerBread brought a new feature, DownloadManager, which allows you to download files easily and delegate the hard work of handling threads, streams, etc. to the system.
First, let's see a utility method:
/**
* #param context used to check the device version and DownloadManager information
* #return true if the download manager is available
*/
public static boolean isDownloadManagerAvailable(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
return true;
}
return false;
}
Method's name explains it all. Once you are sure DownloadManager is available, you can do something like this:
String url = "url you want to download";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Some descrition");
request.setTitle("Some title");
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");
// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
Download progress will be showing in the notification bar.
Final thoughts
First and second methods are just the tip of the iceberg. There are lots of things you have to keep in mind if you want your app to be robust. Here is a brief list:
You must check whether user has an internet connection available
Make sure you have the right permissions (INTERNET and WRITE_EXTERNAL_STORAGE); also ACCESS_NETWORK_STATE if you want to check internet availability.
Make sure the directory were you are going to download files exist and has write permissions.
If download is too big you may want to implement a way to resume the download if previous attempts failed.
Users will be grateful if you allow them to interrupt the download.
Unless you need detailed control of the download process, then consider using DownloadManager (3) because it already handles most of the items listed above.
But also consider that your needs may change. For example, DownloadManager does no response caching. It will blindly download the same big file multiple times. There's no easy way to fix it after the fact. Where if you start with a basic HttpURLConnection (1, 2), then all you need is to add an HttpResponseCache. So the initial effort of learning the basic, standard tools can be a good investment.
This class was deprecated in API level 26. ProgressDialog is a modal
dialog, which prevents the user from interacting with the app. Instead
of using this class, you should use a progress indicator like
ProgressBar, which can be embedded in your app's UI. Alternatively,
you can use a notification to inform the user of the task's progress. For more details Link
Don't forget to add permissions to your manifest file if you're gonna be downloading stuff from the internet!
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.helloandroid"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<application
android:icon="#drawable/icon"
android:label="#string/app_name"
android:debuggable="true">
</application>
</manifest>
Yes the code above will work .But if you are updating your progressbar in onProgressUpdate of Asynctask and you press back button or finish your activity AsyncTask looses its track with your UI .And when you go back to your activity, even if download is running in background you will see no update on progressbar. So on OnResume() try to run a thread like runOnUIThread with a timer task that updates ur progressbar with values updating from the AsyncTask running background.
private void updateProgressBar(){
Runnable runnable = new updateProgress();
background = new Thread(runnable);
background.start();
}
public class updateProgress implements Runnable {
public void run() {
while(Thread.currentThread()==background)
//while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
Message msg = new Message();
progress = getProgressPercentage();
handler.sendMessage(msg);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
}
}
}
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
progress.setProgress(msg.what);
}
};
Don't forget to Destroy the thread when ur activity is not visible.
private void destroyRunningThreads() {
if (background != null) {
background.interrupt();
background=null;
}
}
I'd recommend you to use my Project Netroid, It's based on Volley. I have added some features to it such as multi-events callback, file download management. This could be of some help.
I have modified AsyncTask class to handle creation of progressDialog at the same context .I think following code will be more reusable.
(it can be called from any activity just pass context,target File,dialog message)
public static class DownloadTask extends AsyncTask<String, Integer, String> {
private ProgressDialog mPDialog;
private Context mContext;
private PowerManager.WakeLock mWakeLock;
private File mTargetFile;
//Constructor parameters :
// #context (current Activity)
// #targetFile (File object to write,it will be overwritten if exist)
// #dialogMessage (message of the ProgresDialog)
public DownloadTask(Context context,File targetFile,String dialogMessage) {
this.mContext = context;
this.mTargetFile = targetFile;
mPDialog = new ProgressDialog(context);
mPDialog.setMessage(dialogMessage);
mPDialog.setIndeterminate(true);
mPDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mPDialog.setCancelable(true);
// reference to instance to use inside listener
final DownloadTask me = this;
mPDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
me.cancel(true);
}
});
Log.i("DownloadTask","Constructor done");
}
#Override
protected String doInBackground(String... sUrl) {
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();
}
Log.i("DownloadTask","Response " + connection.getResponseCode());
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream(mTargetFile,false);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
Log.i("DownloadTask","Cancelled");
input.close();
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();
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
getClass().getName());
mWakeLock.acquire();
mPDialog.show();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
// if we get here, length is known, now set indeterminate to false
mPDialog.setIndeterminate(false);
mPDialog.setMax(100);
mPDialog.setProgress(progress[0]);
}
#Override
protected void onPostExecute(String result) {
Log.i("DownloadTask", "Work Done! PostExecute");
mWakeLock.release();
mPDialog.dismiss();
if (result != null)
Toast.makeText(mContext,"Download error: "+result, Toast.LENGTH_LONG).show();
else
Toast.makeText(mContext,"File Downloaded", Toast.LENGTH_SHORT).show();
}
}
Do not forget to replace "/sdcard..." by new File("/mnt/sdcard/...") otherwise you will get a FileNotFoundException
While I was starting to learn android development, I had learnt that ProgressDialog is the way to go. There is the setProgress method of ProgressDialog which can be invoked to update the progress level as the file gets downloaded.
The best I have seen in many apps is that they customize this progress dialog's attributes to give a better look and feel to the progress dialog than the stock version. Good to keeping the user engaged with some animation of like frog, elephant or cute cats/puppies. Any animation with in the progress dialog attracts users and they don't feel like being kept waiting for long.
We can use the coroutine and work manager for downloading files in kotlin.
Add a dependency in build.gradle
implementation "androidx.work:work-runtime-ktx:2.3.0-beta01"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1"
WorkManager class
import android.content.Context
import android.os.Environment
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.sa.chat.utils.Const.BASE_URL_IMAGE
import com.sa.chat.utils.Constants
import kotlinx.coroutines.delay
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
import java.net.URL
class DownloadMediaWorkManager(appContext: Context, workerParams: WorkerParameters)
: CoroutineWorker(appContext, workerParams) {
companion object {
const val WORK_TYPE = "WORK_TYPE"
const val WORK_IN_PROGRESS = "WORK_IN_PROGRESS"
const val WORK_PROGRESS_VALUE = "WORK_PROGRESS_VALUE"
}
override suspend fun doWork(): Result {
val imageUrl = inputData.getString(Constants.WORK_DATA_MEDIA_URL)
val imagePath = downloadMediaFromURL(imageUrl)
return if (!imagePath.isNullOrEmpty()) {
Result.success(workDataOf(Constants.WORK_DATA_MEDIA_URL to imagePath))
} else {
Result.failure()
}
}
private suspend fun downloadMediaFromURL(imageUrl: String?): String? {
val file = File(
getRootFile().path,
"IMG_${System.currentTimeMillis()}.jpeg"
)
val url = URL(BASE_URL_IMAGE + imageUrl)
val connection = url.openConnection()
connection.connect()
val lengthOfFile = connection.contentLength
// download the file
val input = BufferedInputStream(url.openStream(), 8192)
// Output stream
val output = FileOutputStream(file)
val data = ByteArray(1024)
var total: Long = 0
var last = 0
while (true) {
val count = input.read(data)
if (count == -1) break
total += count.toLong()
val progress = (total * 100 / lengthOfFile).toInt()
if (progress % 10 == 0) {
if (last != progress) {
setProgress(workDataOf(WORK_TYPE to WORK_IN_PROGRESS,
WORK_PROGRESS_VALUE to progress))
}
last = progress
delay(50)
}
output.write(data, 0, count)
}
output.flush()
output.close()
input.close()
return file.path
}
private fun getRootFile(): File {
val rootDir = File(Environment.getExternalStorageDirectory().absolutePath + "/AppName")
if (!rootDir.exists()) {
rootDir.mkdir()
}
val dir = File("$rootDir/${Constants.IMAGE_FOLDER}/")
if (!dir.exists()) {
dir.mkdir()
}
return File(dir.absolutePath)
}
}
Start downloading through work manager in activity class
private fun downloadImage(imagePath: String?, id: String) {
val data = workDataOf(WORK_DATA_MEDIA_URL to imagePath)
val downloadImageWorkManager = OneTimeWorkRequestBuilder<DownloadMediaWorkManager>()
.setInputData(data)
.addTag(id)
.build()
WorkManager.getInstance(this).enqueue(downloadImageWorkManager)
WorkManager.getInstance(this).getWorkInfoByIdLiveData(downloadImageWorkManager.id)
.observe(this, Observer { workInfo ->
if (workInfo != null) {
when {
workInfo.state == WorkInfo.State.SUCCEEDED -> {
progressBar?.visibility = View.GONE
ivDownload?.visibility = View.GONE
}
workInfo.state == WorkInfo.State.FAILED || workInfo.state == WorkInfo.State.CANCELLED || workInfo.state == WorkInfo.State.BLOCKED -> {
progressBar?.visibility = View.GONE
ivDownload?.visibility = View.VISIBLE
}
else -> {
if(workInfo.progress.getString(WORK_TYPE) == WORK_IN_PROGRESS){
val progress = workInfo.progress.getInt(WORK_PROGRESS_VALUE, 0)
progressBar?.visibility = View.VISIBLE
progressBar?.progress = progress
ivDownload?.visibility = View.GONE
}
}
}
}
})
}
My personal advice is to use Progress Dialog and build up before execution , or initiate at OnPreExecute() , publish progress often if you use horizontal style of progress bar of the progress dialog. The remaining part is to optimize the algorithm of doInBackground.
Use Android Query library, very cool indeed.You can change it to use ProgressDialog as you see in other examples, this one will show progress view from your layout and hide it after completion.
File target = new File(new File(Environment.getExternalStorageDirectory(), "ApplicationName"), "tmp.pdf");
new AQuery(this).progress(R.id.progress_view).download(_competition.qualificationScoreCardsPdf(), target, new AjaxCallback<File>() {
public void callback(String url, File file, AjaxStatus status) {
if (file != null) {
// do something with file
}
}
});
Permissions
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Using HttpURLConnection
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class DownloadFileUseHttpURLConnection extends Activity {
ProgressBar pb;
Dialog dialog;
int downloadedSize = 0;
int totalSize = 0;
TextView cur_val;
String dwnload_file_path =
"http://coderzheaven.com/sample_folder/sample_file.png";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button b = (Button) findViewById(R.id.b1);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
showProgress(dwnload_file_path);
new Thread(new Runnable() {
public void run() {
downloadFile();
}
}).start();
}
});
}
void downloadFile(){
try {
URL url = new URL(dwnload_file_path);
HttpURLConnection urlConnection = (HttpURLConnection)
url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
//connect
urlConnection.connect();
//set the path where we want to save the file
File SDCardRoot = Environment.getExternalStorageDirectory();
//create a new file, to save the downloaded file
File file = new File(SDCardRoot,"downloaded_file.png");
FileOutputStream fileOutput = new FileOutputStream(file);
//Stream used for reading the data from the internet
InputStream inputStream = urlConnection.getInputStream();
//this is the total size of the file which we are downloading
totalSize = urlConnection.getContentLength();
runOnUiThread(new Runnable() {
public void run() {
pb.setMax(totalSize);
}
});
//create a buffer...
byte[] buffer = new byte[1024];
int bufferLength = 0;
while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
fileOutput.write(buffer, 0, bufferLength);
downloadedSize += bufferLength;
// update the progressbar //
runOnUiThread(new Runnable() {
public void run() {
pb.setProgress(downloadedSize);
float per = ((float)downloadedSize/totalSize) *
100;
cur_val.setText("Downloaded " + downloadedSize +
"KB / " + totalSize + "KB (" + (int)per + "%)" );
}
});
}
//close the output stream when complete //
fileOutput.close();
runOnUiThread(new Runnable() {
public void run() {
// pb.dismiss(); // if you want close it..
}
});
} catch (final MalformedURLException e) {
showError("Error : MalformedURLException " + e);
e.printStackTrace();
} catch (final IOException e) {
showError("Error : IOException " + e);
e.printStackTrace();
}
catch (final Exception e) {
showError("Error : Please check your internet connection " +
e);
}
}
void showError(final String err){
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(DownloadFileDemo1.this, err,
Toast.LENGTH_LONG).show();
}
});
}
void showProgress(String file_path){
dialog = new Dialog(DownloadFileDemo1.this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.myprogressdialog);
dialog.setTitle("Download Progress");
TextView text = (TextView) dialog.findViewById(R.id.tv1);
text.setText("Downloading file from ... " + file_path);
cur_val = (TextView) dialog.findViewById(R.id.cur_pg_tv);
cur_val.setText("Starting download...");
dialog.show();
pb = (ProgressBar)dialog.findViewById(R.id.progress_bar);
pb.setProgress(0);
pb.setProgressDrawable(
getResources().getDrawable(R.drawable.green_progress));
}
}
I am adding another answer for other solution I am using now because Android Query is so big and unmaintained to stay healthy. So i moved to this https://github.com/amitshekhariitbhu/Fast-Android-Networking.
AndroidNetworking.download(url,dirPath,fileName).build()
.setDownloadProgressListener(new DownloadProgressListener() {
public void onProgress(long bytesDownloaded, long totalBytes) {
bar.setMax((int) totalBytes);
bar.setProgress((int) bytesDownloaded);
}
}).startDownload(new DownloadListener() {
public void onDownloadComplete() {
...
}
public void onError(ANError error) {
...
}
});
You can observer the progress of the download manager using LiveData and coroutines, see the gist below
https://gist.github.com/FhdAlotaibi/678eb1f4fa94475daf74ac491874fc0e
data class DownloadItem(val bytesDownloadedSoFar: Long = -1, val totalSizeBytes: Long = -1, val status: Int)
class DownloadProgressLiveData(private val application: Application, private val requestId: Long) : LiveData<DownloadItem>(), CoroutineScope {
private val downloadManager by lazy {
application.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
}
private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override fun onActive() {
super.onActive()
launch {
while (isActive) {
val query = DownloadManager.Query().setFilterById(requestId)
val cursor = downloadManager.query(query)
if (cursor.moveToFirst()) {
val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
Timber.d("Status $status")
when (status) {
DownloadManager.STATUS_SUCCESSFUL,
DownloadManager.STATUS_PENDING,
DownloadManager.STATUS_FAILED,
DownloadManager.STATUS_PAUSED -> postValue(DownloadItem(status = status))
else -> {
val bytesDownloadedSoFar = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
val totalSizeBytes = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
postValue(DownloadItem(bytesDownloadedSoFar.toLong(), totalSizeBytes.toLong(), status))
}
}
if (status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED)
cancel()
} else {
postValue(DownloadItem(status = DownloadManager.STATUS_FAILED))
cancel()
}
cursor.close()
delay(300)
}
}
}
override fun onInactive() {
super.onInactive()
job.cancel()
}
}
Important
AsyncTask is deprecated in Android 11.
For more information please checkout following posts
Android AsyncTask API deprecating in Android 11.What are the alternatives?
https://developer.android.com/reference/android/os/AsyncTask
Probably should move to concorency Framework as suggested by google
private class DownloadTask extends AsyncTask<String, Integer, String> {
private PowerManager.WakeLock mWakeLock;
String onlinePathBundle, onlinePathMusic, offlinePathBundle, offlinePathMusic;
CircleProgressBar progressBar;
RelativeLayout rl_progress;
ImageView btn_download;
TextView tv_progress;
public DownloadTask(String onlinePathBundle, String onlinePathMusic, String offlinePathBundle, String offlinePathMusic, CircleProgressBar progressBar, RelativeLayout rl_progress, ImageView btn_download,
TextView tv_progress) {
this.offlinePathBundle = offlinePathBundle;
this.offlinePathMusic = offlinePathMusic;
this.progressBar = progressBar;
this.rl_progress = rl_progress;
this.btn_download = btn_download;
this.tv_progress = tv_progress;
this.onlinePathBundle = onlinePathBundle;
this.onlinePathMusic = onlinePathMusic;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setMax(100);
rl_progress.setVisibility(View.VISIBLE);
btn_download.setVisibility(View.GONE);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
mWakeLock.acquire();
}
#Override
protected String doInBackground(String... sUrl) {
String firstResult = downTask(onlinePathBundle, 1, offlinePathBundle);
String seondResult = downTask(onlinePathMusic, 2, offlinePathMusic);
if (firstResult != null) {
Toast.makeText(SplashActivity.this, "Download error: " + firstResult, Toast.LENGTH_LONG).show();
return firstResult;
} else {
return seondResult;
}
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
progressBar.setProgress(progress[0]);
tv_progress.setText(progress[0] + "%");
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
rl_progress.setVisibility(View.GONE);
btn_download.setVisibility(View.VISIBLE);
if (result != null) {
Toast.makeText(SplashActivity.this, "Download error: " + result, Toast.LENGTH_LONG).show();
} else {
rl_progress.setVisibility(View.GONE);
btn_download.setVisibility(View.GONE);
}
}
public String downTask(String onlineNewPath, int numberOfTask, String offlineNewPath) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(onlineNewPath);
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();
}
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream(offlineNewPath);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
return null;
}
total += count;
// publishing the progress....
if (fileLength > 0) {// only if total length is known
if (numberOfTask == 1) {
publishProgress((int) (total * 50 / fileLength));
} else if (numberOfTask == 2) {
publishProgress(((int) (total * 50 / fileLength)) + 50);
}
}
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();
}
return null;
}
}
I have came across a Simple File Download library
Fetch and importantly it has Storage Access Framework, Content Provider and URI support. If anyone is still searching might found it helpful.
implementation "androidx.tonyodev.fetch2:xfetch2:3.1.6" //AndroidX
implementation "com.tonyodev.fetch2:fetch2:3.0.12" //Support lib
Required permissions in case your are not using app specific directory.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Internet permission
<uses-permission android:name="android.permission.INTERNET"/>
private Fetch fetch;
FetchConfiguration fetchConfiguration = new FetchConfiguration.Builder(this)
.setDownloadConcurrentLimit(3)//Concurrent Download limit
.build();
fetch = Fetch.Impl.getInstance(fetchConfiguration);
String url = "http:www.example.com/test.txt";//URL of file
String file = "/downloads/test.txt";//Path of file
final Request request = new Request(url, file);
request.setPriority(Priority.HIGH);
request.setNetworkType(NetworkType.ALL);//Preferred network type
request.addHeader("clientKey", "SD78DF93_3947&MVNGHE1WONG");//Auth header if any
fetch.enqueue(request, updatedRequest -> {
//Request was successfully enqueued for download.
}, error -> {
//An error occurred enqueuing the request.
});
}
Listen for update and progress
FetchListener fetchListener = new FetchListener() {
#Override
public void onQueued(#NotNull Download download, boolean waitingOnNetwork) {
if (request.getId() == download.getId()) {
showDownloadInList(download);
}
}
#Override
public void onCompleted(#NotNull Download download) {
}
#Override
public void onError(#NotNull Download download) {
Error error = download.getError();
}
#Override
public void onProgress(#NotNull Download download, long etaInMilliSeconds, long downloadedBytesPerSecond) {
if (request.getId() == download.getId()) {
updateDownload(download, etaInMilliSeconds);
}
int progress = download.getProgress();
}
#Override
public void onPaused(#NotNull Download download) {
}
#Override
public void onResumed(#NotNull Download download) {
}
#Override
public void onCancelled(#NotNull Download download) {
}
#Override
public void onRemoved(#NotNull Download download) {
}
#Override
public void onDeleted(#NotNull Download download) {
}
};
fetch.addListener(fetchListener);
//Remove listener when done.
fetch.removeListener(fetchListener);
This example code is taken from the owner page all credit goes to Tonyo Francis
I have good concept of starting and using the basic service. I mean not to complicated. In My app I want a service which should not be killed in any situation and should download some files from the server then it should call stopSelf. I have made my service in the following way. But before sharing its whole code just let me tell you what I am doing
In Service I am passing the series of url (string array) which has to download all files from the server.
I am using the async task to download from the server.
Under this whole process I am getting a 1st response that is in xml then I parse it , and get the JSON string (sorry about that my web service designer is a numb like me). so after these two conversion I store the data in the database and then starts downloading files and saving them to device and store their path in the database. (this all works fine)
I am calculating and updating progress in the notification bar. (showing user how much the files has been downloaded)
what I really want
I want that my service should not be killed when user removes it from the recent app list , so that it should continue to download and continue to update the status in notification bar. I am using Notification manager to update the progress.
What is really happening
When I close my app from recent app tray, I think my service gets killed and the downloading process stops, and It also stops updating the progress of notification in notification bar, Where As I want it to continue to run until the download process is finished.
Here is my code it is simplified as some methods are really not worthy
to be discussed here Such as Parsing the xml or JSON
Here is the Code
public class MyDemoService extends Service {
private static final String TAG = "MyDemoService";
private static final int NOTIFICATION_ID = 1;
private LocalBinder m_binder = new LocalBinder();
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
myAsyncTask myWebFetch;
// Timer to update the ongoing notification
private final long mFrequency = 100; // milliseconds
private final int TICK_WHAT = 2;
public class LocalBinder extends Binder {
MyDemoService getService() {
return MyDemoService.this;
}
}
private Handler mHandler = new Handler() {
public void handleMessage(Message m) {
updateNotification();
sendMessageDelayed(Message.obtain(this, TICK_WHAT), mFrequency);
}
};
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "bound");
return m_binder;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "created");
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.d(TAG, "Removed");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Destroyed");
}
public void updateNotification() {
// Log.d(TAG, "updating notification");
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
}
public void hideNotification() {
Log.d(TAG, "removing notification");
mNotifyManager.cancel(NOTIFICATION_ID);
mHandler.removeMessages(TICK_WHAT);
}
public void start() {
Log.d(TAG, "start");
mBuilder =
new NotificationCompat.Builder(MyDemoService.this)
.setSmallIcon(R.drawable.download)
.setContentTitle("SMU")
.setContentText("Downloading Images");
Intent targetIntent = new Intent(MyDemoService.this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(MyDemoService.this, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(contentIntent);
mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
myWebFetch = new myAsyncTask();
myWebFetch.execute();
}
class myAsyncTask extends AsyncTask<String, Integer, Void> {
MyDB myDB;
myAsyncTask() {
myDB = new MyDB(MyDemoService.this);
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
mBuilder.setContentText("Download complete");
// Removes the progress bar
mBuilder.setProgress(0, 0, false);
mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mBuilder.setProgress(100, values[0], false);
mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
}
#Override
protected Void doInBackground(String... params) {
//set the download URL, a url that points to a file on the internet
getJSON("http://*****", 1000000);
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mBuilder.setProgress(100, 0, false);
mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
}
public void getJSON(String url, int timeout) {
HttpURLConnection c = null;
try {
URL u = new URL(url);
c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setUseCaches(false);
c.setAllowUserInteraction(false);
c.setConnectTimeout(timeout);
c.setReadTimeout(timeout);
c.setInstanceFollowRedirects(false);
c.connect();
int status = c.getResponseCode();
if (status == 200) {
String readStream = readStream(c.getInputStream());
if (readStream != null) {
JsonParser mJsonParser = new JsonParser(MyDemoService.this);
mJsonParser.parseJaSon(readStream);
ArrayList<SuitDetails> mImageList = new ArrayList<>(myDB.GetAllData());
if (mImageList != null) {
//NOW HERE DOWNLOADING IMAGES FROM URL WE GOT SAVED IN DB AFTER PARSING
downloadImages(mImageList);
}
}
}
} catch (MalformedURLException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} finally {
if (c != null) {
try {
c.disconnect();
} catch (Exception ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
}
}
}
}
#TargetApi(Build.VERSION_CODES.KITKAT)
private String readStream(InputStream in) {
//parsing my input stream and sending back string
return jsonString.toString();
}
void downloadImages(ArrayList<SuitDetails> arrayList) {
try {
ArrayList<SuitDetails> imageUrl = arrayList;
URL url;
float progressImages = 0;
HttpURLConnection urlConnection = null;
for (int i = 0; i < imageUrl.size(); i++) {
progressImages += 100 / imageUrl.size();
publishProgress((int) progressImages);
url = new URL(imageUrl.get(i).getPath().toString());
//create the new connection
urlConnection = (HttpURLConnection) url.openConnection();
//set up some things on the connection
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(false);
urlConnection.setUseCaches(false);
urlConnection.setAllowUserInteraction(false);
urlConnection.setConnectTimeout(60000);
urlConnection.setReadTimeout(60000);
urlConnection.setInstanceFollowRedirects(false);
//and connect!
urlConnection.connect();
File storagePath = new File(MyDemoService.this.getExternalFilesDir("TEST") + "/Mytest");
storagePath.mkdirs();
String finalName = imageUrl.get(i).getImageName();
File myImage = new File(storagePath, finalName + ".png");
FileOutputStream fileOutput = new FileOutputStream(myImage);
InputStream inputStream = urlConnection.getInputStream();
int totalSize = urlConnection.getContentLength();
int downloadedSize = 0;
byte[] buffer = new byte[1024];
int bufferLength = 0;
while ((bufferLength = inputStream.read(buffer)) > 0) {
//add the data in the buffer to the file in the file output stream (the file on the sd card
fileOutput.write(buffer, 0, bufferLength);
//add up the size so we know how much is downloaded
downloadedSize += bufferLength;
//this is where you would do something to report the prgress, like this maybe
}
//close the output stream when done
ContentValues contentValues = new ContentValues();
contentValues.put("Status", "1");
contentValues.put("Path", myImage.getPath().toString());
myDB.UpdateDownloadStatus(contentValues, imageUrl.get(i).getSImageID());
fileOutput.close();
}
myDB.closeDb();
//catch some possible errors...
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I Know this is length code but sharing if You want to analyse it deeply.
I will provide how I am using and calling this service in MainActivity if you demand it
why are you not using an IntentService if you want to do network stuff?
you should consider adding setIntentRedelivery(true); in your constructor
from the documentation
Sets intent redelivery preferences. Usually called from the
constructor with your preferred semantics.
If enabled is true, onStartCommand(Intent, int, int) will return
START_REDELIVER_INTENT, so if this process dies before
onHandleIntent(Intent) returns, the process will be restarted and the
intent redelivered. If multiple Intents have been sent, only the most
recent one is guaranteed to be redelivered.
If enabled is false (the default), onStartCommand(Intent, int, int)
will return START_NOT_STICKY, and if the process dies, the Intent dies
along with it.
I have a URL for a web page, and I want to take a 'screenshot' of this web page in the background, eg. in a Service, and without showing a UI to the user.
I have tried to create a WebView in my Service, and then use the capturePicture() method to get the screenshot when the page has finished loading, but the created Picture (and the Bitmap I create from it ) is always empty. (This works perfectly in a normal Activity, but not in my background Service).
Any way to get this to work, or an alternative way to get a 'screenshot' of a webpage without having a UI ?
Note: This answer is old - the latest Android version I've tried this on is 4.4, YMMV on other Android versions or devices I did not test this on... This is also a super-kludgy hack - nowdays I'd recommend using a web service / API for this.
Figured it out, I have to set the 'size' of the WebView, so that the resulting 'Screenshot' is not 0 x 0 size. Then I have to get the bitmap directly from the WebView's drawing cache, as capturePicture() does not seem to work here.
package com.example.screenshot;
import android.app.*;
import android.content.*;
import android.widget.*;
import android.util.*;
import android.webkit.*;
import android.graphics.*;
import java.io.*;
import android.view.View.*;
import android.os.*;
import android.os.Process;
//this is an example of how to take a screenshot in a background service
//not very elegant, but it works (for me anyway)
public class ScreenshotService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private Message msg;
private WebView webview;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
webview = new WebView(ScreenshotService.this);
//without this toast message, screenshot will be blank, dont ask me why...
Toast.makeText(ScreenshotService.this, "Taking screenshot...", Toast.LENGTH_SHORT).show();
// This is the important code :)
webview.setDrawingCacheEnabled(true);
//width x height of your webview and the resulting screenshot
webview.measure(600, 400);
webview.layout(0, 0, 600, 400);
webview.loadUrl("http://stackoverflow.com");
webview.setWebViewClient(new WebViewClient() {
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
//without this method, your app may crash...
}
#Override
public void onPageFinished(WebView view, String url) {
new takeScreenshotTask().execute();
stopSelf();
}
});
}
}
private class takeScreenshotTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void[] p1) {
//allow the webview to render
synchronized (this) {try {wait(350);} catch (InterruptedException e) {}}
//here I save the bitmap to file
Bitmap b = webview.getDrawingCache();
File file = new File("/sdcard/example-screenshot.png");
OutputStream out;
try {
out = new BufferedOutputStream(new FileOutputStream(file));
b.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
} catch (IOException e) {
Log.e("ScreenshotService", "IOException while trying to save thumbnail, Is /sdcard/ writable?");
e.printStackTrace();
}
Toast.makeText(ScreenshotService.this, "Screenshot taken", Toast.LENGTH_SHORT).show();
return null;
}
}
//service related stuff below, its probably easyer to use intentService...
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
}
}
How to implement SIP protocol in Android ?
there is any SDK or library available to implement it easily into Android?
Here is a third party Library with sample code. You can use this, I have used it and it works fine.
Android 2.3 or higher provides API for SIP.
Refer this link for SIP in Android
also you can see DEMO project for SIP from Sample
update:
Android SDK Samples on github.
SipDemo1, SipDemo2
Search for SipDemo project in samples for android 4.0.3 SDK version(API level -15)
I have been investigated this sort of problem for a long time and found out that SipManager and SipProfile are unfortunatelly poor and extremelly buggy.
So I found a Linphone library. There is a link for their wiki. I implemented it in my project using maven:
repositories {
...
maven { "https://linphone.org/maven_repository/"}
}
Also there is a sample of using it on gitlab: link here, it's pretty fresh, for now :)
If the link would crash, I just copy/paste the most important part of how to use linphone's core:
public class LinphoneService extends Service {
private static final String START_LINPHONE_LOGS = " ==== Device information dump ====";
// Keep a static reference to the Service so we can access it from anywhere in the app
private static LinphoneService sInstance;
private Handler mHandler;
private Timer mTimer;
private Core mCore;
private CoreListenerStub mCoreListener;
public static boolean isReady() {
return sInstance != null;
}
public static LinphoneService getInstance() {
return sInstance;
}
public static Core getCore() {
return sInstance.mCore;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
// The first call to liblinphone SDK MUST BE to a Factory method
// So let's enable the library debug logs & log collection
String basePath = getFilesDir().getAbsolutePath();
Factory.instance().setLogCollectionPath(basePath);
Factory.instance().enableLogCollection(LogCollectionState.Enabled);
Factory.instance().setDebugMode(true, getString(R.string.app_name));
// Dump some useful information about the device we're running on
Log.i(START_LINPHONE_LOGS);
dumpDeviceInformation();
dumpInstalledLinphoneInformation();
mHandler = new Handler();
// This will be our main Core listener, it will change activities depending on events
mCoreListener = new CoreListenerStub() {
#Override
public void onCallStateChanged(Core core, Call call, Call.State state, String message) {
Toast.makeText(LinphoneService.this, message, Toast.LENGTH_SHORT).show();
if (state == Call.State.IncomingReceived) {
Toast.makeText(LinphoneService.this, "Incoming call received, answering it automatically", Toast.LENGTH_LONG).show();
// For this sample we will automatically answer incoming calls
CallParams params = getCore().createCallParams(call);
params.enableVideo(true);
call.acceptWithParams(params);
} else if (state == Call.State.Connected) {
// This stats means the call has been established, let's start the call activity
Intent intent = new Intent(LinphoneService.this, CallActivity.class);
// As it is the Service that is starting the activity, we have to give this flag
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
};
try {
// Let's copy some RAW resources to the device
// The default config file must only be installed once (the first time)
copyIfNotExist(R.raw.linphonerc_default, basePath + "/.linphonerc");
// The factory config is used to override any other setting, let's copy it each time
copyFromPackage(R.raw.linphonerc_factory, "linphonerc");
} catch (IOException ioe) {
Log.e(ioe);
}
// Create the Core and add our listener
mCore = Factory.instance()
.createCore(basePath + "/.linphonerc", basePath + "/linphonerc", this);
mCore.addListener(mCoreListener);
// Core is ready to be configured
configureCore();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
// If our Service is already running, no need to continue
if (sInstance != null) {
return START_STICKY;
}
// Our Service has been started, we can keep our reference on it
// From now one the Launcher will be able to call onServiceReady()
sInstance = this;
// Core must be started after being created and configured
mCore.start();
// We also MUST call the iterate() method of the Core on a regular basis
TimerTask lTask =
new TimerTask() {
#Override
public void run() {
mHandler.post(
new Runnable() {
#Override
public void run() {
if (mCore != null) {
mCore.iterate();
}
}
});
}
};
mTimer = new Timer("Linphone scheduler");
mTimer.schedule(lTask, 0, 20);
return START_STICKY;
}
#Override
public void onDestroy() {
mCore.removeListener(mCoreListener);
mTimer.cancel();
mCore.stop();
// A stopped Core can be started again
// To ensure resources are freed, we must ensure it will be garbage collected
mCore = null;
// Don't forget to free the singleton as well
sInstance = null;
super.onDestroy();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
// For this sample we will kill the Service at the same time we kill the app
stopSelf();
super.onTaskRemoved(rootIntent);
}
private void configureCore() {
// We will create a directory for user signed certificates if needed
String basePath = getFilesDir().getAbsolutePath();
String userCerts = basePath + "/user-certs";
File f = new File(userCerts);
if (!f.exists()) {
if (!f.mkdir()) {
Log.e(userCerts + " can't be created.");
}
}
mCore.setUserCertificatesPath(userCerts);
}
private void dumpDeviceInformation() {
StringBuilder sb = new StringBuilder();
sb.append("DEVICE=").append(Build.DEVICE).append("\n");
sb.append("MODEL=").append(Build.MODEL).append("\n");
sb.append("MANUFACTURER=").append(Build.MANUFACTURER).append("\n");
sb.append("SDK=").append(Build.VERSION.SDK_INT).append("\n");
sb.append("Supported ABIs=");
for (String abi : Version.getCpuAbis()) {
sb.append(abi).append(", ");
}
sb.append("\n");
Log.i(sb.toString());
}
private void dumpInstalledLinphoneInformation() {
PackageInfo info = null;
try {
info = getPackageManager().getPackageInfo(getPackageName(), 0);
} catch (PackageManager.NameNotFoundException nnfe) {
Log.e(nnfe);
}
if (info != null) {
Log.i(
"[Service] Linphone version is ",
info.versionName + " (" + info.versionCode + ")");
} else {
Log.i("[Service] Linphone version is unknown");
}
}
private void copyIfNotExist(int ressourceId, String target) throws IOException {
File lFileToCopy = new File(target);
if (!lFileToCopy.exists()) {
copyFromPackage(ressourceId, lFileToCopy.getName());
}
}
private void copyFromPackage(int ressourceId, String target) throws IOException {
FileOutputStream lOutputStream = openFileOutput(target, 0);
InputStream lInputStream = getResources().openRawResource(ressourceId);
int readByte;
byte[] buff = new byte[8048];
while ((readByte = lInputStream.read(buff)) != -1) {
lOutputStream.write(buff, 0, readByte);
}
lOutputStream.flush();
lOutputStream.close();
lInputStream.close();
}
}
I hope, that will help somebody, because I spend a lot of time trying to find it!
I used by this library:
https://www.mizu-voip.com/Software/SIPSDK/AndroidSIPSDK.aspx
it is very easy.
also i add button for answer the call:
mysipclient.Accept(mysipclient.GetLine());
I have an image view , i had written swiping , at that time of swiping,the images are downloading from Internet, so i thought i have to download the images in the background before swiping , for that which i need to use asynctask or Service or IntentService, all these will help in downloading and storing in data/data/mypackages , but still swiping gets slow in my case any idea, also convey me which one is best one, is it i'm calling in a right way
1. asynctask
2. services
3. Intent Service as shown below,
i m confused which one is right method because still my problem not solved
Here's asynctask code sample snippet
public class Demo extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new FirstTask().execute(); // calling Asynctask here
}
}
Async Task code
private class FirstTask extends AsyncTask<Void, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(Catalogue.this);
int temp = 0;
// can use UI thread here
protected void onPreExecute() {
this.dialog.setMessage("Loading...");
this.dialog.setCancelable(false);
//this.dialog.show();
System.gc();
Toast.makeText(Catalogue.this, "My Async Created",
Toast.LENGTH_LONG).show();
}
#Override
protected Void doInBackground(Void... params) {
Looper.prepare();
try {
myddownloadmethod();// calling my download method
} catch (Exception e) {
Util.trace("Error in Async"+e.getMessage());
}
Looper.loop();
return null;
}
protected void onPostExecute(Void result) {
if (this.dialog.isShowing()) {
Toast.makeText(Catalogue.this, "My Async destroyed",
Toast.LENGTH_LONG).show();
Toast.makeText(Catalogue.this, "count" + temp,
Toast.LENGTH_LONG).show();
this.dialog.dismiss();
}
}
}
Here's My Service sinppet
public class MyService extends Service implements Runnable
{ #Override
public void onCreate() {
super.onCreate();
Thread mythread = new Thread(this);
mythread.start();
}
public void run() {
Looper.prepare();
try {
myddownloadmethod();// calling my download method
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Looper.loop();
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
Invoking Service
public class ServicesDemo extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(this, MyService.class));
}
}
Here's IntentService Code
public class Downloader extends IntentService {
public Downloader() {
super("Downloader");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onHandleIntent(Intent i) {
try {
myddownloadmethod();// calling my download method
} catch (Exception e1) {
// TODO Auto-generated catch block
Log.d("Error",e1.getMessage());
}
}
}
Calling IntentService from MyActivity
public class ServicesDemo extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent i1=new Intent(this, Downloader.class);
startService(i1);
}
}
The best way to download it using the service like i have done to download the file from server and put in SD card also use the notification for it.
It is quite long code but i think the perfect one,if did not understand any thing then please go to android developer blog for services.
public class DownloadService extends Service{
SharedPreferences preferences;
private static final String DOCUMENT_VIEW_STATE_PREFERENCES = "DjvuDocumentViewState";
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private NotificationManager mNM;
String downloadUrl;
public static boolean serviceState=false;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
downloadFile();
showNotification(getResources().getString(R.string.notification_catalog_downloaded),"VVS");
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
serviceState=true;
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
HandlerThread thread = new HandlerThread("ServiceStartArguments",1);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("SERVICE-ONCOMMAND","onStartCommand");
Bundle extra = intent.getExtras();
if(extra != null){
String downloadUrl = extra.getString("downloadUrl");
Log.d("URL",downloadUrl);
this.downloadUrl=downloadUrl;
}
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public void onDestroy() {
Log.d("SERVICE-DESTROY","DESTORY");
serviceState=false;
//Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
public void downloadFile(){
downloadFile(this.downloadUrl,fileName);
}
void showNotification(String message,String title) {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = message;
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.icon, "vvs",
System.currentTimeMillis());
notification.flags |= Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(this, HomeScreenActivity.class);
intent.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP);
//The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this.getBaseContext(), 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, title,
text, contentIntent);
// Send the notification.
// We use a layout id because it is a unique number. We use it later to cancel.
mNM.notify(R.string.app_name, notification);
}
public void downloadFile(String fileURL, String fileName) {
StatFs stat_fs = new StatFs(Environment.getExternalStorageDirectory().getPath());
double avail_sd_space = (double)stat_fs.getAvailableBlocks() *(double)stat_fs.getBlockSize();
//double GB_Available = (avail_sd_space / 1073741824);
double MB_Available = (avail_sd_space / 10485783);
//System.out.println("Available MB : " + MB_Available);
Log.d("MB",""+MB_Available);
try {
File root =new File(Environment.getExternalStorageDirectory()+"/vvveksperten");
if(root.exists() && root.isDirectory()) {
}else{
root.mkdir();
}
Log.d("CURRENT PATH",root.getPath());
URL u = new URL(fileURL);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
int fileSize = c.getContentLength()/1048576;
Log.d("FILESIZE",""+fileSize);
if(MB_Available <= fileSize ){
this.showNotification(getResources().getString(R.string.notification_no_memory),getResources().getString(R.string.notification_error));
c.disconnect();
return;
}
FileOutputStream f = new FileOutputStream(new File(root.getPath(), fileName));
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = in.read(buffer)) > 0) {
f.write(buffer, 0, len1);
}
f.close();
File file = new File(root.getAbsolutePath() + "/" + "some.pdf");
if(file.exists()){
file.delete();
Log.d("FILE-DELETE","YES");
}else{
Log.d("FILE-DELETE","NO");
}
File from =new File(root.getAbsolutePath() + "/" + fileName);
File to = new File(root.getAbsolutePath() + "/" + "some.pdf");
} catch (Exception e) {
Log.d("Downloader", e.getMessage());
}
For anyone running into this question later, take a look at the async download mechanism used in the android sample code for the project com.example.android.bitmapfun.ui.ImageGridActivity. It downloads images asynchronously and also caches them for offline display in an ImageView. Folks have wrapped their code around this one and made image loading libraries of their own. These libraries use an AsyncTask instead of a service. Async tasks are expected to wrap up their work within a couple of seconds.
If you are looking to download something larger, I'd recommend the DownloadManager that is available since API 9 instead of using services. There is a lot of code in there that adds resilience to the download.
The download manager is a system service that handles long-running HTTP downloads. Clients may request that a URI be downloaded to a particular destination file. The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots. Instances of this class should be obtained through getSystemService(String) by passing DOWNLOAD_SERVICE. Apps that request downloads through this API should register a broadcast receiver for ACTION_NOTIFICATION_CLICKED to appropriately handle when the user clicks on a running download in a notification or from the downloads UI. Note that the application must have the INTERNET permission to use this class.
You are probably over engineering this. I have implemented swiping with dynamically loading images and I just a use a simple utility class that does it all for me via static method call.
Try this class:
package com.beget.consumer.util;
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ImageView;
public class DrawableLoader {
private final Map<String, Drawable> drawableMap;
private WeakReference<ImageView> imageViewReference;
public DrawableLoader() {
drawableMap = new HashMap<String, Drawable>();
}
public Drawable fetchDrawable(String urlString) {
if (drawableMap.containsKey(urlString)) {
return drawableMap.get(urlString);
}
Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
try {
InputStream is = fetch(urlString);
Drawable drawable = Drawable.createFromStream(is, "src");
drawableMap.put(urlString, drawable);
Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
+ drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
+ drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
return drawable;
} catch (MalformedURLException e) {
Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
return null;
} catch (IOException e) {
Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
return null;
}
}
public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
if (drawableMap.containsKey(urlString)) {
imageViewReference.get().setImageDrawable(drawableMap.get(urlString));
}
final Handler handler = new Handler() {
#Override
public void handleMessage(Message message) {
imageViewReference.get().setImageDrawable((Drawable) message.obj);
}
};
Thread thread = new Thread() {
#Override
public void run() {
//TODO : set imageView to a "pending" image
Drawable drawable = fetchDrawable(urlString);
Message message = handler.obtainMessage(1, drawable);
handler.sendMessage(message);
}
};
thread.start();
}
private InputStream fetch(String urlString) throws MalformedURLException, IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
}
This is all you need. Then when you need to load an image, you call:
fetchDrawableOnThread("http://path/to/your/image.jpg", yourImageViewReference);
That's it.
If you have an URL from a JSON object, parse the URL into your string so:
String url = jsonObj.getString("url");
Then call fetchDrawableOnThread(url, yourImageViewReference);
Use volley.
Using volley network image view you can do this
we use latest architecure components here.We make some observers with live data for some flag that represents download status.In service we download the image and completing we update the live data so that the observers method automatically called