Android工具类Context详细解析
2016-01-15 10:53:24  By: shinyuu

一、概述

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;
}


若资源对你有帮助、浏览后有很大收获、不妨小额打赏我一下、你的鼓励是维持我不断写博客最大动力

想获取DD博客最新代码、你可以扫描下方的二维码、关注DD博客微信公众号(ddblogs)

或者你也可以关注我的新浪微博、了解DD博客的最新动态:DD博客官方微博(dwtedx的微博)

如对资源有任何疑问或觉得仍然有很大的改善空间、可以对该博文进行评论、希望不吝赐教

为保证及时回复、可以使用博客留言板给我留言: DD博客留言板(dwtedx的留言板)

感谢你的访问、祝你生活愉快、工作顺心、欢迎常来逛逛


快速评论


技术评论

    • dearbaba 2016-01-17 11:44:35  1 评  | 回复

      推荐个搜索博客问答的IT搜索引擎 http://www.itdaan.com 。


DD记账
top
+