@@ -39,7 +39,7 @@ Android设计模式源码解析之外观模式(Facade)
39
39
### 实现源码
40
40
TvController.java
41
41
42
- ```
42
+ ``` java
43
43
public class TvController {
44
44
private PowerSystem mPowerSystem = new PowerSystem ();
45
45
private VoiceSystem mVoiceSystem = new VoiceSystem ();
@@ -168,85 +168,220 @@ public class TvController {
168
168
上面的TvController封装了对电源、声音、频道切换的操作,为用户提供了一个统一的接口。使得用户控制电视机更加的方便、更易于使用。
169
169
170
170
## Android源码中的模式实现
171
- 在Android源码中,ContextImpl这个类封装了很多模块(子系统),比如startActivity()、sendBroadcast()等,分别给用户一个统一的操作入口,简单实例如下:
171
+ 在开发过程中,Context是最重要的一个类型。它封装了很多重要的操作,比如startActivity()、sendBroadcast()等,几乎是开发者对应用操作的统一入口。Context是一个抽象类,它只是定义了抽象接口,真正的实现在ContextImpl类中。它就是今天我们要分析的外观类。
172
+
173
+ 在应用启动时,首先会fork一个子进程,并且调用ActivityThread.main方法启动该进程。ActivityThread又会构建Application对象,然后和Activity、ContextImpl关联起来,然后再调用Activity的onCreate、onStart、onResume函数使Activity运行起来。我们看看下面的相关代码:
172
174
173
175
```
174
- package com.elsdnwn.Facade;
176
+ private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
177
+ // 代码省略
175
178
176
- import android.app.Activity;
177
- import android.content.Intent;
178
- import android.os.Bundle;
179
+ // 1、创建并且加载Activity,调用其onCreate函数
180
+ Activity a = performLaunchActivity(r, customIntent);
179
181
180
- public class MainActivity extends Activity {
181
-
182
- @Override
183
- protected void onCreate(Bundle savedInstanceState) {
184
- super.onCreate(savedInstanceState);
185
- setContentView(R.layout.activity_main);
182
+ if (a != null) {
183
+ r.createdConfig = new Configuration(mConfiguration);
184
+ Bundle oldState = r.state;
185
+ // 2、调用Activity的onResume方法,使Activity变得可见
186
+ handleResumeActivity(r.token, false, r.isForward);
186
187
187
- Intent intent = new Intent();
188
- intent.setClass(this, MainActivity2.class);
189
- startActivity(intent);
190
- }
188
+ }
189
+ }
191
190
192
- }
193
191
194
- ```
192
+ private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
193
+ // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
194
+ // 代码省略
195
195
196
- 通过上面的代码可以看到,启动startActivity需要传递一个Context上下文对象,为什么要传递呢?下面我们看一下ContextImpl相关源码:
196
+ Activity activity = null;
197
+ try {
198
+ java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
199
+ // 1、创建Activity
200
+ activity = mInstrumentation.newActivity(
201
+ cl, component.getClassName(), r.intent);
202
+ r.intent.setExtrasClassLoader(cl);
203
+ if (r.state != null) {
204
+ r.state.setClassLoader(cl);
205
+ }
206
+ } catch (Exception e) {
207
+ if (!mInstrumentation.onException(activity, e)) {
208
+ throw new RuntimeException(
209
+ "Unable to instantiate activity " + component
210
+ + ": " + e.toString(), e);
211
+ }
212
+ }
197
213
198
- ```
214
+ try {
215
+ // 2、创建Application
216
+ Application app = r.packageInfo.makeApplication(false, mInstrumentation);
217
+
218
+ if (activity != null) {
219
+ // ***** 构建ContextImpl ******
220
+ ContextImpl appContext = new ContextImpl();
221
+ appContext.init(r.packageInfo, r.token, this);
222
+ appContext.setOuterContext(activity);
223
+ // 获取Activity的title
224
+ CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
225
+ Configuration config = new Configuration(mConfiguration);
226
+
227
+ // 3、Activity与context, Application关联起来
228
+ activity.attach(appContext, this, getInstrumentation(), r.token,
229
+ r.ident, app, r.intent, r.activityInfo, title, r.parent,
230
+ r.embeddedID, r.lastNonConfigurationInstance,
231
+ r.lastNonConfigurationChildInstances, config);
232
+ // 代码省略
233
+
234
+ // 4、回调Activity的onCreate方法
235
+ mInstrumentation.callActivityOnCreate(activity, r.state);
236
+
237
+ // 代码省略
238
+ }
239
+ r.paused = true;
240
+
241
+ mActivities.put(r.token, r);
242
+
243
+ } catch (SuperNotCalledException e) {
244
+ throw e;
245
+
246
+ } catch (Exception e) {
247
+
248
+ }
249
+
250
+ return activity;
251
+ }
252
+
253
+
254
+ final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
255
+
256
+ unscheduleGcIdler();
257
+
258
+ // 1、最终调用Activity的onResume方法
259
+ ActivityClientRecord r = performResumeActivity(token, clearHide);
260
+ // 代码省略
261
+ // 2、这里是重点,在这里使DecorView变得可见
262
+ if (r.window == null && !a.mFinished && willBeVisible) {
263
+ // 获取Window,即PhoneWindow类型
264
+ r.window = r.activity.getWindow();
265
+ // 3、获取Window的顶级视图,并且使它可见
266
+ View decor = r.window.getDecorView();
267
+ decor.setVisibility(View.INVISIBLE);
268
+ // 4、获取WindowManager
269
+ ViewManager wm = a.getWindowManager();
270
+ // 5、构建LayoutParams参数
271
+ WindowManager.LayoutParams l = r.window.getAttributes();
272
+ a.mDecor = decor;
273
+ l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
274
+ l.softInputMode |= forwardBit;
275
+ if (a.mVisibleFromClient) {
276
+ a.mWindowAdded = true;
277
+ // 6、将DecorView添加到WindowManager中,最终的操作是通过WindowManagerService的addView来操作
278
+ wm.addView(decor, l);
279
+ }
280
+ } else if (!willBeVisible) {
281
+ if (localLOGV) Slog.v(
282
+ TAG, "Launch " + r + " mStartedActivity set");
283
+ r.hideForNow = true;
284
+ }
285
+ // 代码省略
286
+ }
199
287
200
- @Override
288
+ public final ActivityClientRecord performResumeActivity(IBinder token,
289
+ boolean clearHide) {
290
+ ActivityClientRecord r = mActivities.get(token);
291
+
292
+ if (r != null && !r.activity.mFinished) {
293
+ try {
294
+ // 代码省略
295
+ // 执行onResume
296
+ r.activity.performResume();
297
+ // 代码省略
298
+ } catch (Exception e) {
299
+
300
+ }
301
+ }
302
+ return r;
303
+ }
304
+ ```
305
+
306
+ Activity启动之后,Android给我们提供了操作系统服务的统一入口,也就是Activity本身。这些工作并不是Activity自己实现的,而是将操作委托给Activity父类ContextThemeWrapper的mBase对象,这个对象的实现类就是ContextImpl ( 也就是performLaunchActivity方法中构建的ContextImpl )。
307
+
308
+
309
+ ``` java
310
+ class ContextImpl extends Context {
311
+ private final static String TAG = " ApplicationContext" ;
312
+ private final static boolean DEBUG = false ;
313
+ private final static boolean DEBUG_ICONS = false ;
314
+
315
+ private static final Object sSync = new Object ();
316
+ private static AlarmManager sAlarmManager;
317
+ private static PowerManager sPowerManager;
318
+ private static ConnectivityManager sConnectivityManager;
319
+ private AudioManager mAudioManager;
320
+ LoadedApk mPackageInfo;
321
+ private Resources mResources;
322
+ private PackageManager mPackageManager;
323
+ private NotificationManager mNotificationManager = null ;
324
+ private ActivityManager mActivityManager = null ;
325
+
326
+ // 代码省略
327
+
328
+ @Override
329
+ public void sendBroadcast (Intent intent ) {
330
+ String resolvedType = intent. resolveTypeIfNeeded(getContentResolver());
331
+ try {
332
+ ActivityManagerNative . getDefault(). broadcastIntent(
333
+ mMainThread. getApplicationThread(), intent, resolvedType, null ,
334
+ Activity . RESULT_OK , null , null , null , false , false );
335
+ } catch (RemoteException e) {
336
+ }
337
+ }
338
+
339
+
340
+ @Override
201
341
public void startActivity (Intent intent ) {
202
342
if ((intent. getFlags()& Intent . FLAG_ACTIVITY_NEW_TASK ) == 0 ) {
203
343
throw new AndroidRuntimeException (
204
344
" Calling startActivity() from outside of an Activity "
205
345
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
206
346
+ " Is this really what you want?" );
207
347
}
208
-
209
- // 其实是用的getInstrumentation().execStartActivity();
210
348
mMainThread. getInstrumentation(). execStartActivity(
211
- getOuterContext(), mMainThread.getApplicationThread(), null,
212
- (Activity)null, intent, -1);
349
+ getOuterContext(), mMainThread. getApplicationThread(), null , null , intent, - 1 );
213
350
}
214
-
215
- ```
216
-
217
- 我们可以看出启动Activity其实是用的Instrumentation()类里的getInstrumentation().execStartActivity(); 继续查看Instrumentation类里的execStartActivity()的源码:
218
-
219
- ```
220
-
221
- /**
222
- * 需要接受一个Context上下文对象来确定activity的开始
223
- */
224
- public ActivityResult execStartActivity(
225
- Context who, IBinder contextThread, IBinder token, Activity target,
226
- Intent intent, int requestCode, Bundle options) {
227
- IApplicationThread whoThread = (IApplicationThread) contextThread;
228
- if (mActivityMonitors != null) {
229
- synchronized (mSync) {
230
- final int N = mActivityMonitors.size();
231
- for (int i=0; i<N; i++) {
232
- final ActivityMonitor am = mActivityMonitors.get(i);
233
- if (am.match(who, null, intent)) {
234
- am.mHits++;
235
- if (am.isBlocking()) {
236
- return requestCode >= 0 ? am.getResult() : null;
237
- }
238
- break;
239
- }
240
- }
351
+
352
+
353
+ @Override
354
+ public ComponentName startService (Intent service ) {
355
+ try {
356
+ ComponentName cn = ActivityManagerNative . getDefault(). startService(
357
+ mMainThread. getApplicationThread(), service,
358
+ service. resolveTypeIfNeeded(getContentResolver()));
359
+ if (cn != null && cn. getPackageName(). equals(" !" )) {
360
+ throw new SecurityException (
361
+ " Not allowed to start service " + service
362
+ + " without permission " + cn. getClassName());
241
363
}
364
+ return cn;
365
+ } catch (RemoteException e) {
366
+ return null ;
242
367
}
243
- // 代码略...
244
- return null;
245
368
}
246
-
369
+
370
+ @Override
371
+ public String getPackageName () {
372
+ if (mPackageInfo != null ) {
373
+ return mPackageInfo. getPackageName();
374
+ }
375
+ throw new RuntimeException (" Not supported in system context" );
376
+ }
377
+ }
247
378
```
379
+ 可以看到,ContextImpl内部有很多xxxManager类的对象,也就是我们上文所说的各种子系统的角色。ContextImpl内部封装了一些系统级别的操作,有的子系统功能虽然没有实现,但是也提供了访问该子系统的接口,比如获取ActivityManager的getActivityManager方法。
380
+
381
+ 比如我们要启动一个Activity的时候,我们调用的是startActivity方法,这个功能的内部实现实际上是Instrumentation完成的。ContextImpl封装了这个功能,使得用户根本不需要知晓Instrumentation相关的信息,直接使用startActivity即可完成相应的工作。其他的子系统功能也是类似的实现,比如启动Service和发送广播内部使用的是ActivityManagerNative等。ContextImpl的结构图如下 :
382
+ ![ context] ( images/contextimpl.png )
248
383
249
- 通过上面的代码可以看出启动Activity需要传递一个上下文Context才可以,通过外观模式我们不需要知道startActivity是怎么启动的,只需要传递上下文Context,这样就大大降低了客户端与子系统的耦合。
384
+ 外观模式非常的简单,只是封装了子系统的操作,并且暴露接口让用户使用,避免了用户需要与多个子系统进行交互,降低了系统的耦合度、复杂度。
250
385
251
386
252
387
## 4. 杂谈
0 commit comments