这是一个系列,我们将其命名为工具箱,如果你还没有看之前的文章:

Android工具箱之文件目录

Android工具箱之组织你的代码文件

Android工具箱之理解app资源文件

Android工具箱之Activity生命周期

Android工具箱之迁移到AppCompat

Android工具箱之Android 6.0权限管理

这几天一直在思考一个问题,为什么国内的热门博客和热门教程都是很久之前的,例如我向学习EventBus,不论是鸿洋的博文还是其他论坛,几乎清一色的OnEvent,或者比如我想学习Dagger2,文章数量更是少之又少,关键大量还是Dagger1的内容。

基于此,外加上看到CodePath公司整合的Android资源正好符合实际需求,所以特意在sg开辟专栏,希望大家能够喜欢,在此申明下,因为工作量巨大,我非常有幸能够同@xixicat一起翻译这一专题,也恳请大家,如遇到任何翻译错误,请指正,可评论中注明,也可电邮我,同时如果某位志趣相投人士有兴趣参与翻译,也可电邮我,我会进一步联系你:neuyuandaima@gmail.com。

废话不多说,那么我们就开始吧。

动机

你有多少次在StackOverflow中寻找答案时,发现其答案竟然是2年前的,你又有多少次搜出的博文是几年前的旧文呢,我相信绝大部分的你都有这样的经历,所以我们为什么不能利用社交让我们的的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);

创建视图

TextView textView = new TextView(context);

Contexts包含了以下信息:

  • 设备的屏幕大小以及将dp,sp转化为px的尺寸。

  • style属性

  • onClick属性

inflate xml布局文件

我们使用context来获得LayoutInflater,其可以在内存中inflate xml布局文件

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

发送本地广播

我们使用context来获得LocalBroadcastManager,其可以发送或者注册广播接收。

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

获取系统服务

例如当你需要发送通知,你需要NotificationManager。

NotificationManager manager =     (NotificationManager) getSystemService(NOTIFICATION_SERVICE);int notificationId = 1;// Context is required to construct RemoteViewsNotification.Builder builder =     new Notification.Builder(context).setContentTitle("custom title");notificationManager.notify(notificationId, builder.build());

在此就不一一列举系统服务了,系统服务列表参见。

应用级别的Context和Activity级别的Context

当主题被运用在应用层面,其也可被运用在activity层面,比如当应用层面定义了一些主题,activity可以将其覆盖。

                  

大部分视图需要传入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关键字的使用:

public class MainActivity extends AppCompatActivity {    @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布局。

if (convertView == null) {      convertView =           LayoutInflater              .from(getContext())              .inflate(R.layout.item_user, parent, false);   }

注意:当你传入的是应用级别的context,你会发现themes/styles属性将不会被应用,所以确保你在这里传入的是Activity级别的context。

RecyclerView适配器

public class MyRecyclerAdapter extends RecyclerView.Adapter {    @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);       }   }}

可以看到,ArrayAdapter需要在其构造器里面传入context,RecyclerView.Adapter不需要。

RecyclerView通常将其作为父视图传给RecyclerView.Adapter.onCreateViewHolder()。

如果在onCreateViewHolder()方法的外面,你需要用到context,你也可以使用ViewHolder,例如viewHolder.itemView.getContext()。
itemView是一个公有,非空,final类型的成员变量。

避免内存泄露

应用级别的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;}

参考

  • What is a context - Simple Code Stuffs

  • Context, what context - Possible Mobile

  • Context: What, where, & how? - 101 Apps

  • What is a context - Stack Overflow

  • Avoiding memory leaks

更多相关文章

  1. Android(安卓)平台基础开发简介
  2. [Android] 基于 Linux 命令行构建 Android(安卓)应用(一):关于 Andr
  3. Android小项目合集(经典教程)包含十五个Android开发应用实例
  4. android 入门之二【android 体系架构】
  5. Android(安卓)4层框架
  6. Android移动应用基础学习——第二章UI开发
  7. 【Android(安卓)Basics】Android是什么? (What is Android?)
  8. Android深入四大组件(一)应用程序启动过程
  9. Android中minSdkVersion、targetSdkVersion、maxSdkVersion的作

随机推荐

  1. android 添加对back按钮的处理,点击提示退
  2. Android Studio 搭建 + 第一个helloworld
  3. ubuntu10.0.4 android2.2 编译总结
  4. App自动化测试--Android环境搭建
  5. Android打开应用市场
  6. Gps简单更新
  7. 收藏代码-Android状态栏工具代码
  8. android读取联系人信息(学习版)
  9. Customize "share picture via" menu on
  10. android透明视图