Reputation: 1195
I have a method that downloads a image from internet and stores it on a bitmap. While it is downloading the image, it shows a loading dialog. The method works fine, but i want to add the functionality into my app to stop the thread (so stop the download) and dismiss the dialog if the user press the back key on the phone.
public static void getRemoteImage(final String url, final Handler handler) {
Thread thread = new Thread(){
public void run() {
try {
Looper.prepare();
handler.sendEmptyMessage(Util.SHOW_LOADING_DIALOG);
final URL aURL = new URL(url);
final URLConnection conn = aURL.openConnection();
conn.connect();
final BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
image = BitmapFactory.decodeStream(bis);
bis.close();
handler.sendEmptyMessage(Util.HIDE_LOADING_DIALOG);
Looper.loop();
}catch (Exception e) {e.printStackTrace();}
}
};
thread.start();
}
How can i add the functionality to stop the thread when the user press the back key on my activity? I can't find the way on google
EDIT: this is my attempt to use Ovidiu answer, but it doesn't works :(
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
dialogHandler.sendEmptyMessage(Util.HIDE_DIALOG);
task.cancel(true);
return true;
}
return super.onKeyDown(keyCode, event);
}
private class DownloadTask extends AsyncTask{
@Override
protected void onPreExecute() {
super.onPreExecute();
//INITIALIZATIONS
}
@Override
protected Object doInBackground(Object... params) {
try {
dialogHandler.sendEmptyMessage(Util.SHOW_DIALOG);
final URL aURL = new URL(url);
final URLConnection conn = aURL.openConnection();
conn.connect();
final BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
image = BitmapFactory.decodeStream(bis);
bis.close();
dialogHandler.sendEmptyMessage(Util.HIDE_DIALOG);
}catch (Exception e) {e.printStackTrace();}
return null;
}
@Override
protected void onCancelled(){
super.onCancelled();
System.out.println("Task cancelled");
}
}
Upvotes: 3
Views: 928
Reputation: 72331
You should be using AsyncTask
To stop it you should be using Activity
lifecycle methods such as onStop()
or onDestroy()
to cancel()
the AsyncTask
.
To not reinvent the wheel you should probably use some libraries which do exact that (load remote images) like Ignition.
Upvotes: 6
Reputation: 28561
A general advise about managing an AsyncTask within an activity.
public class MyActivity extends Activity {
// Restore the task we kept alive
public void onCreate(Bundle savedInstanceState) {
myTask = (MyTask) getLastNonConfigurationInstance();
if (myTask!=null) myTask.connect(this);
}
// Keep the task alive on screen rotation for example
public Object onRetainNonConfigurationInstance() {
myTask.disconnect();
return myTask;
}
// Kill the task when we stop. If you wanna keep the task alive, you don't kill it here.
protected void onStop() {
killTask();
super.onStop();
}
// Disconnect the task from this activity and cancel it if needed
private void killTask() {
if (myTask!=null) {
myTask.cancel(true);
myTask.disconnect();
myTask = null;
}
}
// Kill task if running, create new one, link it to us and run it
private void launchTask() {
killTask();
myTask = new MyTask();
myTask.connect(this).execute();
}
void handleTaskCancelled() {
Toast.makeText(this, "Task cancelled", Toast.LENGTH_SHORT).show();
}
void handleTaskCompleted(String result) {
Toast.makeText(this, "Task done: " + result, Toast.LENGTH_SHORT).show();
}
private MyTask myTask;
}
// Either a standalone class, or a static inner class of your activity
public class MyTask extends AsyncTask<Void, Void, String> {
@Override
protected void onPostExecute(String result){
if (activityRef.get()!=null) {
activityRef.get().handleTaskCompleted(result);
}
}
@Override
protected void onCancelled(){
if (activityRef.get()!=null) {
activityRef.get().handleTaskCancelled();
}
}
public MyTask connect(MyActivity a) {
activityRef = new WeakReference<MyActivity>(a);
}
public void disconnect() {
activityRef.clear();
}
// Never keep a strong reference to an activity, you might leak memory
WeakReference<MyActivity> activityRef = new WeakReference<MyActivity>(null);
}
Upvotes: 1
Reputation: 28561
Since most of the long work is done by a single call BitmapFactory.decodeStream(bis);
, you won't be able to really stop the thread instantaneously anyway...
Some possible way of doing it though would be (doing as you do with a thread, but this would be better in an AsyncTask, which is essentially putting the run() code into the doInBackground() function):
public class ImageThread extends Thread {
Bitmap image = null;
public void run() {
// 1. download the stream to a byte[]
while data available in input stream
read a few bytes and store them
if (isInterrupted()) cleanUpAndExit();
endwhile
// 2. Create bitmap from data
image = BitmapFactory.decodeByteArray(...)
}
}
Oh. And the missing bit ... You then need to override the activity's onBackPressed, or the activity's onStop method to insert the code to cancel the thread: imageThread.interrupt();
Upvotes: 0