在AsyncTask中启动Activity时内存泄漏(从Thread更改)

时间:2011-05-17 11:47:19

标签: android multithreading android-activity android-context ui-thread

我对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转储显示该线程将始终保留在堆中并以指数方式增长。研究这一点指向引用线程内部的上下文导致泄漏。所以我改变了这个代码几次,直到它成为这个版本,在静态类中只有一个弱引用(这是其他帖子中提到的一些东西)

我想在一个线程中启动Activity的原因是因为我需要从缓慢而庞大的Web服务中读取数据,这需要一些时间。我在活动中显示了一个加载栏,突出显示所选项目,直到XMLparser完成,然后开始新活动。

可能没有正确的方法在线程内启动活动而不会导致内存泄漏?并且,如果是这样,在xml解析器完成其工作之后,是否还有其他方法可以启动意图?


根据Vladimir和Heiko的建议,我将我的线程改为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线程概述堆转储的副本(这很难阅读,因为我的用户级别不允许我发布带有MAT的链接和图像的html ...) 。 AsyncTask线程保留了376或344的堆。当我浏览应用程序的时间更长时,AsyncActivity个线程中将有越来越多的保留堆...

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 

2 个答案:

答案 0 :(得分:1)

哦,我的,在完成一些背景工作后开始一项活动有一件特别的事情。这是AsyncTask与ProgressDialog的界限。查看example.

答案 1 :(得分:0)

您应该查看AsyncTask,在doInBackground()中加载,在onPreExecute设置状态栏,使用publishProgess发布进度更新,然后删除onPostExecute中的进度条。