Skip to content

Commit 71c1088

Browse files
committed
update facade
1 parent 58d8784 commit 71c1088

File tree

2 files changed

+191
-56
lines changed

2 files changed

+191
-56
lines changed

facade/elsdnwn/images/contextimpl.png

50.5 KB
Loading

facade/elsdnwn/readme.md

Lines changed: 191 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Android设计模式源码解析之外观模式(Facade)
3939
### 实现源码
4040
TvController.java
4141

42-
```
42+
```java
4343
public class TvController {
4444
private PowerSystem mPowerSystem = new PowerSystem();
4545
private VoiceSystem mVoiceSystem = new VoiceSystem();
@@ -168,85 +168,220 @@ public class TvController {
168168
上面的TvController封装了对电源、声音、频道切换的操作,为用户提供了一个统一的接口。使得用户控制电视机更加的方便、更易于使用。
169169

170170
## 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运行起来。我们看看下面的相关代码:
172174

173175
```
174-
package com.elsdnwn.Facade;
176+
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
177+
// 代码省略
175178
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);
179181
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);
186187
187-
Intent intent = new Intent();
188-
intent.setClass(this, MainActivity2.class);
189-
startActivity(intent);
190-
}
188+
}
189+
}
191190
192-
}
193191
194-
```
192+
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
193+
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
194+
// 代码省略
195195
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+
}
197213
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+
}
199287
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
201341
public void startActivity(Intent intent) {
202342
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
203343
throw new AndroidRuntimeException(
204344
"Calling startActivity() from outside of an Activity "
205345
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
206346
+ " Is this really what you want?");
207347
}
208-
209-
// 其实是用的getInstrumentation().execStartActivity();
210348
mMainThread.getInstrumentation().execStartActivity(
211-
getOuterContext(), mMainThread.getApplicationThread(), null,
212-
(Activity)null, intent, -1);
349+
getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
213350
}
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());
241363
}
364+
return cn;
365+
} catch (RemoteException e) {
366+
return null;
242367
}
243-
// 代码略...
244-
return null;
245368
}
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+
}
247378
```
379+
可以看到,ContextImpl内部有很多xxxManager类的对象,也就是我们上文所说的各种子系统的角色。ContextImpl内部封装了一些系统级别的操作,有的子系统功能虽然没有实现,但是也提供了访问该子系统的接口,比如获取ActivityManager的getActivityManager方法。
380+
381+
比如我们要启动一个Activity的时候,我们调用的是startActivity方法,这个功能的内部实现实际上是Instrumentation完成的。ContextImpl封装了这个功能,使得用户根本不需要知晓Instrumentation相关的信息,直接使用startActivity即可完成相应的工作。其他的子系统功能也是类似的实现,比如启动Service和发送广播内部使用的是ActivityManagerNative等。ContextImpl的结构图如下 :
382+
![context](images/contextimpl.png)
248383

249-
通过上面的代码可以看出启动Activity需要传递一个上下文Context才可以,通过外观模式我们不需要知道startActivity是怎么启动的,只需要传递上下文Context,这样就大大降低了客户端与子系统的耦合。
384+
外观模式非常的简单,只是封装了子系统的操作,并且暴露接口让用户使用,避免了用户需要与多个子系统进行交互,降低了系统的耦合度、复杂度。
250385

251386

252387
## 4. 杂谈

0 commit comments

Comments
 (0)