Webview内部存款和储蓄器泄漏消除办法2,webview泄漏

Webview内部存储器泄漏消除办法2,webview泄漏

  在此次支付进度中,需求用到webview展示一些分界面,可是加载的页面假设有过多图纸就能够意识内部存储器占用暴涨,而且在脱离该分界面后,即便在蕴藏该webview的Activity的destroy()方法中,使用webview.destroy();webview=null;对内部存款和储蓄器占回收用依旧尚未其余效果。有的人讲,一旦在您的xml布局中援用了webview乃至未有使用过,都会阻止重新步入Application之后对内部存款和储蓄器的gc。包涵动用MapView有时一会掀起OOM,几经周折在英特网看到各类解决办法,在此处跟我们分享一下。但是到这段日子截至还尚未找到根本的消除办法,英特网也可能有正是sdk的bug。可是无论怎么着,大家照旧要求动用的。

  要利用WebView不变成内部存款和储蓄器泄漏,首先应当做的便是无法在xml中定义webview节点,而是在急需的时候动态变化。即:能够在应用WebView的地方停放三个LinearLayout类似ViewGroup的节点,然后在要采用WebView的时候,动态生成即:

WebView      mWebView = new WebView(getApplicationgContext()); 
LinearLayout mll      = findViewById(R.id.xxx); 
mll.addView(mWebView);

  然后绝对要在onDestroy()方法中显式的调用

protected void onDestroy() {
      super.onDestroy();
      mWebView.removeAllViews();
      mWebView.destroy()
}

  注意: new  WebView(getApplicationgContext()) ;必须传入ApplicationContext若是传入Activity的Context的话,对内部存储器的引用会一向被保险着。有人用这些点子解决了当Activity被破除后依旧保持引用的标题。不过你会意识,假设您须求在WebView中展开链接或许你展开的页面带有flash,得到你的WebView想弹出二个dialog,都会产生从ApplicationContext到ActivityContext的强制类型调换错误,进而变成你使用崩溃。那是因为在加载flash的时候,系统会首先把你的WebView作为父控件,然后在该控件上绘制flash,他想找贰个Activity的Context来绘制他,不过你传入的是ApplicationContext。后果,你能够清楚了哈

  于是大牌们就Activity销毁后还保持引用这几个主题材料,提供了另一种消除办法:既然您不可能给本人删除援引,那么自身就自身来啊。于是上边包车型大巴这种办法诞生了:

public void setConfigCallback(WindowManager windowManager) {
    try {
        Field field = WebView.class.getDeclaredField("mWebViewCore");
        field = field.getType().getDeclaredField("mBrowserFrame");
        field = field.getType().getDeclaredField("sConfigCallback");
        field.setAccessible(true);
        Object configCallback = field.get(null);
 
        if (null == configCallback) {
            return;
        }
 
        field = field.getType().getDeclaredField("mWindowManager");
        field.setAccessible(true);
        field.set(configCallback, windowManager);
    } catch(Exception e) {
    }
}

  然后在Activity中调用上面包车型地铁艺术:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setConfigCallback((WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
}
 
public void onDestroy() {
    setConfigCallback(null);
    super.onDestroy();
}

  该反射方法在自己的实验中(2.3.6)确实有些用处,在利用内部存款和储蓄器占用到70M左右的时候会刚烈释放到50M只怕60M然后的放出就某些缓慢,其实正是看不出来了。以前在没动用该办法的时候也许高达120M。

只是!!!大家的行使供给占用内部存款和储蓄器更低啊,那肿么拌?盐水泡么?No。在各个纠结之后,终于找到了极端化解办法!!!该方法适用于大家的供给,在退出WebView的分界面之后,急迅回收内部存款和储蓄器。要问这么些办法是什么,不要9999,不要8999,只要您留意看好上边一句话:那正是为加载WebView的分界面开启新历程,在该页面退出之后关闭那几个进度。

那一点说了现在,你懂了啊?
但是在这些里面,杀死本人进度的时候又蒙受了难点,互连网介绍的各样艺术都糟糕使,
killBackgroundProcesses(getPackageName());种种不佳用,最终接纳System.exit(0);直接退出设想机(Android为每三个经过成立二个设想机的)。那几个一定不用纠结了,一旦退出,内部存款和储蓄器里面释放。听别人说QQ也是这么做。

  还应该有二个标题要说的,也是在WebView使用的时候出现的主题材料:WebView中包蕴二个ZoomButtonsController,当使用web.getSettings().setBuiltInZoomControls(true);启用该装置后,用户只要触摸荧屏,就能够出现缩放调节Logo。这一个图标过上几秒会自动消失,但在3.0系统以上上,就算Logo自动消失前退出当前Activity的话,就能发出ZoomButton找不到依据的Window而致使程序崩溃,化解办法很简短正是在Activity的ondestory方法中调用web.setVisibility(View.GONE);方法,手动将其遮蔽,就不会崩溃了。在3.0弹指间种类上不会出现该崩溃难点,真是各样崩溃,手足无措啊!

在这一次支付进度中,必要用到webview展现一些分界面,可是加载的页面倘诺有那一个图形就能够开采内部存款和储蓄器占用…

protected void onDestroy() {
      super.onDestroy();
      mWebView.removeAllViews();
      mWebView.destroy()
}

  于是大腕们就Activity销毁后还保持援引那一个标题,提供了另一种消除办法:既然您不能够给本人删除引用,那么本人就和好来啊。于是下边包车型大巴这种格局诞生了:

a. 不要在.xml文件中定义webview节点

无须再布局文件中定义webview的节点,而是在急需的时候动态变化。你能够在要求webview的布局位存放四个LinearLayout,要求时在代码中动态生成webview并add进去:

mWebView=new WebView(this);
LinearLayout linearLayout  = findViewById(R.id.xxx);
linearLayout.addView(mWebView);

接下来在onDestroy()方法中调用:

@Override
protected void onDestroy() {
if( mWebView!=null) {
   mWebView.setVisibility(View.GONE);
   mWebView.removeAllViews();
   mWebView.destroy();
}
super.onDestroy();
}

关于创制webview时mWebView=new
WebView(this);到底是传播ApplicationContext依旧Activity的context:个人建议依旧传activity的context。传ApplicationContext貌似可以卫戍webview对activity的援用,可是在相当多动静下会报错,非常多都有谈起webview加载的页面弹出dialog时会出现报错;所以传入activity的context然后办好销毁专门的学问。

WebView      mWebView = new WebView(getApplicationgContext()); 
LinearLayout mll      = findViewById(R.id.xxx); 
mll.addView(mWebView);

  在此番支付进度中,须求用到webview展示一些分界面,不过加载的页面假设有十分的多图纸就能意识内存占用暴涨,况兼在脱离该分界面后,即便在蕴含该webview的Activity的destroy()方法中,使用webview.destroy();webview=null;对内部存款和储蓄器占回收用照旧尚未别的意义。有的人说,一旦在你的xml布局中引用了webview以至未有采纳过,都会堵住重新步向Application之后对内部存款和储蓄器的gc。满含使用MapView有时一会抓住OOM,几经周折在英特网来看各个化解办法,在此地跟大家大饱眼福一下。然则到最近结束还从未找到根本的化解办法,网络也是有正是sdk的bug。不过不论怎么,大家照旧供给利用的。

5.Handler产生的内部存款和储蓄器泄漏

自身在本人的连串中选拔了handler,此时mHandler会隐式地有着一个外表类对象援引这里正是MainActivity,当试行postDelayed方法时,该方法会将您的Handler装入三个Message,并把那条Message推到MessageQueue中,MessageQueue是在二个Looper线程中连连轮询处理音讯,那么当以此Activity退出时消息队列中还会有未管理的音信照旧正在处理音讯,而消息队列中的Message持有mHandler实例的援引,mHandler又独具Activity的引用,所以产生该Activity的内部存款和储蓄器能源不能马上回收,引发内部存储器泄漏。

public class MainActivity extends AppCompatActivity {
private Handler mHandler = new Handler();
private TextView mTextView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_handler);

    mTextView = (TextView) findViewById(R.id.text);//模拟内存泄露
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            mTextView.setText("test");
        }
    }, 5 * 60 * 1000);
}
}

消除办法是 在HandlerActivity
onDestroy里面移除音讯队列中全体消息和具有的Runnable。

@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
mHandler = null;
}

另外原因促成的内部存款和储蓄器泄漏
致使内部存款和储蓄器泄漏的来头有不知凡几,大家那边只是列举了内部比较独立的二种,当然还应该有非常的多缘故会招致内部存款和储蓄器泄漏,举个例子财富开启不过未关门、多线程等等等等。然则我们有LeakCanary其一利器哈。

  于是大拿们就Activity销毁后还维持援引那些难点,提供了另一种化解办法:既然您无法给本身删除援用,那么笔者就和睦来吗。于是上面包车型大巴这种办法诞生了:

WebView      mWebView = new WebView(getApplicationgContext()); 
LinearLayout mll      = findViewById(R.id.xxx); 
mll.addView(mWebView);
c. 进程

为加载WebView的分界面开启新历程,在该页面退出之后关闭这几个进程。
那么些方法本人未有测量检验,不知道应用和效应怎么着,有意思味的能够试试。

  该反射方法在自家的实施中(2.3.6)确实有个别用处,在使用内部存款和储蓄器占用到70M左右的时候会明显释放到50M恐怕60M然后的获释就有个别缓慢,其实正是看不出来了。以前在没动用该情势的时候恐怕达到120M。

那或多或少说精晓后,你懂了吗?
然而在这几个里面,杀死自个儿进程的时候又赶过了难题,英特网介绍的种种措施都不好使,
killBackgroundProcesses(getPackageName());各样倒霉用,最终选拔System.exit(0);间接退出设想机(Android为每三个进程创制多少个虚构机的)。这么些一定不用纠结了,一旦退出,内部存款和储蓄器里面释放。听外人说QQ也是那般做。

3.非静态内部类创立静态实例变成的内部存款和储蓄器泄漏

public class NonStaticActivity extends AppCompatActivity {
private static Config sConfig;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_non_static);
    //Config类并不是静态类,
    sConfig = new Config();
}
class Config {

}
}

率先,非静态内部类暗许会持有外界类的引用。
接下来又采取了该非静态内部类成立了三个静态的实例。
该静态实例的生命周期和行使的完全一样长,那就招致了该静态实例一向会有所该Activity的引用,导致Activity的内部存款和储蓄器能源不能健康回收。
是的的做法有二种,一种是将中间类Config改成静态内部类,还应该有正是将Config抽取出来,封装成二个单例,如上一个例子那样,可是急需context时单例要铭记在心注意Context的走漏,使用applicationContext。

发表评论

电子邮件地址不会被公开。 必填项已用*标注