3

呼び出し元のフラグメントが一時停止/削除されると、非同期タスクはどうなりますか?タスクが完了したと思いますが、誰かがそれを確認できれば素晴らしいと思います。クラッシュの修正方法を見つけようとしています。

再帰的な画像ローダーである非同期タスクがあります。画像ローダーは、画像を読み込むlistFragmentの内部クラスです。すべての画像の読み込みが完了する前に戻るボタンを押さない限り、画像ローダーは完全に機能します。すべての画像の読み込みが完了する前に戻るボタンを押すと、アプリケーションがクラッシュします。イメージローダーがアダプターにアクセスできなくなったように感じますが、この問題を正しく攻撃しているかどうかはわかりません。非同期タスク内でこの問題を修正する方法がわかりません。誰かが私を助けることができれば。私の頭からアイデアを跳ね返して、私に違った考え方をさせることさえできます。

どんな助けでも素晴らしいでしょう。ご覧いただきありがとうございます。

ImageLoader

private class ImageLoaderTask extends
        AsyncTask<HashMap<String, Object>, Void, HashMap<String, Object>> {

    @Override
    protected HashMap<String, Object> doInBackground(
            HashMap<String, Object>... hm) {
        InputStream in = null;

        String url = (String) hm[0].get("image");
        int pos = (Integer) hm[0].get("pos");
        url = "http://kzfr.org/u/img/small/" + url;
        URL mUrl;

        try {
            mUrl = new URL(url);
            URLConnection urlConnect = (URLConnection) mUrl
                    .openConnection();
            in = urlConnect.getInputStream();

            File cacheDirectory = getSherlockActivity().getBaseContext()
                    .getCacheDir();

            File tmp = new File(cacheDirectory.getPath() + "/kzfr_small"
                    + pos + ".png");

            FileOutputStream fOut = new FileOutputStream(tmp);

            Bitmap b = BitmapFactory.decodeStream(in);
            b.compress(Bitmap.CompressFormat.PNG, 100, fOut);
            fOut.flush();
            fOut.close();

            HashMap<String, Object> hmBmp = new HashMap<String, Object>();
            hmBmp.put("blank_start", tmp.getPath());
            hmBmp.put("pos", pos);
            return hmBmp;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(HashMap<String, Object> result) {
        // this is the img path that leads to a local image that was just
        // saved on the phone.
        String imgPath = (String) result.get("blank_start");
        // the position of the image in the listview
        int position = (Integer) result.get("pos");
        // local adapter
        SimpleAdapter adapter = (SimpleAdapter) getListAdapter();
        // hashmap entry from the local adapter at the position of the image
        // that we just loaded.
        HashMap<String, Object> hm = (HashMap<String, Object>) adapter
                .getItem(position);
        // replace the actual blank image with the image path that we just
        // loaded
        hm.put("blank_start", imgPath);
        // update listview
        adapter.notifyDataSetChanged();
        // we are done with the current position increment position and move
        // on.
        position++;
        // this while loop finds the next position in the adapter that does
        // not have false for an image path. False indicates that there is
        // no image and i should load a default image.
        while (position < adapter.getCount()) {
            hm = (HashMap<String, Object>) adapter.getItem(position);
            imgPath = (String) hm.get("image");

            if (!imgPath.equalsIgnoreCase("false")) {
                break;
            }
            position++;
        }

        // checks to make sure that the position is not out of bounds on the
        // adapter. If in bounds then there might be more images to load.
        // Start a new ImageLoader. This is a recursive Class.
        if (position < adapter.getCount()) {
            ImageLoaderTask imageLoader = new ImageLoaderTask();

            hm.put("pos", (position));
            imageLoader.execute(hm);
        }

    }

スタックトレース

01-14 20:09:28.752: E/AndroidRuntime(6069): FATAL EXCEPTION: main
01-14 20:09:28.752: E/AndroidRuntime(6069): java.lang.NullPointerException
01-14 20:09:28.752: E/AndroidRuntime(6069):     at com.appdomum.doublea.ListFrag$ImageLoaderTask.onPostExecute(ListFrag.java:272)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at com.appdomum.doublea.ListFrag$ImageLoaderTask.onPostExecute(ListFrag.java:1)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.AsyncTask.finish(AsyncTask.java:417)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.AsyncTask.access$300(AsyncTask.java:127)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.Looper.loop(Looper.java:130)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.app.ActivityThread.main(ActivityThread.java:3806)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at java.lang.reflect.Method.invokeNative(Native Method)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at java.lang.reflect.Method.invoke(Method.java:507)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at     com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at   com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at dalvik.system.NativeStart.main(Native Method)
4

2 に答える 2

4

あなたはここで正しい方向に進んでいると思います。

カスタムを書くときAsyncTask、多くの開発者は、タスクのキャンセルを処理する必要があることを忘れています。タスクを単にキャンセルすることは、そのコードが(たとえば)Activity/Fragmentリソースで実行されないことを意味するわけではなく、その時点で解放される可能性があります。これは通常、次の手順で実行されます。

  1. タスクを作成したら、そのタスクへの参照を保存します。
  2. Activity/Fragmentが終了したら、実行中のすべてのタスクをキャンセルします。これは通常、Activity.onDestroy()/で行われFragment.onDestroy()ます。キャンセルされたタスクへのすべての参照を削除します。
  3. タスクのコード:
    1. 定期的にdoInBackground()チェックしてくださいisCancelled()。その場合は、整理して、それ以上の実行を中止します。
    2. 最終的にはでキャンセルを処理しonCancelled()ます(UIスレッドで実行されます)。
    3. でキャンセルされたタスクの処理を実行しますonPostExecute()(タスクがキャンセルされた場合に結果とともに実行さnullれます)。
于 2013-01-15T04:41:09.493 に答える
1

呼び出し元のフラグメントが一時停止/削除されると、非同期タスクはどうなりますか?タスクが完了したと思いますが、誰かがそれを確認できれば素晴らしいと思います。

それは正しくありません。フレームワークは、バックグラウンドスレッドで実行している作業をキャンセルすることによって作業を実行しません。onPause()のようなコールバックが呼び出される理由は、のような長期的なコンポーネントにない実行中の作業をクリーンアップしてキャンセルする必要があることをonResume()アプリケーションに通知するためです。Service

この場合、キャンセルしないとタスクは実行を継続します。このクラスは非静的内部クラスとして定義されているため、AsyncTaskはへの暗黙の参照を保持しているFragmentため、またタスクは実行中のスレッドにアタッチされているため、オブジェクト(またはそのメンバー)のどちらも一時的なメモリリークを作成したことも意味します。 )後でもガベージコレクションが可能onDestroy()です。

AsyncTask手動で作業をキャンセルできるキャンセルフラグonPause()または同様のコールバックをチェックするように実装する必要があります。

于 2013-01-15T04:39:22.557 に答える