3

インターネットから画像をダウンロードしてビットマップに保存する方法があります。画像をダウンロードしている間、読み込みダイアログが表示されます。メソッドは正常に動作しますが、アプリに機能を追加してスレッドを停止し (ダウンロードを停止し)、ユーザーが電話の戻るキーを押した場合にダイアログを閉じたいと考えています。

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

3 に答える 3

6
  1. 使用する必要がありますAsyncTask

  2. それを停止するには、またはなどのライフサイクルメソッドを使用する必要がありActivityます。onStop()onDestroy()cancel()AsyncTask

  3. 車輪の再発明をしないためには、おそらくIgnitionのようにそれを正確に実行する(リモートイメージをロードする)いくつかのライブラリを使用する必要があります。

于 2012-10-17T20:14:01.153 に答える
1

アクティビティ内での AsyncTask の管理に関する一般的なアドバイス。

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);
}
于 2012-10-18T08:03:24.653 に答える
0

長い作業のほとんどは 1 回の呼び出しBitmapFactory.decodeStream(bis);で行われるため、スレッドを瞬時に停止することはできません...

ただし、それを行ういくつかの可能な方法は次のとおりです(スレッドで行うのと同じように行いますが、これは本質的にrun()コードをdoInBackground()関数に入れるAsyncTaskの方が優れています):

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

于 2012-10-17T20:13:00.320 に答える