Утечки памяти при запуске Activity в AsyncTask (изменено с Thread) - PullRequest
1 голос
/ 17 мая 2011

Я довольно новичок в разработке под 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 приложения после выполнения этого кода показывает, что поток всегда будет сохраняться в куче и расти в геометрической прогрессии.Исследование этого указывает на ссылку на контекст внутри потока, вызывающего утечку.Поэтому я несколько раз менял этот код, пока он не стал этой версией со слабой ссылкой в ​​статическом классе (некоторые вещи упоминались в других публикациях)

Причина, по которой я хочу запустить действие впоток, потому что мне нужно читать данные из медленного и большого веб-сервиса, что занимает некоторое время.Я отобразил полосу загрузки в упражнении, выделив выделенный элемент до тех пор, пока не будет выполнено 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 (его очень трудно прочитать, потому что мне не разрешалось публиковать html со ссылками и изображениями, такими какв MAT из-за моего уровня пользователя ...).Потоки 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 ]

1 голос
/ 17 мая 2011

О боже, есть особая вещь, чтобы начать действие после того, как какая-то работа в фоновом режиме сделана. Это AsyncTask с ограниченным ProgressDialog. См. пример.

0 голосов
/ 17 мая 2011

Вы должны посмотреть на AsyncTask , где вы выполняете загрузку в doInBackground(), настраиваете строку состояния в onPreExecute, публикуете обновления прогресса с помощью publishProgess, а затем удаляете индикатор выполнения в onPostExecute.

...