1. 程式人生 > >Android入門之從輸入裝置中獲取訊息——視窗建立過程

Android入門之從輸入裝置中獲取訊息——視窗建立過程

        上文講到訊息獲取過程,本文來詳細看程式碼。

        我們說視窗建立時會建立本地的ViewRoot,然後呼叫WmS的addWindow方法,所以我們首先來看看WmS的程式碼。

        你會看到frameworks/base/services/java/com/android/server/WindowManagerService.java中,沒有公開的構造子,但有一個main方法,我們推測main方法即是此類的入口(當然,網路上很多資料表明,main方法就是WmS的入口)。

        main方法程式碼如下所示:

public static WindowManagerService main(Context context,
    PowerManagerService pm, boolean haveInputMethods) {
	WMThread thr = new WMThread(context, pm, haveInputMethods);
	thr.start();

	synchronized (thr) {
		while (thr.mService == null) {
		try {
			thr.wait();
		} catch (InterruptedException e) {
		}
		}
	}

	return thr.mService;
}

建立一個WMThread,然後啟動它,WMThread定義在WindowManagerService.java裡面,它的run方法如下所示:
public void run() {
	Looper.prepare();
	WindowManagerService s = new WindowManagerService(mContext, mPM,
			mHaveInputMethods);
	android.os.Process.setThreadPriority(
			android.os.Process.THREAD_PRIORITY_DISPLAY);
	android.os.Process.setCanSelfBackground(false);

	synchronized (this) {
		mService = s;
		notifyAll();
	}

	Looper.loop();
}
        先忽略Looper,後面會再次描述到。

        主體部分是建立一個WindowManagerService,後面是設定執行緒優先順序等,所以有必要看看WindowManagerService的構造方法做了什麼:

private WindowManagerService(Context context, PowerManagerService pm,
		boolean haveInputMethods) {
	mContext = context;
	mHaveInputMethods = haveInputMethods;
	mLimitedAlphaCompositing = context.getResources().getBoolean(
			com.android.internal.R.bool.config_sf_limitedAlpha);

	mPowerManager = pm;
	mPowerManager.setPolicy(mPolicy);
	PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
	mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
			"SCREEN_FROZEN");
	mScreenFrozenLock.setReferenceCounted(false);

	mActivityManager = ActivityManagerNative.getDefault();
	mBatteryStats = BatteryStatsService.getService();

	// Get persisted window scale setting
	mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
			Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
	mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
			Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);

	// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
	IntentFilter filter = new IntentFilter();
	filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
	mContext.registerReceiver(mBroadcastReceiver, filter);

	mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
			"KEEP_SCREEN_ON_FLAG");
	mHoldingScreenWakeLock.setReferenceCounted(false);

	mInputManager = new InputManager(context, this);

	PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
	thr.start();

	synchronized (thr) {
		while (!thr.mRunning) {
			try {
				thr.wait();
			} catch (InterruptedException e) {
			}
		}
	}

	mInputManager.start();

	// Add ourself to the Watchdog monitors.
	Watchdog.getInstance().addMonitor(this);
}

        在WindowManagerService的構造子中,建立了一個InputManager物件,並呼叫它的start()方法,我們可以淺顯地判斷InputManager是一個執行緒類,對應的構造子如下:
public InputManager(Context context, WindowManagerService windowManagerService) {
	this.mContext = context;
	this.mWindowManagerService = windowManagerService;
	
	this.mCallbacks = new Callbacks();
	
	init();
}

        這裡有兩點需要注意,一是Callbacks方法,進入到Callbacks類裡面,可以看到它主要是呼叫了WindowManagerService的其他方法。另一個是init()方法,init內部呼叫了initNative()方法,跟蹤initNative()方法時你會發現它僅僅是有以下定義:
private static native void nativeInit(Callbacks callbacks);

        它沒有具體的實現方法,我們知道,InputManager是Java類,它會與對應的C函式進行互動,所以我們判斷nativeInit實現上是使用JNI呼叫C函式執行操作,那怎麼找到InputManager方法對應的C函式呢?

        InputManager類的全路徑是frameworks/base/services/java/com/android/server/InputManager.java,所以它對應的JNI一定是在frameworks/base/services/jni下,我們找到這個目錄,發現該目錄下有個檔名為com_android_server_InputManager.cpp,與Java檔案的路徑可以找到共同點,於是我們判斷,com_android_server_InputManager.cpp即為InputManager.java對應的C函式。

        InputManager.cpp中定義了一個NativeInputManager物件,該物件有個構造子:

NativeInputManager::NativeInputManager(jobject callbacksObj) :
    mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),
    mMaxEventsPerSecond(-1),
    mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0) {
    JNIEnv* env = jniEnv();

    mCallbacksObj = env->NewGlobalRef(callbacksObj);

    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

        這個構造子即對應了initNative(Callbacks callbacks)方法。

        你會看到在NativeInputManager的構造子中,建立了一個InputManager物件,C程式碼不能直接呼叫Java程式碼,所以這個InputManager當然不是InputManager.java。跟到frameworks/base/libs/ui/InputManager.cpp裡面去,找到對應的InputManager物件的構造子,程式碼如下所示:

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

        或以看到,在InputManager.cpp的構造子中,建立了一個InputDispatcher物件和一個InputReader物件。接著看initialize()方法:
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

        很明顯,在initialize()方法中,分別建立了InputReader執行緒和InputDispatcher執行緒。

        再返回WindowManagerService的構造子,發現其最後一行程式碼是:

Watchdog.getInstance().addMonitor(this);

        再看看WindowManagerService的定義:
public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor {

        由此我們可以判斷,WindowManagerService事實上是一個Monitor,構造子的最後一行,是把WmS本身這個InputMonitor新增到Watchdog裡面。

        再聯絡上文的視窗建立過程:

        我們很容易地把程式碼與上圖關聯起來了。

相關推薦

Android入門輸入裝置獲取訊息——視窗建立過程

        上文講到訊息獲取過程,本文來詳細看程式碼。         我們說視窗建立時會建立本地的ViewRoot,然後呼叫WmS的addWindow方法,所以我們首先來看看WmS的程式碼。         你會看到frameworks/base/services/j

struts框架問題六值棧獲取

  6. 問題六: 在JSP中獲取值棧的資料 * 總結幾個小問題: > 訪問root中資料 不需要# > 訪問context其它物件資料 加 # > 如果向root中存入物件的話,優先使用push方法。 > 如果向

c++ 輸入獲取輸入

點選開啟連結 輸入流物件cin讀取輸入流的三種方式 c++ 從輸入流中獲取特定型別的資料的方式: 1、cin(以空白【空格,製表符和換行符】結束讀取) 2、cin的成員函式 getline(),用法:cin.getline()。功能:獲取一行輸入,包括空白【

Android-音訊檔案獲取專輯圖片

如何獲取本地音訊檔案的專輯圖片呢?不多說了,直接上程式碼吧: public static Bitmap setArtwork(Context context, String url, ImageVie

android封裝框架入門自定義對話方塊開始callback幫你忙

android封裝框架入門之從封裝確定、取消對話方塊開始 最近,封裝了一個輕量級的網路非同步網路請求框架MHttpUtils(傳送門),由於非常喜歡RxJava和Retrofit等的鏈式程式設計風格,於是自己搗鼓著按這種風格來封裝,期間的一些封裝思路抽取出

android 如何系統相簿獲取圖片

http://bbs.csdn.net/topics/390133207 需要在專案中加入一個從系統相簿中選取圖片的功能,選擇的圖片bitmap顯示出來即可,不需要圖片剪下功能網上的例子很多,我用的以下程式碼實現的Intent intent=new Intent(Inten

Android開發--app跳轉到淘寶店鋪

首先、一個工具類   方法,檢測該包名下的應用是否存在 public static boolean checkPackage(Context context ,String packageName) { if (packageName == null || "".

Cocos2d-x3.0 代碼獲取cocostudio編輯的UI控件

ucid 編輯 top ica sans sce nero val -i 依據名字查找控件 須要包括的頭文件及名字空間: #include "cocostudio/CocoStudio.h"#include "ui/CocosGUI.h"using namespac

package.json獲取屬性

pack tps .json over href from version span package var pjson = require(‘./package.json‘); console.log(pjson.version); 詳見:https://stack

Android入門文件系統操作(二)文件操作相關指令

-h tools strong abc his art 為什麽 重命名 path (一)獲取總根 [java] view plain copy File[] fileList=File.listRoots(); //返回fileList.length為1 /

volley6--CacheDispatcher緩存獲取數據

splay nbsp anti without .post getc rri software req 源碼: 1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 *

volley7--NetworkDispatcher網絡獲取數據

ota ria ould min over med unless col call 源碼: 1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed u

[轉]使用@Test 也可以spring容器獲取依賴註入

oca fig article ring1 detail ice 如果 text resource 轉自:http://blog.csdn.net/u010987379/article/details/52091790 @RunWith(SpringJUnit4Cla

Elasticsearch入門零開始安裝ik分詞器

gpo article terms n) rm -rf 從零開始 系列 pack 默認 起因 需要在ES中使用聚合進行統計分析,但是聚合字段值為中文,ES的默認分詞器對於中文支持非常不友好:會把完整的中文詞語拆分為一系列獨立的漢字進行聚合,顯然這並不是我的初衷。我們來看個

postman實現response headers獲取cookie,並將其設置為環境變量

png header 參數 ESS 數組 字段 分割 src 圖片 1.最近在學習postman的使用方法,為了保證後續模塊操作,必須在登錄時獲取的session值,並將其設置為環境變量,session的位置處於response headers裏面返回的set-cookie

php 指定數字獲取隨機組合的方法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

js方法json物件獲取特定值

 //從json中獲得key指定值     function getJsonValue(obj,name){         var result = null;         var v

資料夾獲取指定檔案的檔名

從資料夾中獲取指定檔案的檔名 有時候我們需要從資料夾中判斷一個指定的檔案是否存在,如果存在就返回檔名+字尾名,不存在返回空。前臺可以根據此判斷選擇性的進行圖片的展示情況。 前臺請求獲取響應的檔名 1.配置檔案內:配置路徑資訊 #圖片儲存路徑 本地磁碟C 下面的"XX資料夾"

Jmeter使用Beanshell前處理器指定列表獲取隨機值

變數mynation從列表{"china","US","UK"}中隨機取值 String[] nation = new String[]{"china","US","UK"}; Random random = new Random(); int i = random.nexInt(nation.le

JAVA WEB快速入門編寫一個JSP WEB網站了解JSP WEB網站的基本結構、除錯、部署

接上篇《JAVA WEB快速入門之環境搭建》,在完成了環境搭建後(JDK、Tomcat、IDE),現在是萬事具備,就差寫程式碼了,今天就來從編寫一個JSP WEB網站了解JSP WEB網站的基本結構、除錯、部署,至於為什麼要先寫JSP WEB,而不是直接上SSM(Spring、SpringMVC、Mybati