服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

面试题:Android 的 Intent 采用了什么设计模式?

日期: 来源:AndroidPub收集编辑:小虾米君


答案是采用了原型模式

“原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。”

原型模式的好处在于方便地拷贝某个实例的属性进行使用、又不会对原实例造成影响,其逻辑在于对 Cloneable 接口的实现。

话不多说看下 Intent 的关键源码:

// frameworks/base/core/java/android/content/Intent.java
public class Intent implements Parcelable, Cloneable {
    ...
    private static final int COPY_MODE_ALL = 0;
    private static final int COPY_MODE_FILTER = 1;
    private static final int COPY_MODE_HISTORY = 2;

    @Override
    public Object clone() {
        return new Intent(this);
    }

    public Intent(Intent o) {
        this(o, COPY_MODE_ALL);
    }

    private Intent(Intent o, @CopyMode int copyMode) {
        this.mAction = o.mAction;
        this.mData = o.mData;
        this.mType = o.mType;
        this.mIdentifier = o.mIdentifier;
        this.mPackage = o.mPackage;
        this.mComponent = o.mComponent;
        this.mOriginalIntent = o.mOriginalIntent;
        ...

        if (copyMode != COPY_MODE_FILTER) {
            ...
            if (copyMode != COPY_MODE_HISTORY) {
                ...
            }
        }
    }
    ...
}

可以看到 Intent 实现的 clone() 逻辑是直接调用了 new 并传入了自身实例,而非调用 super.clone() 进行拷贝。

默认的拷贝策略是 COPY_MODE_ALL,顾名思义,将完整拷贝源实例的所有属性进行构造。其他的拷贝策略是 COPY_MODE_FILTER 指的是只拷贝跟 Intent-filter 相关的属性,即用来判断启动目标组件的 action、data、type、component、category 等必备信息。无视启动 flag、bundle 等数据。

// frameworks/base/core/java/android/content/Intent.java
public class Intent implements Parcelable, Cloneable {
    ...
    public @NonNull Intent cloneFilter() {
        return new Intent(this, COPY_MODE_FILTER);
    }

    private Intent(Intent o, @CopyMode int copyMode) {
        this.mAction = o.mAction;
        ...

        if (copyMode != COPY_MODE_FILTER) {
            this.mFlags = o.mFlags;
            this.mContentUserHint = o.mContentUserHint;
            this.mLaunchToken = o.mLaunchToken;
            ...
        }
    }
}

还有中拷贝策略是 COPY_MODE_HISTORY,不需要 bundle 等历史数据,保留 action 等基本信息和启动 flag 等数据。

// frameworks/base/core/java/android/content/Intent.java
public class Intent implements Parcelable, Cloneable {
    ...
    public Intent maybeStripForHistory() {
        if (!canStripForHistory()) {
            return this;
        }
        return new Intent(this, COPY_MODE_HISTORY);
    }

    private Intent(Intent o, @CopyMode int copyMode) {
        this.mAction = o.mAction;
        ...

        if (copyMode != COPY_MODE_FILTER) {
            ...
            if (copyMode != COPY_MODE_HISTORY) {
                if (o.mExtras != null) {
                    this.mExtras = new Bundle(o.mExtras);
                }
                if (o.mClipData != null) {
                    this.mClipData = new ClipData(o.mClipData);
                }
            } else {
                if (o.mExtras != null && !o.mExtras.isDefinitelyEmpty()) {
                    this.mExtras = Bundle.STRIPPED;
                }
            }
        }
    }
}

总结起来:

Copy Modeaction 等数据flags 等数据bundle 等历史
COPY_MODE_ALLYESYESYES
COPY_MODE_FILTERYESNONO
COPY_MODE_HISTORYYESYESNO

除了 Intent,Android 源码中还有很多地方采用了原型模式。

  • Bundle 也实现了 clone(),提供了 new Bundle(this) 的处理:

    public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        ...
        @Override
        public Object clone() {
            return new Bundle(this);
        }
    }
  • 组件信息类 ComponentName 也在 clone() 中提供了类似的实现:

    public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> {
        ...
        public ComponentName clone() {
            return new ComponentName(mPackage, mClass);
        }
    }
  • 工具类 IntArray 亦是如此:

    public class IntArray implements Cloneable {
        ...
        @Override
        public IntArray clone() {
            return new IntArray(mValues.clone(), mSize);
        }
    }

原型模式也不一定非得实现 Cloneable,提供了类似的实现即可。比如:

  • Bitmap 没有实现该接口但提供了 copy(),内部将传递原始 Bitmap 在 native 中的对象指针并伴随目标配置进行新实例的创建:

    public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> {
        ...
        public Bitmap copy(Config config, boolean isMutable) {
            ...
            noteHardwareBitmapSlowCall();
            Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable);
            if (b != null) {
                b.setPremultiplied(mRequestPremultiplied);
                b.mDensity = mDensity;
            }
            return b;
        }
    }

-- END --

推荐阅读

      

相关阅读

  • 你想要的各种彩色,化学里都有!

  • 一、单质1、金属:绝大多数为银白色。Cu为紫红色,Au为黄色。2、非金属:二氧化物1、金属氧化物:大多数主族金属氧化物为白色。Na2O2为淡黄色,Pb3O4为红色。2、非金属氧化物:大多数过
  • 福利来袭 | 你阅读,我送礼!“阅读”越幸运!

  • 看文章 | 集碎片 | 赢福利“阅读”越幸运! 上海黄浦 送福利啦!动动手指,看看推文,就有机会赢奖?没错!上海黄浦这个活动了解一下↓活动介绍为鼓励广大网友踊跃阅读公众号文章上海
  • 陈向阳在襄垣县调研

  • 陈向阳在襄垣县调研安全生产和产业转型时强调压实责任守牢安全底线主动应变做强优势产业3月3日,市委副书记、代市长陈向阳深入襄垣县,就安全生产和产业转型等工作进行调研。他
  • 长治日报速览(2023年3月4日)

  • 点击图片浏览电子报刊1234编辑丨解 婷 王素茂监制丨暴爱国版权声明长治日报社旗下“长治日报”“上党晚报”“i长治”微信公众号刊发、登载的所有内容及i长治网和新媒体
  • 参与 2023 第一季度官方 Flutter 开发者调查

  • Flutter 3.7 已经正式发布,每个季度一次的 Flutter 开发者调查也如约而至,邀请社区的各位成员们填写!调查表链接:https://flutter.cn/urls/2023q1wx本次调研将会涉及既有的对 F
  • 《HelloGitHub》第 83 期

  • 兴趣是最好的老师,HelloGitHub 让你对编程感兴趣!简介HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。https://github.com/521xueweihan/HelloGitHub这里有实战项目、入

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 面试题:Android 的 Intent 采用了什么设计模式?

  • 答案是采用了原型模式。“原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。这种
  • 取代房子,中国又一种资本在崛起

  • 2022年底,“房地产是国民经济的支柱产业”被重新提起,房地产市场供需两端政策支持力度加大。加上房贷利率降低,房价在逐渐宽松的市场环境下有回暖的迹象。于是很多朋友问我,今年
  • 学雷锋“益”起来!春天里的第一份爱从这里启航

  • 学雷锋树新风今天真的太棒了!我的水壶修好啦!通过和律师面对面的交谈,明确了装修逾期的违约责任,这桩烦心事终于解决了!我一直想去测一测血压,总很忙没时间。今天路过这里,看见有量