当用户按下后退键时可以停止一个线程?

时间:2012-10-17 20:10:15

标签: java android multithreading

我有一种从互联网下载图像并将其存储在位图上的方法。在下载图像时,它会显示一个加载对话框。该方法工作正常,但我想在我的应用程序中添加功能以停止线程(因此停止下载)并在用户按下手机上的后退键时关闭对话框。

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

当用户按下我的活动上的后退键时,如何添加停止线程的功能?我在谷歌上找不到方法

编辑:这是我尝试使用Ovidiu的答案,但它不起作用:(

@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");
        }
    }

3 个答案:

答案 0 :(得分:6)

  1. 您应该使用AsyncTask

  2. 要停止它,您应该使用Activity生命周期方法,例如onStop()onDestroy()cancel() AsyncTask

  3. 为了不重新发明轮子你应该使用一些像Ignition那样确切(加载远程图像)的库。

答案 1 :(得分:1)

关于在活动中管理异步任务的一般建议。

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

//您的活动的独立课程或静态内部课程

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

答案 2 :(得分:0)

由于大部分长期工作都是通过一次电话BitmapFactory.decodeStream(bis);完成的,所以无论如何你都无法立即停止线程......

虽然这样做的一些可能的方法是(像对待线程一样,但这在AsyncTask中会更好,这实际上是将run()代码放入doInBackground()函数中):

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(...)
  }  
}

BitmapFactory.decodeByteArray

喔。缺少的一点......然后你需要覆盖活动的onBackPressed,或者活动的onStop方法来插入取消线程的代码:imageThread.interrupt();