zoukankan      html  css  js  c++  java
  • Android开发 静态static类与static方法持有Context是否导致内存泄露的疑问

    简述

      在Android开发的过程中,难免会使用单例模式或者静态方法工具类.我们会让它们持有一些外部的Context或者View一般有以下几种情况:

    1.   单例模式,类的全局变量持有Context 或 View (注意!持有View和持有Context其实是一样的) ----->此方式会内存泄露
    2.   单例模式,方法引入Context  ----->此方式不会内存泄露
    3.   工具类静态方法持有Context 或 View
    4.   工具类静态变量持有Context 或 View

      上面我已经说明了会内存泄露的情况,我们就来逐一详细说明下如何操作,和证明他们是否会内存泄露

    Context的类型认识

      在讲解关于静态持有Context之前,我们需要来认识一下Context自己的区别,原则上Context其实只有2种(尽管Activity/Fragment/Service/都有Context,但是实际上他们属于一个类型的Context)

      第一种

    应用的Context,下面的2行代码都是调用应用的Context,这个Context在一个app里只会有一个.并且在App启动时创建,App关闭时消亡,所以这个Context是贯彻App生命周期全程的.

    Context applicationContext = getApplicationContext();
    Context baseContext = getBaseContext();

      第二种

    Activity 或者 Service 自己,Activity 或 Service自己本身就是Context,这种Context的生命周期只在Activity或Service的生命周期下,关闭了Activity后Context理所应当的也随着消亡.有多少Activity和Service就会有多少个Context,并且重复多次创建某个Activity的时候Context也是多个

    单例模式持有Context的情况

    第一种情况 单例模式,类的变量持有Context 或 View  此方式会内存泄露

    首先说明,持有View和持有Context都是一样的道理,所以我这里就不在验证持有View的情况

     验证顺序是这样的,我在MainActivity里反复启动退出TestActivity,然后在TestActivity的onCreate方法里调用单例类并且让它持有Context,然后我们在用Android studio自带的内存泄露工具来分析.在这篇中,我将贴全代码,后续只会将单例类或者工具类贴出.

     首先我们创建一个简单的单例模式,并且让它的全局变量持有Context

    public class SingleMode {
        private static SingleMode mSingleMode;
        private Context mContext;
        private SingleMode(){
    
        }
    
        public static synchronized SingleMode I(){
            if (mSingleMode == null){
                mSingleMode = new SingleMode();
            }
    
            return mSingleMode;
        }
    
        public void setContext(Context context){
            this.mContext = context;
        }
    }

    然后让TestActivity里让调用这个单例类

    public class TestActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_test);
            SingleMode.I().setContext(this);
    
        }
    }

    然后我们在MainActivity里启动这个TestActivity

    public class MainActivity extends AppCompatActivity {
        private static final String TAG = MainActivity.class.getName();
        private Button btn1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            btn1 = findViewById(R.id.btn1);
            btn1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this,TestActivity.class);
                    startActivity(intent);
                    
                }
            });    
        }
    }

    手动反复进出多次,然后我们在退出到MainActivity里,抓取内存泄露信息

    从内存泄露分析里,可以看到我已经返回到MainActivity有一段时间了,并且主动手动清理一次内存,但是在查找包下面我们依然可以看到TestActivity在存活,并且存活了多个,而SingleMode在存活是正常的因为静态存活时间是最长的.换句话说就是因为SingleMode在存活并且持有Context才导致内存泄露了

    第二种情况 单例模式,方法引入Context

    工具类持有Context的情况

    待续...

  • 相关阅读:
    网页内容切换效果实现的15个jQuery插件
    【转】C#获取客户端及服务器端主机信息及其获取IP地址
    EnableViewState 属性
    Dictionary字典类使用范例
    AspNetPager分页控件官方网站
    [区别]APPlication,Session,Cookie,ViewState和Cache
    C#特性之数据类型
    WindowsPhone8.1 开发技巧
    关于在WP8.1中使用剪贴板的问题
    MVC中使用JQuery方式进行异步请求和使用自带方式进行异步请求
  • 原文地址:https://www.cnblogs.com/guanxinjing/p/10701192.html
Copyright © 2011-2022 走看看