Androidのビュー描画とイベント配信の流れ(下段)
14306 ワード
他人の労働成果を尊重してください.勝手に盗作しないでください.転載は明記してください.ありがとうございます.
転載は出典を明記してください.http://blog.csdn.net/evan_マン/アート/detail/521999517
本論文では、ActivityのSetContentView方法の下層部はどのように私達のlayout.xmlファイルを処理していますか?そして、WindowManagerServiceからWiewのdispatTouchEvent方法に事件がどのように伝えられているかを簡単に分析してみます.
ActivityでViewを作成する過程は大体次の通りです. Activity対応の呼び出しを行いました. はその後、set ContentViewを実行する.実際に呼び出したPhone Window.set ContentView方法 です.は、DecorView、View、またはView Groupオブジェクト を作成する.
OResumeメソッドを呼び出しました.Activityのmake Visibleを呼び出す方法があります. WindowManagerを取得し、そのaddView方法を呼び出して、WindowManager Serviceにビューを渡して管理します. View RootとW を作成します. WinowManagerがWmSのリモートインターフェースを呼び出して完了しました.画面 にウィンドウを追加しました.
フロントビューのset Visibilityメソッドを呼び出します.この方法は最終的にはView RootのperformTravels方法にジャンプします.参考メモ『View—重絵』 set ContentViewの方法の内容は以下の通りです.
1、comp.android.internal.policy.impl.Phone Window
のsetContintViewとget Decorviewの2つの方法を参照してください.
2、
android.view.WindowManager
のaddView方法を探究します.
3、View Rootの作成、表示、イベントの配布
ビューの描画
Phone Window.class (comp.android.internal.policy.impl.Phone Window)
set ContentView(View) )@Phone Window.class
2、contentViewをmConteent Partに追加する
View Group content Parter=(View Group)decor.findView ById(IDuANDROIDu CONTENT)に相当します.
public static final int IDuANDROIDENT=comp.android.internal.R.id.com nt.mDecor.findViewByIdに相当する.
comp.android.internal.R.id.com nt
を選択します
取得したのは、ユーザがViewをカスタマイズしたレイアウトファイルの親レイアウトです.
get Decorview()@Phone Window.class
WindowManagerがよく使うのは3つの方法addView、udateView、removeViewがあります.
WindowManagerのaddViewメソッドの下の階は、Viewに基づいてView Rootを作成し、View Rootの内部にはWクラスが含まれています. Wは、IWindow.Stubインターフェースを実現したView Rootの内部クラスであり、効果はView Rootを呼び出す同名の方法であり、WMSとView Rootの間の通信は明らかにWに通過している. 、ViewRootからWMSへの通信は、IWindowSession=IWindowManager.Stub.asInterface( ServiceManager.get Service(「window」).openSession(imm.get Cient(),imm.getInputContext(); WでもIWindowSessionでも、彼らの最下層はBinder通信方式によって実現されます. ViewはAndroidビューの表現ですが、Viewは単独では存在しません.Windowという抽象的な概念に依存しなければなりません.一つのPhone WindowはViewに対応しています.一つのviewはView RootとWindowManager.LayoutParamに対応しています.
View Rootはビュー描画の制御とイベントの処理を行うために、Window Manager.LayoutParaamsはWMSの現在のWindowが画面のどの位置にあるかを知らせるために使用されます.ここでWindow Manager.LayoutParaamsのflagsとtypeパラメータが重要です.
WindowManager.LayoutParaams.class FLAG_NOTUFOCUSABLE:入力イベントを受け付けないことを示しています.このフラグは同時にFLAG_NOTKUMODALを起動します.入力イベントは下の階のフォーカスWindow に伝達されます. FLAG_NOTUTOUCH_MODAL:現在Windowエリア以外のクリックイベントは下のWindowに伝達されています.現在Windowエリア内のクリックイベントは自分で処理します.一般的にはこのマークをオンにしないと、下のWindowはイベントを取得できません. FLAG_SHOW_WHEN_uLOCKED:このWindowをスクリーンロックの画面上に表示させることができるようにする.
TypeパラメータはWindowのタイプを表しています.Windowには三つのタイプがあります. アプリケーションWindow:つまり、私たちの普通のActivityに対応するView です.子Window:父Windowに依存する必要があります.dialog のように単独では存在できません.システムWindow:Toastとシステムステータスバー など、ステートメント権限が必要です.
Windowは階層的で、対応するz-ordedが大きいほど前に表示され、階層が大きいほど、階層が小さいWindowをカバーします. 具体的には次のとおりです
WindowManagerのaddViewメソッドの下の階はView RootとWクラスを作成します.
1、WはIWindow.Stubインターフェースを実現したView Rootの内部クラスであり、効果はView Rootを呼び出す同名の方法であり、WMSとView Rootの間の通信は明らかにWを通じている.
2、ViewRootからWMSへの通信はIWindowSession swindowSession=IWindowManager.Stub.asInterface(
ServiceManager.get Service(「window」)
openSession(imm.get Client()、imm.get Input Contect();
3、Wであろうと、IWindowSessionであろうと、彼らの最下層はBinder通信機構によって実現されます.
addViewのパラメータはmDecorWindowですので、View Rootの作成はこのmDecorviewに基づいています.View RootのmViewドメインに対応しています.そのため、mDecorWindowは最初にユーザがクリックしたイベントを受信したViewです.下で全体の流れを分析します.
まずView RootのhandleMessage方法から見ます.
handle Message()@View Root.class
deliverPointerEvent()@View Root.lass
dispatch TouchEvent()@DecorWindow.class
2、cb.dispatch TouchEvent(ev)はActivityのdispatch TouchEventを呼び出す方法です.
atch Touch Event()@Activity.lass
super Displatch TouchEvent()方法
2、自分のワンタッチイベントを呼び出す方法
upler Displatch TouchEvent()@Phone Window.class
upler Displatch Touch
Event()@DecorWindow.class
上記の簡単な分析により、WMSからのイベント(W転送によるW変換イベントは非同期イベント)をまずView Rootが受信したという結論が分かります.その後、ViewRootは、Handlerでイベントを処理します.ユーザのタッチスクリーン情報などのイベントの多くは、直接的なサブビュー、すなわちDecorWindowオブジェクトに任せることが多いです.DecorWindowのdispatch TouchEvent方法を例にとって、この方法の内部ではgetCallbackのdispatch TouchEventメソッドを呼び出します.dispatch TouchEventメソッド内部ではまずPhone Windowのsuper DisplatTouchEventメソッドを呼び出します.(メソッド内部でDecorWindowのsuper DisplatTouchEventメソッドを呼び出します.さらにDecorWindowの親タイプFrame Layoutのdispatch TouchEvent方法を呼び出します.次は普通のVictEventの配布プロセスです.)イベントがDecorWindowの下のViewで処理されていない場合は、最後に自身のon TouchEventメソッドを呼び出します.
転載は出典を明記してください.http://blog.csdn.net/evan_マン/アート/detail/521999517
本論文では、ActivityのSetContentView方法の下層部はどのように私達のlayout.xmlファイルを処理していますか?そして、WindowManagerServiceからWiewのdispatTouchEvent方法に事件がどのように伝えられているかを簡単に分析してみます.
ActivityでViewを作成する過程は大体次の通りです.
[email protected]
public void setContentView(@LayoutRes int layoutResID) {
mWindow.setContentView(layoutResID);
initWindowDecorActionBar(); // ActionBar
}
private Window mWindow = new PhoneWindow(this);
プロットの下の詳細を分析するなら、次のいくつかの方法から開始します.1、comp.android.internal.policy.impl.Phone Window
のsetContintViewとget Decorviewの2つの方法を参照してください.
2、
android.view.WindowManager
のaddView方法を探究します.
3、View Rootの作成、表示、イベントの配布
ビューの描画
Phone Window.class (comp.android.internal.policy.impl.Phone Window)
public class PhoneWindow extends Window
private DecorView mDecor; //DecorView PhoneWindow private final class DecorView extends FrameLayout
private ViewGroup mContentParent;
private LayoutInflater mLayoutInflater;
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
set ContentView(int)@Phone Window.class@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent); //note1
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
1、xmlファイルを解析しながらparentをmConteent Parentとするset ContentView(View) )@Phone Window.class
@Override
public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor(); //note1
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
mContentParent.addView(view, params); //noe1
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
1、DecorWindowとContentPartentを作成する2、contentViewをmConteent Partに追加する
installDecor()@PhoneWindow.class
private void installDecor() {
if (mDecor == null) { // DecorWindow
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) { // mContentParent
mContentParent = generateLayout(mDecor); // DecorWindow parent ViewGroup
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
.........
}
}
generateDecor()@PhoneWindow.class
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
generateLayout()@PhoneWindow.class
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
....// DecorWindow WrapContent
int layoutResource;
int features = getLocalFeatures();
....// feature
View in = mLayoutInflater.inflate(layoutResource, null); // View, 、ActionBar、 View
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); //note1
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
......
return contentParent;
}
1、View Group content Parter=(View Group)decor.findView ById(IDuANDROIDu CONTENT)に相当します.
public static final int IDuANDROIDENT=comp.android.internal.R.id.com nt.mDecor.findViewByIdに相当する.
comp.android.internal.R.id.com nt
を選択します
取得したのは、ユーザがViewをカスタマイズしたレイアウトファイルの親レイアウトです.
get Decorview()@Phone Window.class
@Override
public final View getDecorView() {
if (mDecor == null) {
installDecor();
}
return mDecor;
}
WindowManager.classWindowManagerがよく使うのは3つの方法addView、udateView、removeViewがあります.
WindowManagerのaddViewメソッドの下の階
View Rootはビュー描画の制御とイベントの処理を行うために、Window Manager.LayoutParaamsはWMSの現在のWindowが画面のどの位置にあるかを知らせるために使用されます.ここでWindow Manager.LayoutParaamsのflagsとtypeパラメータが重要です.
WindowManager.LayoutParaams.class
WindowManager.LayoutParams extends ViewGroup.LayoutParams implements Parcelable{
public int x;
// X , ; gravity LEFT、RIGHT x
public int y;
// Y , ; gravity BOTTOM、TOP y
public int flags;
public int type;
.....
}
FlaggasパラメータはWindowの属性を表し、Flagsパラメータの値を変更することによってWindowの表示特性を制御します.TypeパラメータはWindowのタイプを表しています.Windowには三つのタイプがあります.
Windowは階層的で、対応するz-ordedが大きいほど前に表示され、階層が大きいほど、階層が小さいWindowをカバーします. 具体的には次のとおりです
// Window 1~99
FIRST_APPLICATION_WINDOW = 1;
TYPE_BASE_APPLICATION = 1;
TYPE_APPLICATION = 2;
TYPE_APPLICATION_STARTING = 3;
LAST_APPLICATION_WINDOW = 99;
// Window 1000~1999
FIRST_SUB_WINDOW = 1000;
TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;
TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
LAST_SUB_WINDOW = 1999;
// Window 2000~2999
FIRST_SYSTEM_WINDOW = 2000;
TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;
TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;
TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6;
TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7;
TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8;
TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9;
TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10; // AndroidManifest
TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11;
TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;
TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14;
TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
TYPE_DRAG = FIRST_SYSTEM_WINDOW+16;
TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;
TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
TYPE_KEYGUARD_SCRIM = FIRST_SYSTEM_WINDOW+29;
TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;
TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
LAST_SYSTEM_WINDOW = 2999;
イベントの配布WindowManagerのaddViewメソッドの下の階はView RootとWクラスを作成します.
1、WはIWindow.Stubインターフェースを実現したView Rootの内部クラスであり、効果はView Rootを呼び出す同名の方法であり、WMSとView Rootの間の通信は明らかにWを通じている.
2、ViewRootからWMSへの通信はIWindowSession swindowSession=IWindowManager.Stub.asInterface(
ServiceManager.get Service(「window」)
openSession(imm.get Client()、imm.get Input Contect();
3、Wであろうと、IWindowSessionであろうと、彼らの最下層はBinder通信機構によって実現されます.
addViewのパラメータはmDecorWindowですので、View Rootの作成はこのmDecorviewに基づいています.View RootのmViewドメインに対応しています.そのため、mDecorWindowは最初にユーザがクリックしたイベントを受信したViewです.下で全体の流れを分析します.
まずView RootのhandleMessage方法から見ます.
handle Message()@View Root.class
public void handleMessage(Message msg) {
case DISPATCH_POINTER: {
MotionEvent event = (MotionEvent) msg.obj;
try {
deliverPointerEvent(event);
} finally {
event.recycle();
if (msg.arg1 != 0) {
finishInputEvent();
}
if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
}
} break;
}
DISPATCHINTERイベントはユーザーのクリックイベントに対応しています.ViewRootのdeliverPointメソッドを呼び出します.deliverPointerEvent()@View Root.lass
private void deliverPointerEvent(MotionEvent event){
....
handled = mView.dispatchTouchEvent(event);
....
}
View RootのdeliverPoint EventメソッドはmViewのdispatch TouchEventメソッドを呼び出します.dispatch TouchEvent()@DecorWindow.class
public boolean dispatchTouchEvent(MotionEvent ev) {
final Callback cb = getCallback(); //note1
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) //note2
: super.dispatchTouchEvent(ev);
}
1、Phone WindowのgetCallbackメソッドを呼び出してActivityがAttach方法で導入したCallbackオブジェクトを取得し、Activityがこのインターフェースを実現しました.2、cb.dispatch TouchEvent(ev)はActivityのdispatch TouchEventを呼び出す方法です.
@Window.class
public void setCallback(Callback callback) {
mCallback = callback;
}
@Window.class
public final Callback More ...getCallback() {
return mCallback;
}
dispatch Touch Event()@Activity.lass
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) { //note1
return true;
}
return onTouchEvent(ev); //note2
}
1、Phone Windowを呼び出すsuper Displatch TouchEvent()方法
2、自分のワンタッチイベントを呼び出す方法
upler Displatch TouchEvent()@Phone Window.class
public boolean uperDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
//呼び出しmDecorDiscpatch TouchEvent方法upler Displatch Touch
Event()@DecorWindow.class
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
//親タイプのFraameLayoutを呼び出すdispatch TouchEventメソッド上記の簡単な分析により、WMSからのイベント(W転送によるW変換イベントは非同期イベント)をまずView Rootが受信したという結論が分かります.その後、ViewRootは、Handlerでイベントを処理します.ユーザのタッチスクリーン情報などのイベントの多くは、直接的なサブビュー、すなわちDecorWindowオブジェクトに任せることが多いです.DecorWindowのdispatch TouchEvent方法を例にとって、この方法の内部ではgetCallbackのdispatch TouchEventメソッドを呼び出します.dispatch TouchEventメソッド内部ではまずPhone Windowのsuper DisplatTouchEventメソッドを呼び出します.(メソッド内部でDecorWindowのsuper DisplatTouchEventメソッドを呼び出します.さらにDecorWindowの親タイプFrame Layoutのdispatch TouchEvent方法を呼び出します.次は普通のVictEventの配布プロセスです.)イベントがDecorWindowの下のViewで処理されていない場合は、最後に自身のon TouchEventメソッドを呼び出します.