インタビューの質問: Android の Intent にはどのようなデザイン パターンが使用されていますか?

答えは、プロトタイプ パターンを使用することです。

プロトタイプ モードの利点は、元のインスタンスに影響を与えることなく使用するインスタンスのプロパティをコピーするのに便利なことです. そのロジックは、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) {
                 ...
             }
         }
     }
     ...
 }
复制代码

実装されたロジックは、コピーのために super.clone() を呼び出すのではなく、直接 new を呼び出して独自のインスタンスを渡すことであることがIntentわかります。clone()

デフォルトのコピー戦略はCOPY_MODE_ALL、名前が示すように、ソース インスタンスのすべての属性の完全なコピーで構築することです。他のコピー戦略はCOPY_MODE_FILTERIntent-filterに関連する属性、つまり、開始ターゲット コンポーネントを決定するために使用されるactiondatatypecomponentcategoryなどの必要な情報のみをコピーすることを指します。開始フラグバンドル、およびその他のデータを無視します。

 // 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必要ありませんが、アクションなどの基本的な情報や起動フラグなどのデータは保持されます

 // 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_MODE_ALL はい はい はい
COPY_MODE_FILTER はい いいえ いいえ
COPY_MODE_HISTORY YES YES NO

除了 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;
         }
     }
    复制代码

Guess you like

Origin juejin.im/post/7204013918958649405