button是Android 中常用的控件, 父类是 Textview, 在之前的文章中对 Textview的一些 基本信息都介绍过, 还包括Textview的 之 setText方法 带来的一些 性能问题。 这篇文章就讲到了 button的一些使用要注意的地方。

这些需要注意的 还包括了 Textview 已经一些 Textview的 子类 如 CheckBox,EditText 等等 一些控件。 问题的产生

button 我们一般都会给它 设置一个background,许多人会做成selector 或者 shape ,layer-list等等一些 资源。

有的做的漂亮的项目 会给 按钮 两张图片 ,一张 是选中 或者点击状态,另外一张 则是 正常状态。


<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">      <!-- checked -->    <item android:drawable="@drawable/language_press" android:state_checked="true"/>    <!-- default -->    <item android:drawable="@drawable/language_no_press" android:state_checked="false"/></selector></span>

那么这样使用 就使得 xml加载的时候 这两张图片也加载了, 也就是一个按钮 就占用了 两张 图片的内存,这是不合理的。 那有人说 我都这么用 没一点事, 确实 随着现在 机器硬件的提升,以及Android本身系统的优化 等 大幅提高了效率, 使得这种 问题 变的不会很明显, 你一个xml 可能 使用带有图片的 selector 可能也就那么几个 不会很多。 那么我们讲的是为什么 会出现这个问题 ,怎么避免。 至于一些 临界点(使用多少会出现性能问题 造成卡顿)暂不关心。

那么 为什么会加载两张,因为我们在 xml中配置,Drawable.java的createFromXmlInner方法中对图片进行解析,最终调用Drawable的inflate方法),相当于一个按钮占用了两张相同大小图片所使用的内存。 我们来看看 源码

<span style="font-size:18px;"> public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)    throws XmlPullParserException, IOException {        Drawable drawable;        final String name = parser.getName();        if (name.equals("selector")) {            drawable = new StateListDrawable();        } else if (name.equals("level-list")) {            drawable = new LevelListDrawable();        /* Probably not doing this.        } else if (name.equals("mipmap")) {            drawable = new MipmapDrawable();        */        } else if (name.equals("layer-list")) {            drawable = new LayerDrawable();        } else if (name.equals("transition")) {            drawable = new TransitionDrawable();        } else if (name.equals("color")) {            drawable = new ColorDrawable();        } else if (name.equals("shape")) {            drawable = new GradientDrawable();        } else if (name.equals("scale")) {            drawable = new ScaleDrawable();        } else if (name.equals("clip")) {            drawable = new ClipDrawable();        } else if (name.equals("rotate")) {            drawable = new RotateDrawable();        } else if (name.equals("animated-rotate")) {            drawable = new AnimatedRotateDrawable();                    } else if (name.equals("animation-list")) {            drawable = new AnimationDrawable();        } else if (name.equals("inset")) {            drawable = new InsetDrawable();        } else if (name.equals("bitmap")) {            drawable = new BitmapDrawable(r);            if (r != null) {               ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());            }        } else if (name.equals("nine-patch")) {            drawable = new NinePatchDrawable();            if (r != null) {                ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());             }        } else {            throw new XmlPullParserException(parser.getPositionDescription() +                    ": invalid drawable tag " + name);        }        drawable.inflate(r, parser, attrs);        return drawable;    }</span>

可以看到 源码中 做了 很多判断,根据xml中的配置 加载了 不同的资源(我的源码可能是老版本的,新版本的 我看了 做了优化 匹配都变为了 switch/case模式)。可以看到 使用图片的话 会用BitmapDrawable , 使用BitmapDrawable 这个类里面的inflate的方法。 会将图片加载到内存中。并绘制出来

如果在内存吃紧的情况下 做一些 小优化还是非常有必要的。

比如 在 图片是 纯颜色的 时候 建议selector 里面使用 颜色 而不使用 图片。具体原因 还是源码

下面是BitmapDrawable的inflate方法


<span style="font-size:18px;"> @Override    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)            throws XmlPullParserException, IOException {        super.inflate(r, parser, attrs);        TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.BitmapDrawable);        final int id = a.getResourceId(com.android.internal.R.styleable.BitmapDrawable_src, 0);        if (id == 0) {            throw new XmlPullParserException(parser.getPositionDescription() +                    ": <bitmap> requires a valid src attribute");        }        final Bitmap bitmap = BitmapFactory.decodeResource(r, id);        if (bitmap == null) {            throw new XmlPullParserException(parser.getPositionDescription() +                    ": <bitmap> requires a valid src attribute");        }        mBitmapState.mBitmap = bitmap;        setBitmap(bitmap);        setTargetDensity(r.getDisplayMetrics());        final Paint paint = mBitmapState.mPaint;        paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,                paint.isAntiAlias()));        paint.setFilterBitmap(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_filter,                paint.isFilterBitmap()));        paint.setDither(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_dither,                paint.isDither()));        setGravity(a.getInt(com.android.internal.R.styleable.BitmapDrawable_gravity, Gravity.FILL));        int tileMode = a.getInt(com.android.internal.R.styleable.BitmapDrawable_tileMode, -1);        if (tileMode != -1) {            switch (tileMode) {                case 0:                    setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);                    break;                case 1:                    setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);                    break;                case 2:                    setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);                    break;            }        }        a.recycle();    }</span>

下面是ColorDrawable的inflate的源码

<span style="font-size:18px;"> @Override    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)            throws XmlPullParserException, IOException {        super.inflate(r, parser, attrs);        TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ColorDrawable);        int color = mState.mBaseColor;        color = a.getColor(com.android.internal.R.styleable.ColorDrawable_color, color);        mState.mBaseColor = mState.mUseColor = color;        a.recycle();    }</span>

具体一对比,不说细节,光说代码量就能说明一点问题了吧。 如果非要使用 图片,就用代码 进行动态设置。

给要使用的view加 onTouch事件,在 down,和move的时候为 点击状态, up为正常状态。觉得每一个设置太麻烦?

那就封装一个方法

<span style="font-size:18px;">    public void changeImage(View view, final int normalResId, final int pressResId){        view.setOnTouchListener(new OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                switch(event.getAction()){                   case MotionEvent.ACTION_DOWN:                       v.setBackgroundResource(pressResId);                      break;                        case MotionEvent.ACTION_MOVE:                            v.setBackgroundResource(pressResId);                            break;                        case MotionEvent.ACTION_UP:                            v.setBackgroundResource(normalResId);                      break;                 }             // 为了不影响其他事件              return false;            }        });    }</span>



这样不仅 节省了内存, 而且 能减小apk包的大小(不需要每个都写 selector.xml了)

有些 边框,线条,圆角等等 能自己写 stroke,layer-list,shape 就尽量使用。 对内存和性能 比图片更好一点





更多相关文章

  1. 安卓(Android)实现选择时间功能
  2. Android(安卓)使用Glide加载图片
  3. Android中对MIME类型的理解
  4. Android高手进阶教程(十一)之----Android(安卓)通用获取Ip的方法
  5. Android(安卓)上层应用读写设备节点
  6. Android(安卓)Studio导入SlidingMenu类库的方法(其他类库应该也适
  7. 总结系列-硬件加速
  8. Android(安卓)Studio的基本控件 图片框与进度条
  9. Android中Window的管理深入讲解

随机推荐

  1. SQL判断语句用法和多表查询
  2. SQLServer获取临时表所有列名或是否存在
  3. Sql Server中Substring函数的用法实例解
  4. Mysql数据库性能优化三(分表、增量备份、
  5. SQL where条件和jion on条件的详解及区
  6. SQL 多条件查询几种实现方法详细介绍
  7. SQL Server附加数据库报错无法打开物理文
  8. SQL Server简单查询示例汇总
  9. 浅谈SQL Server交叉联接 内部联接
  10. SqlServer 注释符 单行注释与多行注释