Android设计模式之装饰者模式(Decorator Pattern)
来源:互联网 发布:莺莺传和西厢记知乎 编辑:程序博客网 时间:2024/05/22 12:25
概论
在Android源码里很多时候会看到这个模式。下面来讲一些这个模式。
装饰者模式主要的优点是动态给一个对象添加一些额外的职责。使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。缺点是,要创建比继承更多的对象。
先来个热身,下面是装饰者模式的uml图。它大概就长得这样子的。
1. Component抽象组件,是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象。(注:在装饰模式中,必然有一个最基本、最核心、最原始的接口或者抽象类充当Component抽象组件)
2. ConcreteComponent具体组件,是最核心、最原始、最基本的接口或抽象类的实现,我们需要装饰的就是它。
3. Decorator装饰角色, 一般是一个抽象类,实现接口或者抽象方法,它的属性里必然有一个private变量指向Component抽象组件
4. 具体装饰角色,如上图中的ConcreteDecorator,我们要把我们最核心的、最原始的、最基本的东西装饰成其它东西。
Android源码中应用
再来一个Android的Context的uml图
两个图一对比,你这下你知道怎么回事了吧!
再看看context里面有什么。
public abstract class Context { ...... public abstract Resources getResources(); /** Return PackageManager instance to find global package information. */ public abstract PackageManager getPackageManager(); /** Return a ContentResolver instance for your application's package. */ public abstract ContentResolver getContentResolver(); public abstract Looper getMainLooper(); public abstract Context getApplicationContext(); public abstract void sendBroadcast(@RequiresPermission Intent intent); ...... @Nullable public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter); ......}
Context个抽象类,提供了一组通用的API,具体操作还没实现。 对应装饰者模式中的Componetnt。
ContextImpl类是下面这个样子的,它是Context的实现。对应ConcreteComponent。它会与Android框架层的各个服务(包括组件管理服务、资源管理服务、安装管理服务等)建立远程连接,通过对Android进程间的通信机制(IPC)和这些服务进行通信。
class ContextImpl extends Context { ...... @Override public void startActivity(Intent intent) { warnIfCallingFromSystemProcess(); startActivity(intent, null); } /** @hide */ @Override public void startActivityAsUser(Intent intent, UserHandle user) { startActivityAsUser(intent, null, user); } ...... /** @hide */ @Override public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) { try { ActivityManagerNative.getDefault().startActivityAsUser( mMainThread.getApplicationThread(), getBasePackageName(), intent, intent.resolveTypeIfNeeded(getContentResolver()), null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @Override public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } ......}
这个是ContextWrapper ,它对应装饰者模式中的Decorator。在Android源码中有不少这样带Wrapper后缀的类,其实都可以往装饰者模式方面想。在外部调用时候需要把ContextImpl传进来赋值给mBase。像这样,ContextWrapper(new ContextImpl)。
public class ContextWrapper extends Context { Context mBase; public ContextWrapper(Context base) { mBase = base; } ...... @Override public void startActivity(Intent intent, Bundle options) { mBase.startActivity(intent, options); } ...... @Override public void sendBroadcast(Intent intent) { mBase.sendBroadcast(intent); } ...... @Override public Intent registerReceiver( BroadcastReceiver receiver, IntentFilter filter) { return mBase.registerReceiver(receiver, filter); } .....}
Android的界面组件Activity、服务组件Service以及应用基类Application都派生于ContextWrapper,它们可以通过重载来修改Context接口的实现。
ContextThemeWrapper
public class ContextThemeWrapper extends ContextWrapper { ...... public ContextThemeWrapper(Context base, @StyleRes int themeResId) { super(base); mThemeResource = themeResId; } ...... @Override public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mInflater == null) { mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this); } return mInflater; } return getBaseContext().getSystemService(name); } ......}
Activity
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, WindowControllerCallback { private static final String TAG = "Activity"; private static final boolean DEBUG_LIFECYCLE = false; /** Standard activity result: operation canceled. */ public static final int RESULT_CANCELED = 0; /** Standard activity result: operation succeeded. */ public static final int RESULT_OK = -1; /** Start of user-defined activity results. */ public static final int RESULT_FIRST_USER = 1; /** @hide Task isn't finished when activity is finished */ public static final int DONT_FINISH_TASK_WITH_ACTIVITY = 0; /** * @hide Task is finished if the finishing activity is the root of the task. To preserve the * past behavior the task is also removed from recents. */ public static final int FINISH_TASK_WITH_ROOT_ACTIVITY = 1; /** * @hide Task is finished along with the finishing activity, but it is not removed from * recents. */ public static final int FINISH_TASK_WITH_ACTIVITY = 2; static final String FRAGMENTS_TAG = "android:fragments"; private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState"; private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds"; private static final String SAVED_DIALOGS_TAG = "android:savedDialogs"; private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_"; private static final String SAVED_DIALOG_ARGS_KEY_PREFIX = "android:dialog_args_"; private static final String HAS_CURENT_PERMISSIONS_REQUEST_KEY = "android:hasCurrentPermissionsRequest"; private static final String REQUEST_PERMISSIONS_WHO_PREFIX = "@android:requestPermissions:"; private static final String KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME = "com.android.systemui"; private static final String KEYBOARD_SHORTCUTS_RECEIVER_CLASS_NAME = "com.android.systemui.statusbar.KeyboardShortcutsReceiver"; private static class ManagedDialog { Dialog mDialog; Bundle mArgs; } private SparseArray<ManagedDialog> mManagedDialogs; // set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called. private Instrumentation mInstrumentation; private IBinder mToken; private int mIdent; /*package*/ String mEmbeddedID; private Application mApplication; /*package*/ Intent mIntent; /*package*/ String mReferrer; private ComponentName mComponent; /*package*/ ActivityInfo mActivityInfo; /*package*/ ActivityThread mMainThread; Activity mParent; boolean mCalled; /*package*/ boolean mResumed; /*package*/ boolean mStopped; boolean mFinished; boolean mStartedActivity; private boolean mDestroyed; private boolean mDoReportFullyDrawn = true; /** true if the activity is going through a transient pause */ /*package*/ boolean mTemporaryPause = false; /** true if the activity is being destroyed in order to recreate it with a new configuration */ /*package*/ boolean mChangingConfigurations = false; /*package*/ int mConfigChangeFlags; /*package*/ Configuration mCurrentConfig; private SearchManager mSearchManager; private MenuInflater mMenuInflater; static final class NonConfigurationInstances { Object activity; HashMap<String, Object> children; FragmentManagerNonConfig fragments; ArrayMap<String, LoaderManager> loaders; VoiceInteractor voiceInteractor; } /* package */ NonConfigurationInstances mLastNonConfigurationInstances; private Window mWindow; private WindowManager mWindowManager; /*package*/ View mDecor = null; /*package*/ boolean mWindowAdded = false; /*package*/ boolean mVisibleFromServer = false; /*package*/ boolean mVisibleFromClient = true; /*package*/ ActionBar mActionBar = null; private boolean mEnableDefaultActionBarUp; private VoiceInteractor mVoiceInteractor; private CharSequence mTitle; private int mTitleColor = 0; // we must have a handler before the FragmentController is constructed final Handler mHandler = new Handler(); final FragmentController mFragments = FragmentController.createController(new HostCallbacks()); // Most recent call to requestVisibleBehind(). boolean mVisibleBehind; private static final class ManagedCursor { ManagedCursor(Cursor cursor) { mCursor = cursor; mReleased = false; mUpdated = false; } private final Cursor mCursor; private boolean mReleased; private boolean mUpdated; } private final ArrayList<ManagedCursor> mManagedCursors = new ArrayList<ManagedCursor>(); // protected by synchronized (this) int mResultCode = RESULT_CANCELED; Intent mResultData = null; private TranslucentConversionListener mTranslucentCallback; private boolean mChangeCanvasToTranslucent; private SearchEvent mSearchEvent; private boolean mTitleReady = false; private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY; private int mDefaultKeyMode = DEFAULT_KEYS_DISABLE; private SpannableStringBuilder mDefaultKeySsb = null; private ActivityManager.TaskDescription mTaskDescription = new ActivityManager.TaskDescription(); protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused}; @SuppressWarnings("unused") private final Object mInstanceTracker = StrictMode.trackActivity(this); private Thread mUiThread; ActivityTransitionState mActivityTransitionState = new ActivityTransitionState(); SharedElementCallback mEnterTransitionListener = SharedElementCallback.NULL_CALLBACK; SharedElementCallback mExitTransitionListener = SharedElementCallback.NULL_CALLBACK; private boolean mHasCurrentPermissionsRequest; private boolean mEatKeyUpEvent; private static native String getDlWarning(); /** Return the intent that started this activity. */ public Intent getIntent() { return mIntent; } /** * Change the intent returned by {@link #getIntent}. This holds a * reference to the given intent; it does not copy it. Often used in * conjunction with {@link #onNewIntent}. * * @param newIntent The new Intent object to return from getIntent * * @see #getIntent * @see #onNewIntent */ public void setIntent(Intent newIntent) { mIntent = newIntent; } /** Return the application that owns this activity. */ public final Application getApplication() { return mApplication; } /** Is this activity embedded inside of another activity? */ public final boolean isChild() { return mParent != null; } /** Return the parent activity if this view is an embedded child. */ public final Activity getParent() { return mParent; } /** Retrieve the window manager for showing custom windows. */ public WindowManager getWindowManager() { return mWindowManager; } ......}
Application
public class Application extends ContextWrapper implements ComponentCallbacks2 { private ArrayList<ComponentCallbacks> mComponentCallbacks = new ArrayList<ComponentCallbacks>(); private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks = new ArrayList<ActivityLifecycleCallbacks>(); private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null; ...... @CallSuper public void onLowMemory() { Object[] callbacks = collectComponentCallbacks(); if (callbacks != null) { for (int i=0; i<callbacks.length; i++) { ((ComponentCallbacks)callbacks[i]).onLowMemory(); } } } @CallSuper public void onTrimMemory(int level) { Object[] callbacks = collectComponentCallbacks(); if (callbacks != null) { for (int i=0; i<callbacks.length; i++) { Object c = callbacks[i]; if (c instanceof ComponentCallbacks2) { ((ComponentCallbacks2)c).onTrimMemory(level); } } } } public void registerComponentCallbacks(ComponentCallbacks callback) { synchronized (mComponentCallbacks) { mComponentCallbacks.add(callback); } } public void unregisterComponentCallbacks(ComponentCallbacks callback) { synchronized (mComponentCallbacks) { mComponentCallbacks.remove(callback); } } public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) { synchronized (mActivityLifecycleCallbacks) { mActivityLifecycleCallbacks.add(callback); } } public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) { synchronized (mActivityLifecycleCallbacks) { mActivityLifecycleCallbacks.remove(callback); } } public void registerOnProvideAssistDataListener(OnProvideAssistDataListener callback) { synchronized (this) { if (mAssistCallbacks == null) { mAssistCallbacks = new ArrayList<OnProvideAssistDataListener>(); } mAssistCallbacks.add(callback); } } public void unregisterOnProvideAssistDataListener(OnProvideAssistDataListener callback) { synchronized (this) { if (mAssistCallbacks != null) { mAssistCallbacks.remove(callback); } } /** * @hide */ /* package */ final void attach(Context context) { attachBaseContext(context); mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; } /* package */ void dispatchActivityCreated(Activity activity, Bundle savedInstanceState) { Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { for (int i=0; i<callbacks.length; i++) { ((ActivityLifecycleCallbacks)callbacks[i]).onActivityCreated(activity, savedInstanceState); } } } /* package */ void dispatchActivityStarted(Activity activity) { Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { for (int i=0; i<callbacks.length; i++) { ((ActivityLifecycleCallbacks)callbacks[i]).onActivityStarted(activity); } } } ......}
Service
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 { private static final String TAG = "Service"; ...... public void onDestroy() { } public void onConfigurationChanged(Configuration newConfig) { } public void onLowMemory() { } public void onTrimMemory(int level) { } ......}
结尾附上Context的应用场景
注:
NO1 表示Application context的确可以开始一个Activity,但是它需要创建一个新的task。这可能会满足一些特定的需求,但是在你的应用中会创建一个不标准的回退栈(back stack),这通常是不推荐的或者不是是好的实践。
NO2 表示这是非法的,但是这个填充(inflation)的确可以完成,但是是使用所运行的系统默认的主题(theme),而不是你app定义的主题。
NO3 在Android4.2以上,如果Receiver是null的话(这是用来获取一个sticky broadcast的当前 值的),这是允许的。
- Android设计模式之装饰者模式(Decorator Pattern)
- 设计模式之装饰模式(Decorator Pattern)
- 设计模式之装饰模式--- Pattern Decorator
- 设计模式-装饰者模式(Decorator Pattern)
- 设计模式系列之四:装饰者模式(Decorator Pattern)
- 设计模式笔记之装饰者模式(Decorator Pattern)
- 设计模式之装饰者模式Decorator Pattern
- C#设计模式之装饰者模式(Decorator Pattern)
- 设计模式(结构型)之装饰者模式(Decorator Pattern)
- 设计模式总结之Decorator Pattern(装饰者模式)
- Java设计模式之装饰者模式(Decorator pattern)
- 装饰者设计模式(Decorator Pattern)
- 设计模式(二)之装饰模式(Decorator Pattern)
- JAVA设计模式之 装饰模式【Decorator Pattern】
- C#设计模式之装饰模式(Decorator Pattern)
- android设计模式-装饰模式(Decorator Pattern)
- 设计模式[6] Decorator Pattern 装饰模式
- 设计模式-装饰模式(Decorator Pattern)
- bzoj1036: [ZJOI2008]树的统计Count(树剖模版)
- 《TCP IP网络编程》尹圣雨----4.第二章习题
- gevent协程-配合爬虫使用
- scrollWidth、clientWidth、offsetWidth的区别;
- AngularJS 获取JSON数据
- Android设计模式之装饰者模式(Decorator Pattern)
- ORACLE导入导出 创建表空间 备份流程
- 剑指offer_扑克牌顺子
- Halcon常用数组算子
- ReentrantLock学习
- Git
- WOJ1268-Game of Connections
- java 读取 properties 文件的方法
- 计算机视觉与图像处理、模式识别、机器学习学科之间的关系