開篇之單例模式:
相信大家已經(jīng)很熟悉單例模式了吧甚垦,特別是在保證某個(gè)類只有一個(gè)對(duì)象的場(chǎng)景下才會(huì)使用到艰亮。那有人會(huì)問什么時(shí)候用到單例模式呢迄埃,其實(shí)如果一個(gè)對(duì)象創(chuàng)建需要消耗過多資源時(shí)侄非,正是單例模式用到之處逞怨。
看看單例模式的UML類圖:
- 單例類里面有成員變量(當(dāng)前實(shí)例自己)
- 暴露一個(gè)public類型的
getInstance
方法 - 當(dāng)前構(gòu)造器不公開叠赦,private類型
樣例代碼:
public class SingletonDemo {
private static SingletonDemo singletonDemo;
private SingletonDemo(){}
//懶漢式獲取單例實(shí)例
public static SingletonDemo getInstance() {
if (singletonDemo == null) {
synchronized (SingletonDemo.class) {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
}
}
return singletonDemo;
}
***********************
//飽漢式
private static final SingletonDemo singletonDemo = new SingletonDemo();
private SingletonDemo() {
}
public static SingletonDemo getInstance() {
return SingletonDemo.singletonDemo;
}
}
看到這個(gè)地方,可能大家還是覺得不好使用單例模式册踩。想想你的項(xiàng)目中那些網(wǎng)絡(luò)操作棍好、對(duì)話框的管理借笙、io文件的讀取等等單一實(shí)例的地方是不是都可以去處理呢业稼。但是單例模式由于是一直持有實(shí)例的低散,因此對(duì)于上下文(context)的地方熔号,需要注意注意內(nèi)存泄漏的情況了引镊。
Builder模式:
builder設(shè)計(jì)模式的出現(xiàn)弟头,是為了更好地為一些復(fù)雜對(duì)象進(jìn)行分離處理赴恨。通俗點(diǎn)也就是類的功能太多了伦连,將一些行為放到Builder
類中間接處理惑淳。
UML類圖:
樣例代碼:
public class Factory {
Builder builder;
public Factory() {
builder = new Builder();
}
public void createEngine() {
builder.createEngine();
}
public void createGearbox() {
builder.createGearbox();
}
public void createSuspension() {
builder.createSuspension();
}
public static class Builder {
private Car car;
public Builder() {
car = new Car();
}
public Builder createEngine() {
car.engine = "自然吸氣";
return this;
}
public Builder createGearbox() {
car.gearbox = "at變速箱";
return this;
}
public Builder createSuspension() {
car.suspension = "獨(dú)立懸架";
return this;
}
}
}
public class Car {
//發(fā)動(dòng)機(jī)
public String engine;
//變速箱
public String gearbox;
//懸架
public String suspension;
//正規(guī)寫法是提供set方法的短荐,參數(shù)都是由外部提供的忍宋,為了省事糠排,你懂的
}
上面事例代碼,也正好說明了Builder模式的特點(diǎn),將復(fù)雜對(duì)象的構(gòu)成放到我們的內(nèi)部類中進(jìn)行處理速客。
還記得之前我們顯示一個(gè)對(duì)話框的代碼嗎?
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("dialog title");
builder.setMessage("I am a dialog.");
builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//// TODO: 17/12/26
}
});
builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//// TODO: 17/12/26
}
});
builder.show();
相信這段代碼誰都會(huì)寫了吧,以前總是一頭霧水地寫完這段代碼巢钓,然后交給經(jīng)理樂樂地說搞定了≈⑿冢現(xiàn)在不行啊背镇,對(duì)源碼得有點(diǎn)分析,下面就去看看源碼吧:
首先是生成了一個(gè)AlertDialog.Builder對(duì)象济瓢,那咋們瞧瞧吧:
public class AlertDialog extends AppCompatDialog implements DialogInterface {
******省略AlertDialog類中代碼******
public static class Builder {
private final AlertController.AlertParams P;
private final int mTheme;
/**
* Creates a builder for an alert dialog that uses the default alert
* dialog theme.
* <p>
* The default alert dialog theme is defined by
* {@link android.R.attr#alertDialogTheme} within the parent
* {@code context}'s theme.
*
* @param context the parent context
*/
public Builder(@NonNull Context context) {
this(context, resolveDialogTheme(context, 0));
}
/**
* Creates a builder for an alert dialog that uses an explicit theme
* resource.
* <p>
* The specified theme resource ({@code themeResId}) is applied on top
* of the parent {@code context}'s theme. It may be specified as a
* style resource containing a fully-populated theme, such as
* {@link R.style#Theme_AppCompat_Dialog}, to replace all
* attributes in the parent {@code context}'s theme including primary
* and accent colors.
* <p>
* To preserve attributes such as primary and accent colors, the
* {@code themeResId} may instead be specified as an overlay theme such
* as {@link R.style#ThemeOverlay_AppCompat_Dialog}. This will
* override only the window attributes necessary to style the alert
* window as a dialog.
* <p>
* Alternatively, the {@code themeResId} may be specified as {@code 0}
* to use the parent {@code context}'s resolved value for
* {@link android.R.attr#alertDialogTheme}.
*
* @param context the parent context
* @param themeResId the resource ID of the theme against which to infra
* this dialog, or {@code 0} to use the parent
* {@code context}'s default alert dialog theme
*/
public Builder(@NonNull Context context, @StyleRes int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
mTheme = themeResId;
}
/**
* Returns a {@link Context} with the appropriate theme for dialogs area
* Applications should use this Context for obtaining LayoutInflaters of
* that will be used in the resulting dialogs, as it will cause views to
* the correct theme.
*
* @return A Context for built Dialogs.
*/
@NonNull
public Context getContext() {
return P.mContext;
}
/**
* Set the title using the given resource id.
*
* @return This Builder object to allow for chaining of calls to set met
*/
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
/**
* Set the title displayed in the {@link Dialog}.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setTitle(@Nullable CharSequence title) {
P.mTitle = title;
return this;
}
/**
* Set the message to display using the given resource id.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setMessage(@StringRes int messageId) {
P.mMessage = P.mContext.getText(messageId);
return this;
}
/**
* Set the message to display.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setMessage(@Nullable CharSequence message) {
P.mMessage = message;
return this;
}
/**
* Set a listener to be invoked when the positive button of the dialog is pressed.
* @param textId The resource id of the text to display in the positive button
* @param listener The {@link DialogInterface.OnClickListener} to use.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
P.mPositiveButtonText = P.mContext.getText(textId);
P.mPositiveButtonListener = listener;
return this;
}
/**
* Set a listener to be invoked when the positive button of the dialog is pressed.
* @param text The text to display in the positive button
* @param listener The {@link DialogInterface.OnClickListener} to use.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
P.mPositiveButtonText = text;
P.mPositiveButtonListener = listener;
return this;
}
/**
* Set a listener to be invoked when the negative button of the dialog is pressed.
* @param textId The resource id of the text to display in the negative button
* @param listener The {@link DialogInterface.OnClickListener} to use.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) {
P.mNegativeButtonText = P.mContext.getText(textId);
P.mNegativeButtonListener = listener;
return this;
}
/**
* Set a listener to be invoked when the negative button of the dialog is pressed.
* @param text The text to display in the negative button
* @param listener The {@link DialogInterface.OnClickListener} to use.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setNegativeButton(CharSequence text, final OnClickListener listener) {
P.mNegativeButtonText = text;
P.mNegativeButtonListener = listener;
return this;
}
/**
* Creates an {@link AlertDialog} with the arguments supplied to this
* builder and immediately displays the dialog.
* <p>
* Calling this method is functionally identical to:
* <pre>
* AlertDialog dialog = builder.create();
* dialog.show();
* </pre>
*/
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
/**
* Creates an {@link AlertDialog} with the arguments supplied to this
* builder.
* <p>
* Calling this method does not display the dialog. If no additional
* processing is needed, {@link #show()} may be called instead to both
* create and display the dialog.
*/
public AlertDialog create() {
// We can't use Dialog's 3-arg constructor with the createThemeContextWrapper param,
// so we always have to re-set the theme
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
}
}
這里就是我們剛才顯示對(duì)話框的時(shí)候铺纽,調(diào)的幾個(gè)方法狡门∑淞螅可以看到Builder
內(nèi)部類中的setTitle
叛复、setMessage
、setPositiveButton
翘簇、
setNegativeButton
方法都是給AlertController.AlertParams P
變量賦值缘揪≌殷荩看來AlertParams
又是AlertController
內(nèi)部類了袖裕。接著就是調(diào)了show
方法急鳄,show
方法里面緊接著調(diào)了create
方法疾宏。在create
方法里面生成了一個(gè)AlertDialog
坎藐,然后調(diào)用了
AlertController.AlertParams
的apply
方法岩馍,去看看做了些啥吧:
public void apply(AlertController dialog) {
if (mCustomTitleView != null) {
dialog.setCustomTitle(mCustomTitleView);
} else {
if (mTitle != null) {
dialog.setTitle(mTitle);
}
if (mIcon != null) {
dialog.setIcon(mIcon);
}
if (mIconId != 0) {
dialog.setIcon(mIconId);
}
if (mIconAttrId != 0) {
dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
}
if (mMessage != null) {
dialog.setMessage(mMessage);
}
if (mPositiveButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null);
}
if (mNegativeButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
mNegativeButtonListener, null);
}
if (mNeutralButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
mNeutralButtonListener, null);
}
// For a list, the client can either supply an array of items or an
// adapter or a cursor
if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
createListView(dialog);
}
if (mView != null) {
if (mViewSpacingSpecified) {
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
} else {
dialog.setView(mView);
}
} else if (mViewLayoutResId != 0) {
dialog.setView(mViewLayoutResId);
}
/*
dialog.setCancelable(mCancelable);
dialog.setOnCancelListener(mOnCancelListener);
if (mOnKeyListener != null) {
dialog.setOnKeyListener(mOnKeyListener);
}
*/
}
看到了沒,這里才是將上面builder
中的賦值又傳給了AlertController
類,這里我們就看下AlertController
的setTitle
方法:
public void setTitle(CharSequence title) {
mTitle = title;
if (mTitleView != null) {
mTitleView.setText(title);
}
}
這里就把builder
中傳過來的title
給了AlertController
中的mTitleView
佃乘。那咱們看看mTitleView
是什么時(shí)候生成的吧:
private void setupTitle(ViewGroup topPanel) {
if (mCustomTitleView != null) {
//省略代碼
} else {
mIconView = (ImageView) mWindow.findViewById(android.R.id.icon);
final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
if (hasTextTitle && mShowTitle) {
// Display the title if a title is supplied, else hide it.
mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
mTitleView.setText(mTitle);
//省略代碼
}
}
可以看到實(shí)際上mTitleView
是window
對(duì)象的R.id.alertTitle
布局了庞呕。這里可以自己去研究該window
下是怎么生成的,這里就把create
的過程屢了一遍了地啰,最后就剩下了show
岭埠∠郏可以看到Builder
中show
方法最后調(diào)用了AlertDialog
的show
方法馆类。
這里可以畫張流程圖更清晰:
關(guān)于builder
模式就先說這么多了乾巧,總結(jié)下來就是將復(fù)雜對(duì)象的生成放到單獨(dú)的一個(gè)類進(jìn)行處理沟于,對(duì)主類進(jìn)行分離旷太。
一直看好的工廠模式:
說到工廠模式其實(shí)大家可能沒怎么留意,而且自己在寫代碼的時(shí)候嗜傅,也很少知道自己寫的是不是工廠模式了吕嘀。工廠模式顯著的特點(diǎn)是具體產(chǎn)品類專門由一個(gè)叫工廠類專門去構(gòu)造偶房,也就是new
的過程棕洋。這樣的模式好處是調(diào)用者無需關(guān)心具體構(gòu)造產(chǎn)品的過程掰盘,而且對(duì)于一些復(fù)雜對(duì)象的構(gòu)造愧捕,也起到了透明
的效果次绘。
UML類圖:
事例代碼也很簡(jiǎn)單:
//抽象的產(chǎn)品
public abstract class Product {
public abstract void function();
}
//具體的產(chǎn)品
public class ProductA extends Product {
@Override
public void function() {
//// TODO: 17/12/27
}
}
//具體的產(chǎn)品
public class ProductB extends Product {
@Override
public void function() {
//// TODO: 17/12/27
}
}
//抽象工廠
public abstract class Factory {
abstract Product createProductA();
abstract Product createProductB();
}
//具體的工廠類
public class FactoryProduct extends Factory {
@Override
Product createProductA() {
return new ProductA();
}
@Override
Product createProductB() {
return new ProductB();
}
}
所以從上面結(jié)構(gòu)看管跺,標(biāo)準(zhǔn)的工廠模式是產(chǎn)品有各種各樣的,而工廠就只有一個(gè)
下面通過另外一種方式去看下工廠類的寫法(反射來獲取具體產(chǎn)品):
//反射方式的抽象工廠類
public abstract class ReflexFactory {
protected abstract <T extends Product> T createProduct(Class<T> cl);
}
//具體的反射工廠類
public class ReflexFactoryProduct extends ReflexFactory {
@Override
protected <T extends Product> T createProduct(Class<T> cl) {
Product p = null;
try {
p = (Product) Class.forName(cl.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) p;
}
}
這里和普通的工廠類相比贩绕,少了創(chuàng)建不同product
的方法淑倾,通過傳入不同的class
類型來獲得不同的product
娇哆。但是貌似只能調(diào)用到無參的product
碍讨,這里尷尬了勃黍,要是構(gòu)造器要傳入屬性就麻煩了,不就相當(dāng)于new Object()
了弄息。
這里除了上面兩種工廠類之外摹量,還有種靜態(tài)工廠類
的形式:
public class StaticFactory {
enum ProductType {
ProductA, ProductB;
}
public static Product createProduct(ProductType type) {
switch (type) {
case ProductA:
return new ProductA();
case ProductB:
return new ProductB();
}
return null;
}
}
靜態(tài)工廠類就一個(gè)類啊荆永,通過分支創(chuàng)建不同的Product
具钥。缺點(diǎn)就是如果很多種product
的話,那這個(gè)類就龐大了宁玫,而且這里如果每種product
需要傳參的話欧瘪,那靜態(tài)方法的參數(shù)也是不定的佛掖。好處就是一個(gè)類搞定了啊芥被。
好了拴魄,說了幾種工廠模式后,去看下android源碼中有沒有應(yīng)用了:
AudioManager audioManager=context.getSystemService(Context.AUDIO_SERVICE)
相信大家都獲取過****Manager了吧顶捷,那咱們?nèi)タ纯催@句代碼跟工廠模式有關(guān)系沒焊切。
是不是在activity
中直接有getSystemService
呢专肪,那咱們?nèi)タ聪掳?
@Override
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException(
"System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
直接看最后一行調(diào)用了父類的getSystemService
方法:
那咱們?nèi)?code>ContextThemeWrapper中去找唄:
@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);
}
看最后一行就行了伍宦,這里獲取getBaseContext
后,然后調(diào)了getSystemService
遇骑。咱們看下getBseContext
是什么鬼落萎。又要去ContextThemeWrapper
的父類去找getBaseContext
了:
好吧,父類是
ContextWrapper
,那咱們看下getBaseContext
是什么了:
/**
* @return the base context as set by the constructor or setBaseContext
*/
public Context getBaseContext() {
return mBase;
}
這里是ContextWrapper
中的mBase
變量了:
public ContextWrapper(Context base) {
mBase = base;
}
/**
* Set the base context for this ContextWrapper. All calls will then be
* delegated to the base context. Throws
* IllegalStateException if a base context has already been set.
*
* @param base The new base context for this wrapper.
*/
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
賦值就這兩個(gè)地方了。那咱們就知道Activity中的context
實(shí)際上就是ContextWrapper
中的mBase
變量了绿鸣。這就要追溯到Activity
創(chuàng)建的地方了枚驻,才能揭穿mBase
的真面目了。這里需要知道點(diǎn)Android的應(yīng)用啟動(dòng)流程了株旷,咱們就直接看ActivityThread
類了:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//省略代碼
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
//省略代碼
return activity;
}
看到最后面調(diào)用了activity
的attach
方法再登,并且把創(chuàng)建的appContext
傳進(jìn)了attach
方法,那咱們看下創(chuàng)建這個(gè)context
是什么了:
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
//省略代碼
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;
//省略代碼
return baseContext;
}
看到這的時(shí)候晾剖,基本就知道上面說的mBase
其實(shí)就是ContextImpl
了锉矢。Activity
的attach
的方法也正是把傳進(jìn)來的ContextImpl
給了ContextWrapper
中的mBase
:
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
//調(diào)用了父類ContextWrapper的attach方法
attachBaseContext(context);
//省略代碼
}
到這里ContextWrapper
中的mBase
其實(shí)是一個(gè)ContextImpl
了齿尽,下面就去看下ContextImp
的getSystemService
方法了:
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
好吧沽损,又是走了一層了,去看下SystemServiceRegistry
中的getSystemService
方法吧:
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
這里就很清晰了循头,首先通過name
去SYSTEM_SERVICE_FETCHERS
中獲取一個(gè)ServiceFetcher
對(duì)象绵估,然后調(diào)用了getService
方法:
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
好吧,這里是個(gè)HashMap
卡骂,那咱們看下什么時(shí)候put進(jìn)去的ServiceFetcher
:
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
這里是在registerService
的時(shí)候?qū)?code>serviceFetcherput進(jìn)去的:
static {
registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
new CachedServiceFetcher<AccessibilityManager>() {
@Override
public AccessibilityManager createService(ContextImpl ctx) {
return AccessibilityManager.getInstance(cox);
}});
registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
new CachedServiceFetcher<CaptioningManager>() {
@Override
public CaptioningManager createService(ContextImpl ctx) {
return new CaptioningManager(cox);
}});
registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
new CachedServiceFetcher<AccountManager>() {
@Override
public AccountManager createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.ACCOUNT_SERVICE);
IAccountManager service = IAccountManager.Stub.asInterface(b);
return new AccountManager(ctx, service);
}});
//registerService太多了国裳,我這里就羅列上面幾個(gè)了
}
看到這的時(shí)候,才看到有工廠模式的影子啊全跨,好多小伙伴都要哭了缝左。源碼真的是藏得深啊。這里簡(jiǎn)單說下在靜態(tài)的時(shí)候,通過service
的name構(gòu)造出不同的ServiceFetcher
渺杉,并存儲(chǔ)在SYSTEM_SERVICE_FETCHERS
中蛇数。然后在getSystemService
過程中通過傳進(jìn)來的name
獲取不同的ServiceFetcher
,最后調(diào)用getService
方法獲取相應(yīng)的Manager
了是越。不難看出這里的ServiceFetcher
就是產(chǎn)品抽象類耳舅,SystemServiceRegistry
就是一個(gè)生產(chǎn)***Manager
的靜態(tài)工廠類了。
下面畫張圖理解下Activity
中getSystemService