Android工具类Context详细解析
一、概述
Context对象可以获取应用状态的信息、其使得activitys和Fragments以及Services能够使用资源文件、图片、主题、以及其他的文件夹内容、其也可以用于使用Android自带服务、例如inflate、键盘、以及content providers
很多情况下、当你需要用到Context的时候、你肯定只是简单的利用当前activity的实例this、当你一个被activity创建的内部对象的时候、例如adapters里或者fragments里的时候、你需要将activity的实例传给它们、而当你在activity之外、例如application或者service的时候、我们需要利用application的context对象代替
二、Contex启动组件
明确地启动一个组件、例如在activity或者service中直接启动一个组件
Intent intent = new Intent(context, MyActivity.class); startActivity(intent);
三、Contex创建视图
Contexts包含了以下信息、设备的屏幕大小以及将dp、sp转化为px的尺寸、style属性、onClick属性
TextView textView = new TextView(context);
四、Contex Inflate xml布局文件
我们使用context来获得LayoutInflater、其可以在内存中inflate xml布局文件
LayoutInflater inflater = LayoutInflater.from(context); inflater.inflate(R.layout.my_layout, parent);
五、Contex 发送本地广播
我们使用context来获得LocalBroadcastManager、其可以发送或者注册广播接收
Intent broadcastIntent = new Intent("custom-action"); LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
六、Contex 获取系统服务
例如当你需要发送通知、你需要NotificationManager
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); int notificationId = 1; // Context is required to construct RemoteViews Notification.Builder builder = new Notification.Builder(context).setContentTitle("custom title"); notificationManager.notify(notificationId, builder.build());
七、应用级别的Context和Activity级别的Context
当主题被运用在应用层面、其也可被运用在activity层面、比如当应用层面定义了一些主题、activity可以将其覆盖
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/MyCustomTheme" >
大部分视图需要传入activity级别的Context对象、这样其才能获取主题、styles、dimensions等属性、如果某个控件没有使用theme、其默认使用了应用的主题、在大部分情况下、你需要使用activity级别的Context、通常、关键字this代表着一个类的实例、其可被用于activity中的Context传递、例如
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toast.makeText(this, "hello", Toast.LENGTH_SHORT).show(); } }
八、匿名方法
当我们使用了匿名内部类的适合、例如实现监听、this关键字的使用
@Override protected void onCreate(Bundle savedInstanceState) { TextView tvTest = (TextView) findViewById(R.id.abc); tvTest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "hello", Toast.LENGTH_SHORT).show(); } }); } }
九、数组适配器
当你为listview定义适配器的适合、getContext()方法被经常使用、其用来实例化xml布局、注意:当你传入的是应用级别的context,你会发现themes/styles属性将不会被应用、所以确保你在这里传入的是Activity级别的context
if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.item_user, parent, false); }
十、RecyclerView适配器
ArrayAdapter需要在其构造器里面传入context、RecyclerView.Adapter不需要、RecyclerView通常将其作为父视图传给RecyclerView.Adapter.onCreateViewHolder()
如果在onCreateViewHolder()方法的外面、你需要用到context、你也可以使用ViewHolder、例如viewHolder.itemView.getContext()、itemView是一个公有、非空、final类型的成员变量
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> { @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(itemLayout, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(ViewHolder viewHolder, int i) { // If a context is needed, it can be retrieved // from the ViewHolder´s root view. Context context = viewHolder.itemView.getContext(); // Dynamically add a view using the context provided. if(i == 0) { TextView tvMessage = new TextView(context); tvMessage.setText("Only displayed for the first item.") viewHolder.customViewGroup.addView(tvMessage); } } public static class ViewHolder extends RecyclerView.ViewHolder { public FrameLayout customViewGroup; public ViewHolder(view imageView) { super(imageView); // Perform other view lookups. customViewGroup = (FrameLayout) imageView.findById(R.id.customViewGroup); } } }
十一、避免内存泄露
应用级别的context通常在单例中使用、例如一个常用的管理类、其管理Context对象来获取系统服务、但是其不能同时被多个activity获取、由于维护一个activity级别的context引用会导致内存泄露、所以你需要使用application级别的context替代
在下面这个例子中、如果context是activity级别或者service级别、当其被destroy、其实际不会被gc, 因为CustomManager类拥有了其static应用
pubic 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; } }
十二、适当地存储context:利用应用级别context
为了避免内存泄露、不要在其生命周期以外持有该对象、检查你的非主线程、pending handlers或者内部类是否持有context对象、存储应用级别的context的最好的办法是CustomManager.getInstance()、其为单例、生命周期为整个应用的进程
public static CustomManager getInstance(Context context) { if (sInstance == null) { // When storing a reference to a context, use the application context. // Never store the context itself, which could be a component. sInstance = new CustomManager(context.getApplicationContext()); } return sInstance; }
下一篇: FFMPEG采集摄像头推流方法说明