1

я действительно работал над этим вопросом, но не могу найти решение ожидать, что это неестественно https://stackoverflow.com/a/2866717/2008040OutOfMemoryError если перезапустить законченную деятельность с ViewPager

I обладает активностью (WebViewActivityForHeadlines), который начинается с моей основной деятельности, эта деятельность содержит пользовательский просмотр пейджера (такое же поведение происходит, когда я использую стандартный просмотр пейджера), и этот просмотр пейджера раздувает пользовательские масштабируемые изображения (такое же поведение происходит, когда я использую стандартный просмотр изображений).

Ниже вы можете найти код деятельности, я просто вырезал некоторые несвязанные части.

@Fullscreen 
@EActivity(R.layout.activity_web_view_for_headlines) 
public class WebViewActivityForHeadlines extends BaseActivity 
{ 
    /** The log tag. */ 
    private static final String LOG_TAG = WebViewActivityForHeadlines.class.getSimpleName(); 

    private static int NUM_PAGES; 

    private static String CURRENT_URL = ""; 
    private static String CURRENT_TITLE = ""; 

    HeadlineListAdapter headlineListAdapter = GazetelikApplication.headlineListAdapter; 

    @ViewById(R.id.mPager) 
    public static JazzyViewPager MPAGER; 

    PagerAdapter mPagerAdapter; 

    @Bean 
    GazetelikSharingHelper gazetelikSharingHelper; 

    @ViewById 
    Button webViewButtonBack; 

    @ViewById 
    Button webViewButtonForward; 

    @ViewById 
    Button webViewButtonHome; 

    @ViewById 
    Button webViewButtonHide; 

    @ViewById 
    Button webViewButtonShare; 

    @ViewById 
    Button webViewButtonClose; 

    @ViewById(R.id.webViewControlPanel) 
    RelativeLayout controlPanel; 

    @ViewById(R.id.upperLayout) 
    RelativeLayout upperLayout; 

    @ViewById(R.id.mainRelativeLayout) 
    RelativeLayout mainLayout; 

    @ViewById(R.id.webViewShowControlPanelPanel) 
    RelativeLayout showControlPanelPanel; 

    Boolean isFirstRun = true; 
    Integer orderIdOfStart = null; 

    String tinyUrlString = ""; 
    boolean isTinyUrlReady; 
    int tinyUrlCount; 

    // ProgressDialog mProgressDialog; 

    /** The view to show the ad. */ 
    private AdView adView; 

    final Activity thisActivity = this; 

    DisplayImageOptions options; 

    Resources res; 

    @SuppressLint("NewApi") 
    @AfterViews 
    void afterViews() 
    { 
     NUM_PAGES = headlineListAdapter.getCount(); 

     Intent thisIntent = getIntent(); // gets the previously created intent 
     orderIdOfStart = thisIntent.getIntExtra("orderId", 0); 

     mPagerAdapter = new ImageAdapter(); 
     MPAGER.setAdapter(mPagerAdapter); 

     MPAGER.setCurrentItem(orderIdOfStart); 

     MPAGER.setTransitionEffect(JazzyViewPager.TransitionEffect.Accordion); 

     View decorView = getWindow().getDecorView(); 
     if (Build.VERSION.SDK_INT == 14 || Build.VERSION.SDK_INT == 15) 
     { 
      int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 
      decorView.setSystemUiVisibility(uiOptions); 
     } 
     else if (Build.VERSION.SDK_INT >= 16) 
     { 
      if (Build.VERSION.SDK_INT >= 19) 
      { 
       int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 
       decorView.setSystemUiVisibility(uiOptions); 
       getTemporaryCache().setWebViewControlPanelVisible(true); 
      } 
      else 
      { 
       int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; 
       decorView.setSystemUiVisibility(uiOptions); 
      } 
     } 

     res = getResources(); 

     DisplayImageOptions options = new DisplayImageOptions.Builder() 
       .showImageOnLoading(R.drawable.ic_launcher) 
       .showImageForEmptyUri(R.drawable.ic_launcher) 
       .cacheInMemory(false) 
       .build(); 
    } 

    /** Called before the activity is destroyed. */ 
    @Override 
    public void onDestroy() 
    { 
     try 
     { 
      upperLayout.removeAllViews(); 
      mainLayout.removeAllViews(); 
      mPagerAdapter = null; 
      MPAGER.removeAllViews(); 
     } 
     catch (Exception e) 
     { 
      Toast.makeText(thisActivity, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); 
     } 

     super.onDestroy(); 
    } 

    @Click(R.id.webViewButtonBack) 
    void onButtonBackClick() 
    { 
     int desiredPage = MPAGER.getCurrentItem() - 1; 

     if (desiredPage < 0) 
     { 
      desiredPage = 0; 
     } 

     if (desiredPage > mPagerAdapter.getCount()) 
     { 
      desiredPage = mPagerAdapter.getCount(); 
     } 

     MPAGER.setCurrentItem(desiredPage); 

    } 

    @Click(R.id.webViewButtonForward) 
    void onButtonForwardClick() 
    { 
     int desiredPage = MPAGER.getCurrentItem() + 1; 

     if (desiredPage < 0) 
     { 
      desiredPage = 0; 
     } 

     if (desiredPage > mPagerAdapter.getCount()) 
     { 
      desiredPage = mPagerAdapter.getCount(); 
     } 

     MPAGER.setCurrentItem(desiredPage); 
    } 

    @Click(R.id.webViewButtonHome) 
    void onButtonHomeClick() 
    { 
     MPAGER.setCurrentItem(orderIdOfStart); 
    } 

    @Click(R.id.webViewButtonHide) 
    void onButtonHideClick() 
    { 
     upperLayout.removeView(controlPanel); 
     showControlPanelPanel.setVisibility(RelativeLayout.VISIBLE); 
    } 

    @Click(R.id.webViewButtonClose) 
    void onButtonCloseClick() 
    { 
     finish(); 
    } 

    @Click(R.id.webViewButtonShare) 
    void onButtonShareClick() 
    { 
     ... 
    } 

    @Background 
    void buildTinyUrl(String longUrl) 
    { 
     ... 
    } 

    @UiThread 
    void onOtherShareButtonClickTask(String url) 
    { 
     ... 
    } 

    @UiThread 
    void onFacebookShareButtonClickTask(String url) 
    { 
     ... 
    } 

    @UiThread 
    void onTwitterShareButtonClickTask(String url) 
    { 
     ... 
    } 

    @Click(R.id.webViewButtonShow) 
    void onButtonShowClick() 
    { 
     upperLayout.addView(controlPanel); 
     showControlPanelPanel.setVisibility(RelativeLayout.INVISIBLE); 
    } 

    @UiThread 
    void popupToast(String message) 
    { 
     if (message != null) 
     { 
      Toast.makeText(this, message, Toast.LENGTH_LONG).show(); 
     } 
    } 

    @Override 
    public void onConfigurationChanged(Configuration newConfig) 
    { 
     RelativeLayout layout = (RelativeLayout) findViewById(R.id.headlinesForAddRelativeLayout); 
     layout.removeView(adView); 

     if (adView != null) 
     { 
      // Destroy the AdView. 
      adView.destroy(); 
     } 
     super.onConfigurationChanged(newConfig); 

    } 

    @Override 
    public void onBackPressed() 
    { 
     if (orderIdOfStart == MPAGER.getCurrentItem()) 
     { 
      super.onBackPressed(); 
     } 
     else if (MPAGER.getCurrentItem() > orderIdOfStart) 
     { 
      MPAGER.setCurrentItem(MPAGER.getCurrentItem() - 1); 
     } 
     else if (MPAGER.getCurrentItem() < orderIdOfStart) 
     { 
      MPAGER.setCurrentItem(MPAGER.getCurrentItem() + 1); 
     } 
    } 

    private class ImageAdapter extends PagerAdapter 
    { 
     private LayoutInflater inflater; 

     ImageAdapter() 
     { 
      inflater = LayoutInflater.from(thisActivity); 
     } 

     @Override 
     public void destroyItem(ViewGroup container, int position, Object object) 
     { 
      container.removeView((View) object); 
     } 

     @Override 
     public int getCount() 
     { 
      return NUM_PAGES; 
     } 

     @Override 
     public Object instantiateItem(ViewGroup view, int position) 
     { 
      View imageLayout = inflater.inflate(R.layout.simple_image_view, view, false); 
      assert imageLayout != null; 
      final TouchImageView imageView = (TouchImageView) imageLayout.findViewById(R.id.image); 
      final ProgressBar spinner = (ProgressBar) imageLayout.findViewById(R.id.loading); 

      ImageLoader.getInstance().displayImage(headlineListAdapter.getItem(position).getUrl(), imageView, options, new SimpleImageLoadingListener() 
      { 
       @Override 
       public void onLoadingStarted(String imageUri, View view) 
       { 
        spinner.setVisibility(View.VISIBLE); 
       } 

       @Override 
       public void onLoadingFailed(String imageUri, View view, FailReason failReason) 
       { 
        String message = null; 
        switch (failReason.getType()) { 
         case IO_ERROR: 
          message = "Input/Output error"; 
          break; 
         case DECODING_ERROR: 
          message = "Image can't be decoded"; 
          break; 
         case NETWORK_DENIED: 
          message = "Downloads are denied"; 
          break; 
         case OUT_OF_MEMORY: 
          message = "Out Of Memory error"; 
          break; 
         case UNKNOWN: 
          message = "Unknown error"; 
          break; 
        } 
        Toast.makeText(thisActivity, message, Toast.LENGTH_SHORT).show(); 
        spinner.setVisibility(View.GONE); 
       } 

       @Override 
       public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) 
       { 
        spinner.setVisibility(View.GONE); 
        imageView.setZoom(1F); 
       } 
      }); 
      view.addView(imageLayout, 0); 
      return imageLayout; 
     } 

     @Override 
     public boolean isViewFromObject(View view, Object object) 
     { 
      return view.equals(object); 
     } 

     @Override 
     public void restoreState(Parcelable state, ClassLoader loader) 
     { 
     } 

     @Override 
     public Parcelable saveState() 
     { 
      return null; 
     } 
    } 
} 

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

Это выход LogCat

java.lang.OutOfMemoryError 
      at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 
      at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:623) 
      at com.nostra13.universalimageloader.core.decode.BaseImageDecoder.decode(BaseImageDecoder.java:78) 
      at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeImage(LoadAndDisplayImageTask.java:264) 
      at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:237) 
      at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:135) 
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) 
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) 
      at java.lang.Thread.run(Thread.java:856) 

Не могли бы вы, ребята, пожалуйста, помогите мне найти утечку памяти?

ответ

0

Хорошо, я выясню проблему.

Я использовал MAT для анализа утечек памяти и при проверке моего дампа с помощью MAT я понял, что две отдельные библиотеки приводят к этой проблеме. Кстати, это хорошая тема, если вам нужна дополнительная информация о MAT View Pager Memory Leak with Bitmaps and Volley

Моя первая утечка - ACRA. ACRA - это инструмент отчетности о сбоях, так как это естественное поведение для инструмента отчетов о сбоях, ACRA всегда ссылается на недавно закрытую деятельность до начала другого действия. Но на самом деле это не большая проблема, потому что ACRA выпускает свою ссылку сразу же после запуска пользователем другого действия. Поэтому ACRA не является основной причиной, по которой я получаю OOME.

Моей второй утечкой является Google Ads. Я не мог узнать точную причину, но когда я завершаю свою деятельность, Google Ads всегда сохраняет ссылку на мой viewPager и снова открывает эту активность снова, чтобы приложение вышло из строя из-за OOME. На данный момент я просто удаляю рекламу при этой активности, но позже выкопаю эту проблему.

Благодарим за внимание замечательных людей.

1

Тот факт, что ваша куча не уменьшается при завершении вашей деятельности, свидетельствует о том, что GC не может избавиться от нее. Типичным виновником является то, что постоянный объект все еще держит ссылку на него.

Предлагаю вам ознакомиться с тем, что у вас есть, чтобы убедиться, что ваш контекст активности не удерживается вне его жизненного цикла. Рассмотрим, например, следующая проблема с приложением:

  1. ImageLoader создается внутри вашей деятельности
  2. Изображение начинается загрузка в фоновом процессе
  3. До тех пор, как фоновый процесс запущен, ссылка существует к деятельности, так как ссылки, что задача экземпляр SimpleImageLoadingListener создается внутри экземпляра деятельности
  4. в то же время, как вы закончите деятельность
  5. активность не GC'd, потому что ImageLoader ссылается SimpleImageLoadingListen эр, который ссылается на деятельность
  6. Начало новой деятельности превышает размер кучи и вызывает OOME

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

Надеюсь, это даст некоторое представление о проблеме!

+0

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

1

Большинство проблем с утечкой памяти связано с прямой ссылкой на экземпляр Context. В вашем случае переменная типа thisActivity является источником утечки.

Есть, по сути, способы избежать утечек памяти, вызванных непосредственными ссылками на контексты. Один очевидный выбор - использовать WeakReference для thisActivity и позволить GC очистить память.Если вы ищете более «андроидное» решение, вы можете либо переместить все ваши ссылки на активность в более локальную область (например, получить ссылку на действие непосредственно внутри метода), либо использовать контекст приложения, просто позвонив Context.getApplicationContext() или Activity.getApplication()

В блоге разработчиков Android есть замечательный blog post об этом, где вы можете получить более подробную информацию.

+0

Я переместил загрузчик изображений как одноэлементный компонент и ввел этот компонент в класс приложения. Я использовал только ссылку на bean из моего приложения при проблемной деятельности. Но все же куча растет каждый раз, когда я перезапускаю активность. Я также удалил thisActivity, и теперь я не держу никаких ссылок на свою деятельность. –

+0

Просто из любопытства, ваш ImageLoader или ваша деятельность когда-либо перерабатывают ваши растровые изображения? –

+0

Нет утечки памяти, когда я просто просматриваю изображения в одном и том же виде, проблема возникает, когда я снова и снова перезапускаю действие. –

Смежные вопросы