1

私はAndroid開発にまったく慣れておらず、メモリリークが非常に大きいことに気付いたときに、最初のアプリケーションを完成させようとしていました。

スレッド内から新しいアクティビティを開始すると、リークが発生します。

private static class CatalogRowOnClickListener implements OnClickListener 
{
    List<CatalogRow> catRows;
    WeakReference<CatalogViewActivity> mActivity;

    CatalogRowOnClickListener(WeakReference<CatalogViewActivity> mActivity) 
    {
        this.mActivity = mActivity;
        catRows = new ArrayList<CatalogRow>();
    }


    public void addCatalogRow(CatalogRow row) 
    {
        catRows.add(row);
    }

    public void onClick(View v) 
    {   
        v.setBackgroundColor(Color.argb(150, 255, 255, 255));


        final ProgressBar linProgressBar = (ProgressBar) v.findViewById(R.id.CatProgressBar);
        linProgressBar.setVisibility(View.VISIBLE);

        final View fv = v;
        final fItem fhitem = findFItem(fv);
        try
        {
            new Thread()
            {


                public void run() 
                {
                    initializeApp();

                }
                public void initializeApp()
                {
                    // Initialize application data here


                    FItemListStore.getItemsFromWebservice(fhitem);
                    boolean isArticleOverview = false;

                    for(FItem item: FItemListStore.fItemViewStorage) 
                    {   
                        if( item instanceof fiArticle ) 
                        {
                            isArticleOverview = true;
                            break;
                        }
                    }


                    Intent intent = new Intent();
                    intent.setClassName("nl.project.Android", "nl.project.Android.Activities.HomeViewActivity");
                    Bundle bundle = new Bundle();

                    if(isArticleOverview)
                    {
                        bundle.putInt("OverviewNr", 1);
                    }
                    else
                    {
                        bundle.putInt("OverviewNr", 0);
                    }
                    intent.putExtras(bundle);

                    //if( mActivity.get() != null )
                        mActivity.get().startActivity(intent);

                    mActivity.clear();

                }
            }.start();
        }
        catch (Exception e) {}

        //Debug.stopMethodTracing();
        //android.os.Debug.stopMethodTracing();
    }     

このコードを実行した後のアプリのHPROFダンプは、スレッドが常にヒープに保持され、指数関数的に成長することを示しています。これを調査すると、リークの原因となるスレッド内のコンテキストを参照することになります。そのため、静的クラスで弱参照のみが含まれるこのバージョンになるまで、このコードを数回変更しました(これは他の投稿で言及されていることです)

スレッドでアクティビティを開始する理由は、低速で大きなWebサービスからデータを読み取る必要があるためです。これには時間がかかります。アクティビティに読み込みバーを表示し、完了するまで選択したアイテムを強調表示し、XMLparserその後新しいアクティビティを開始しました。

メモリリークを引き起こさずにスレッド内でアクティビティを開始する正しい方法がないのではないでしょうか。そして、もしそうなら、xmlパーサーが彼の仕事を終えた後にインテントを開始させる別の方法はありますか?


ウラジミールとヘイコのアドバイスで、スレッドをAnyncTaskに変更しました。保持されているヒープの拡張は停止しましたが、開始したAsyncTaskスレッドはまだヒープに残っています。これが私の新しいコードです:

private static class QueryFHTask extends AsyncTask<FredHopperItem, Integer, Boolean> 
 {

     WeakReference<CatalogViewActivity> mActivity;

     QueryFHTask(WeakReference<CatalogViewActivity> mActivity) 
     {
        this.mActivity = mActivity;

     }


     protected void onPreExecute() 
     {

     }
     protected Boolean doInBackground(FItem... items) {
         int count = items.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             FItemListStore.getItemsFromWebservice(items[i]);
             boolean isArticleOverview = false;

             for(FItem item: FItemListStore.fhItemViewStorage) 
             {  
                if( item instanceof FArticle ) 
                {
                    isArticleOverview = true;
                    break;
                }
             }

             Intent intent = new Intent();
             intent.setClassName("nl.project.Android", "nl.project.Android.Activities.HomeViewActivity");
             Bundle bundle = new Bundle();

             if(isArticleOverview)
             {
                bundle.putInt("OverviewNr", 1);
             }
             else
             {
                bundle.putInt("OverviewNr", 0);
             }
             intent.putExtras(bundle);
             mActivity.get().startActivity(intent);

         }
         return true;
     }

     protected void onProgressUpdate(Integer... progress) {
         //setProgressPercent(progress[0]);

     }

     protected void onPostExecute(Long result) {
         //showDialog("Downloaded " + result + " bytes");
     }
 }

private static class CatalogRowOnClickListener implements OnClickListener 
{
    List<CatalogRow> catRows;
    WeakReference<CatalogViewActivity> mActivity;

    CatalogRowOnClickListener(WeakReference<CatalogViewActivity> mActivity) 
    {
        this.mActivity = mActivity;
        catRows = new ArrayList<CatalogRow>();
    }


    public void addCatalogRow(CatalogRow row) 
    {
        catRows.add(row);
    }

    public void onClick(View v) 
    {   
        v.setBackgroundColor(Color.argb(150, 255, 255, 255));
        final ProgressBar linProgressBar = (ProgressBar) v.findViewById(R.id.CatProgressBar);
        linProgressBar.setVisibility(View.VISIBLE);

        final View fv = v;
        final fItem fhitem = findFItem(fv);     
        new QueryFHTask(mActivity).execute(fhitem);       


    }

私の問題を明確にするために、これが私のHPROFスレッド概要ヒープダンプの1つのコピーです(ユーザーレベルのためにMATのようにリンクや画像を含むHTMLを投稿することが許可されなかったため、読むのは非常に困難です...)。AsyncActivityAsyncTaskスレッドは376または344のヒープを保持します。アプリケーションのブラウザーを長くするにつれて、スレッドから保持されるヒープはますます多くなります。

Name Instance Shallow Heap Retained Heap Context Class Loader 
main java.lang.Thread @ 0x40027550 80 1.464 dalvik.system.PathClassLoader @ 0x4051ce30 
JDWP java.lang.Thread @ 0x40515838 80 384  
AsyncTask #6 java.lang.Thread @ 0x406ea788 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #7 java.lang.Thread @ 0x40690178 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #4 java.lang.Thread @ 0x4068a630 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #3 java.lang.Thread @ 0x406851f0 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #5 java.lang.Thread @ 0x405d9f28 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #2 java.lang.Thread @ 0x40539db0 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #1 java.lang.Thread @ 0x40517180 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #8 java.lang.Thread @ 0x4068cdb0 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #9 java.lang.Thread @ 0x4068b558 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #10 java.lang.Thread @ 0x4068a178 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #11 java.lang.Thread @ 0x406639f0 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #12 java.lang.Thread @ 0x40661b00 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
Binder Thread #2 java.lang.Thread @ 0x40519b20 80 344  
Binder Thread #1 java.lang.Thread @ 0x40516868 80 344  
Thread-2 java.util.logging.LogManager$2$1 @ 0x40195298 80 168 dalvik.system.PathClassLoader @ 0x400277f8 
Signal Catcher java.lang.Thread @ 0x40515778 80 160  
Compiler java.lang.Thread @ 0x405158e8 80 152  
HeapWorker java.lang.Thread @ 0x40515618 80 152  
GC java.lang.Thread @ 0x405156d0 80 136  
Total: 21 entries  1.680 7.656 
4

2 に答える 2

1

ああ、バックグラウンドでいくつかの作業が行われた後にアクティビティを開始する特別なことがあります。これは、ProgressDialogが制限されたAsyncTaskです。例を参照してください

于 2011-05-17T11:55:15.080 に答える
0

で読み込みを行い、でステータスバーを設定し、で進行状況の更新を公開してから、で進行状況バーを削除するAsyncTaskを確認する必要があります。doInBackground()onPreExecutepublishProgessonPostExecute

于 2011-05-17T11:53:57.983 に答える