Android Context使用详解

本文详细讲解了Android中的Context类及其用法,涵盖了启动Activity、创建View、 inflating布局、发送广播、Service与ContentProvider操作,以及Context内存泄露的防范。特别强调了单例模式下避免内存泄漏的最佳实践。
摘要由CSDN通过智能技术生成

一.Context概述

1.Context是一个抽象类,其通用实现在ContextImpl类中。它的主要作用是一个访问application环境全局信息的接口,包括为Activities, Fragments, and Services提供访问resource files, images, themes/styles等相关的类,其具体结构类图如下:

二.Context使用

1.启动Activity

1).java方式

Intent intent = new Intent(context, MyActivity.class);
startActivity(intent);

2).kotlin方式

val intent = Intent(context, MyActivity::class.java)
startActivity(intent)

2.创建View,

1).java方式

TextView textView = new TextView(context);

2).kotlin方式

val textView = TextView(context)

此外Contexts也包含view需要的一些信息,eg:

1‘. 将dp、sp 转换为像素的设备屏幕尺寸和维度
2'. styled属性
3'. activity onclick关联的属性

3.Inflating一个XML布局文件

1).java方式

LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.my_layout, parent);

2).kotlin方式

val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.my_layout, parent)

4.发送广播

1).java方式

Intent broadcastIntent = new Intent("action");
LocalBroadcastManager.getInstance(context).sendBroadcast(broadcastIntent);

2).kotlin方式

val broadcastIntent = Intent("action")
LocalBroadcastManager.getInstance(context).sendBroadcast(broadcastIntent)

5.获取系统Service,eg:发送通知,通知管理获取

1).java方式

NotificationManager notificationManager = 
    (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

int notificationId = 1;

// Context is required to construct RemoteViews
Notification.Builder builder = 
    new Notification.Builder(context).setContentTitle("title");

notificationManager.notify(notificationId, builder.build());

2).kotlin方式

val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

val notificationId = 1

// Context is required to construct RemoteViews
val builder = Notification.Builder(context).setContentTitle("title")

notificationManager.notify(notificationId, builder.build())

6.Application和Activity Context对比

在传递Context参数的时候,如果是在Activity中,我们可以传递this(这里的this指的是Activity.this,是当前Activity的context)或者Activity.this。这个时候如果我们传入getApplicationContext(),我们会发现这样也是可以用的。可是大家有没有想过传入Activity.this和传入getApplicationContext()的区别呢?首先Activity.this和getApplicationContext()返回的不是同一个对象,一个是当前Activity的实例,一个是项目的Application的实例,这两者的生命周期是不同的,它们各自的使用场景不同,this.getApplicationContext()取的是这个应用程序的Context,它的生命周期伴随应用程序的存在而存在;而Activity.this取的是当前Activity的Context,它的生命周期则只能存活于当前Activity,这两者的生命周期是不同的。getApplicationContext() 生命周期是整个应用,当应用程序摧毁的时候,它才会摧毁;Activity.this的context是属于当前Activity的,当前Activity摧毁的时候,它才摧毁。

7.Context的应用场景

ApplicationActivityServiceContentProviderBroadcastReceiver
New a DialogNOYESNONONO
Start ActivityNO1YESNO1NO1NO1
Inflation LayoutNO2YESNO2NO2NO2
Start ServiceYESYESYESYESYES
Bind ServiceYESYESYESYESNO
Send BroadcastYESYESYESYESYES
Register BroadcastReceiverYESYESYESYESNO3
Load ResourceYESYESYESYESYES

大家注意看到有一些NO后面添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?解释如下:

NO1:启动Activity在这些类中是可以的,但是需要创建一个新的task。一般情况不推荐。
NO2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。
NO3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。

8.Context的数量计算

Context个数=Activity数+Service数+1(Application)

三.Context内存泄露问题

1.单例模式导致内存泄漏

1).java demo

public class CustomManager {
    private static CustomManager sInstance;

    public static CustomManager getInstance(Context context) {
        if (sInstance == null) {

            // This class will hold a reference to the context
            // until it's unloaded. The context could be an Activity or Service.
            sInstance = new CustomManager(context);
        }

        return sInstance;
    }

    private Context mContext;

    private CustomManager(Context context) {
        mContext = context;
    }
}

2).kotlin demo

class CustomManager private constructor(private val context: Context) {
    companion object {
        @Volatile
        private var instance: CustomManager? = null

        fun getInstance(context: Context): CustomManager {
            val i = instance
            if (i != null) {
                return instance as CustomManager
            }
            return synchronized(this) {
                val i2 = instance
                if (i2 != null) {
                    i2
                } else {
                    val created = CustomManager(context)
                    instance = created
                    created
                }
            }
        }
    }
}

上面demo有内存泄露的隐患,如果是在Activity中创建这个单例的话,传入的context为Activity的context,如果想要销毁Activity,但是单例的生命周期是整个应用,导致Activity的内存不能完全释放,

正确的方法是将application context存储在CustomManager.getInstance()中。 application context是一个单例,并且与应用程序进程的生命周期相关联,因此可以安全地存储对它的引用。

如果在组件的生命周期之外需要Context引用,或者它应该独立于传入的Context的生命周期,请使用application context。eg:

1).java方式

public static CustomManager getInstance(Context context) {
    if (sInstance == null) {

        sInstance = new CustomManager(context.getApplicationContext());
    }

    return sInstance;
}

2).kotlin方式

class CustomManager private constructor(private val context: Context) {
    companion object {
        fun getInstance(context: Context): CustomManager {

            val created = CustomManager(context.applicationContext)
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值