我真的在解决这个问题,但找不到解决方案,期望这种不自然的方式https://stackoverflow.com/a/2866717/2008040
我有一个活动(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 :(得分:1)
在完成活动时堆没有减少的事实表明GC无法处理它。一个典型的罪魁祸首是持久对象仍然持有对它的引用。
我建议您检查一下您所拥有的内容,以确保您的活动上下文不会被保留到其生命周期之外。例如,考虑您的应用程序存在以下问题:
一个可能的解决方案是拥有一个单例SimpleImageLoadingListener,您可以在创建活动时连接它。
我希望这可以提供一些有关问题的见解!
答案 1 :(得分:1)
大多数内存泄漏问题都是由于直接引用了Context实例。在您的情况下,thisActivity
变量是泄漏的来源。
thisActivity
并允许GC清理内存。如果您正在寻找更多&#34; androidy&#34;解决方案,您可以将所有活动引用移动到更本地的范围(例如直接在方法中获取活动引用),或者您可能只想通过调用Context.getApplicationContext()
或Activity.getApplication()
<来使用应用程序上下文/ p>
Android开发者博客中有一个很棒的blog post,您可以从中获取更详细的信息。
答案 2 :(得分:0)
好的,我发现了这个问题。
我用MAT来分析我的内存泄漏,在用MAT检查我的转储时,我意识到两个独立的库导致了这个问题。顺便说一下,如果您需要有关MAT View Pager Memory Leak with Bitmaps and Volley
的更多信息,这是一个很好的主题我的第一次泄漏是ACRA。 ACRA是一种崩溃报告工具,因为它是崩溃报告工具的自然行为,ACRA始终保留对最近关闭的活动的引用,直到另一个活动开始。但实际上这不是一个大问题,因为ACRA在用户启动另一项活动后立即发布其参考。所以ACRA并不是我获得OOME的主要原因。
我的第二个漏洞是谷歌广告。我无法找到确切的原因但是当我完成我的活动时,Google广告始终会保留对我的viewPager的引用并再次打开该活动,导致应用因OOME而崩溃。目前我只是删除该活动的广告,但稍后会解决此问题。
感谢宝贵的评论。