2015-06-24 2 views
13

Я инициализировать переменную-член в моем классе активностьсфера активности членов и AsyncTask

private String test = new String("A"); 

тогда я использую его, чтобы написать для входа в течение длительного времени, потребляющего цикл в doInBackground() методом анонимного AsyncTask запущен из деятельности

new AsyncTask<Void, Void, Void>() { 
    @Override 
    protected void onPreExecute() { 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 

    for (int j = 10; j >= 0; j--) { 
     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     Log.i("DOINBACKGROUND ", test); 
    } 

}.execute(); 

ВОПРОС: Когда я уезжаю в то время как активность Asynctask по-прежнему выполняется, и после активности 012-х, я вижу в журнале, что переменная-член все еще жива и не уничтожена. Может кто-нибудь объяснить мне, как это возможно?

BOUNTY ВОПРОС: переменный член еще жив, потому что, даже после того, как onDestroy(), оно не еще garbaged в связи с критериями Gc и приоритетом ого. Хорошо.

Но мои сомнения, если

  • «тест» переменный-член (и контекст своей деятельности в) не garbaged пока реферирование AsyncTask не закончил свой материал, таким образом, AsyncTask может завершить свою doInBackground() всегда и, конечно, без сбоев (хотя и с временным потреблением памяти)

или вместо

  • переменная член «тест» будет б е garbaged рано или поздно, независимо AsyncTask работает, может быть, в результате чего завесить asysnctask в

ответ

8

Не путайте сбор мусора и жизненный цикл деятельности.

Объект может быть собран из мусора после того, как все ссылки, отнесенные к нему из объектов GC root, исчезли.

onDestroy() является частью жизненного цикла деятельности. По сути, рамки выполняются с помощью этой деятельности и отказываются от каких-либо ссылок, которые могут быть связаны с деятельностью и связанными с ней ресурсами.

Когда вы создаете анонимный внутренний класс, он получает неявную ссылку на родительский объект. Другими словами, внутренний класс anon всегда является нестационарным внутренним классом. Эта родительская ссылка является ссылкой на ваш Activity. Затем вы передаете объект задачи async исполнителю с вызовом execute(), и исполнитель сохраняет ссылку на асинхронную задачу до тех пор, пока это необходимо, а также предотвращает сбор данных, на которые ссылается активность.


Таким образом, AsyncTask в моем сниппета примере завершит свою doInBackground() всегда и, конечно, без сбоев из-за NPE?

Да. Но учтите следующее:

  • Сделайте свои внутренние классы static, если они специально не нужны, чтобы получить доступ к родительскому объекту. Поскольку внутренние классы anon всегда равны static, сделайте их не анонимными.

  • Смешивание асинхронных операций с объектами с отдельным жизненным циклом (например, действия или фрагменты) является хрупким, и его лучше избегать. Проблемы включают, например, аннулирование, подача результатов на ушедший объект и сохранение ссылок, связанных с предотвращением GC, на дорогостоящие объекты, такие как действия.

+0

Таким образом, asynctask в моем примере фрагмента завершает doInBackground() всегда и, конечно, без сбоев из-за NPE? – GPack

3

Прежде всего, OnDestroy() происходит как раз перед уничтожением деятельности и просит диспетчера активности, чтобы освободить все ресурсы, связанные с этой деятельностью. Это означает, что все ресурсы активности будут кандидатами на удаление gc. Однако это не заставляет gc удалять ресурсы из памяти, они просто кандидаты. Этот кандидат будет оцениваться gc на основе их размера, возраста, продолжительности, типа и т. Д., И всякий раз, когда системе требуется больше места, она просит gc удалить кандидатов, и это делается на основе их оценок. Кандидат с более высоким счетом, скорее всего, будет удален первым.

Это заметно, когда вы видите крушение из ниоткуда, даже после того, как вы покинули приложение.

Возможно, вы сможете увидеть этот сбой, если вы создадите другое действие и вызовете System.gc() на нем.

Приветствия А.

+0

Очень ясно. Мое сомнение теперь в том, что в этом случае переменная-член все еще жива только из-за приоритета gc, но рано или поздно она будет изнашиваться, независимо от того, будет ли запущена асинтеза, или вместо этого, если она будет изнашиваться только тогда, когда асинтета (которая сохраняет ссылка на переменную-член?) завершила свою работу. – GPack

+0

Экземпляр объекта asyncktask принадлежит к активности, и действие уничтожается. Таким образом, gc уже отметил все переменные как мусор. Однако они будут удалены из памяти. Если вы хотите использовать долгосрочную задачу, используйте другие структуры, такие как службы или intentservices, в зависимости от вашей ситуации. Если вы хотите придерживаться своего текущего решения, чтобы предотвратить крах в фоновом режиме, вы можете определить переменную внутри объекта asynktask и проверить обратный вызов на нуль в onPostExecute(). Делая это, он не падает, хотя результат будет потерян. –

+0

Да, я сомневаюсь, что эта анонимная асинтеза сохраняет ссылку на переменную «test» внешнего класса и, следовательно, на контекст активности. Таким образом, они, поскольку они ссылаются, не будут сбрасываться до тех пор, пока асинтексат не закончит свой материал. Я ошибаюсь? – GPack

2

AsyncTask не привязан к жизненному циклу деятельности, который его содержит. Например, если вы запускаете AsyncTask внутри Activity и пользователь поворачивает устройство, активность будет уничтожена (и будет создан новый экземпляр Activity), но AsyncTask не умрет, а продолжит жизнь до завершения.

Затем, когда AsyncTask завершает работу, а не обновляет пользовательский интерфейс нового действия, он обновляет прежний экземпляр Activity (то есть тот, в котором он был создан, но который больше не отображается!). Это может привести к исключению (типа java.lang.IllegalArgumentException: просмотр не привязан к оконному менеджеру, если вы используете, например, findViewById для получения представления внутри Activity).

Существует также потенциальная возможность для этого привести к утечке памяти, так как AsyncTask поддерживает ссылку на Activity, что предотвращает сбор мусора, пока AsyncTask остается в живых.

По этим причинам использование AsyncTasks для долгосрочных фоновых задач - это, как правило, плохая идея. Скорее, для длительных фоновых задач должен использоваться другой механизм (например, служба).

+0

Шахта - это просто попытка, чтобы проверить на поле некоторые теоретические вопросы о ссылках. В связи с этим, например, я пытаюсь использовать findViewById из Asysnctask для извлечения и обновления представления Activity, пока активность больше не видна (таким образом, после нажатия BACK или изменения ориентации). В результате результат Asynctask завершает работу, обновление представления теряется, но я не получаю никакого исключения и не использую findViewById в doInBackground(), выкидывая оператор runOnUiThread() и не используя метод findViewById в OnPostExecute(). – GPack

3

Переменная член test не будет утилизирован сборщиком мусора, пока экземпляр деятельности не является сбор мусора.

Экземпляр Activity не будет возвращен сборщиком мусора до тех пор, пока AsyncTask не будет завершен, так как AsyncTask содержит ссылку на экземпляр Activity.

Экземпляр AsyncTask не будет собираться мусором, пока он не завершит свою работу.

AsyncTask завершает метод doInBackground() без сбоев. Наверняка.

+0

спасибо, очень четкое объяснение цепочки ссылок. – GPack

0

Я предполагаю, что задача async не является статической и содержит ссылку на прилагаемую активность, предотвращая сбор мусора.

Если вы хотите знать, как анонимный класс может привести к течи деятельности относятся это -

Также вы можете попробовать поворота устройства несколько устройств и проверить, если имеется несколько экземпляров одного и того же вида деятельности, используя следующую команду и проверяя отсутствие действий.

ADB dumpsys оболочки MemInfo your.app.packagename

Applications Memory Usage (kB): 
Uptime: 40343748 Realtime: 164852669 

** MEMINFO in pid 16561 [samsung.svl.com.graph] ** 
        Pss Private Private Swapped  Heap  Heap  Heap 
       Total Dirty Clean Dirty  Size Alloc  Free 
       ------ ------ ------ ------ ------ ------ ------ 
    Native Heap  5708  5664  16  2380 20480  8849 11630 
    Dalvik Heap  1163  972  136 27080 37459 29598  7861 
Dalvik Other  604  604  0  4       
     Stack  288  288  0  0       
    Other dev  4  0  4  0       
    .so mmap  3569  992  72  2120       
    .apk mmap  39  0  0  0       
    .ttf mmap  0  0  0  0       
    .oat mmap  539  0  4  0       
    .art mmap  747  524  4  704       
    Other mmap  5  4  0  0       
    GL mtrack 10951 10951  0  0       
     Unknown  2260  2260  0  92       
     TOTAL 25877 22259  236 32380 57939 38447 19491 

Objects 
       Views:  17   ViewRootImpl:  1 
     AppContexts:  3   **Activities:  1** 
       Assets:  3  AssetManagers:  3 
     Local Binders:  8  Proxy Binders:  23 
     Parcel memory:  3   Parcel count:  12 
    Death Recipients:  0  OpenSSL Sockets:  0 

SQL 
     MEMORY_USED:  0 
    PAGECACHE_OVERFLOW:  0   MALLOC_SIZE:  0 
Смежные вопросы