Android Telephony分析(七) ---- 接口扩展(异步转同步)
本文是基于上一篇《Android Telephony分析(六) —- 接口擴(kuò)展(實(shí)踐篇)》來寫的。?
上一篇介紹的接口擴(kuò)展的方法需要實(shí)現(xiàn)兩部分代碼:?
1. 從APP至RIL,發(fā)送請求;?
2. 從RIL至APP,上報(bào)結(jié)果。
由于這是一個(gè)異步請求,所以兩部分流程都不能少,導(dǎo)致流程過于復(fù)雜。?
而本文的目的就是為了將異步請求轉(zhuǎn)換成同步請求,節(jié)省第二部分“上報(bào)結(jié)果”的流程,從而簡化整個(gè)接口擴(kuò)展的流程和代碼量。(當(dāng)然,雖然《Android Telephony分析(六) —- 接口擴(kuò)展(實(shí)踐篇)》代碼流程復(fù)雜了些,但是它綜合較多的知識(shí)點(diǎn),其自身的價(jià)值還是有的。)
本文來自http://blog.csdn.net/linyongan?,轉(zhuǎn)載請務(wù)必注明出處。
1. 具體的代碼實(shí)現(xiàn)
1.1 擴(kuò)展CommandsInterface接口
同《Android Telephony分析(六) —- 接口擴(kuò)展(實(shí)踐篇)》1.1小節(jié)。
1.2 擴(kuò)展PhoneInternalInterface接口
同《Android Telephony分析(六) —- 接口擴(kuò)展(實(shí)踐篇)》1.2小節(jié)。?
假如現(xiàn)在Phone.java (frameworks\opt\telephony\src\java\com\Android\internal\telephony)中已有兩個(gè)可用的接口:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
1.3 擴(kuò)展ITelephony接口
先在ITelephony.aidl(frameworks\base\telephony\java\com\android\internal\telephony)中新增接口:
boolean setValueToModem (int input); String getValueFromModem();- 1
- 2
- 1
- 2
請注意,此時(shí)接口的返回值已不再是void。?
在PhoneInterfaceManager.java (packages\services\telephony\src\com\android\phone)中實(shí)現(xiàn)該接口:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
同時(shí)需要定義四個(gè)消息:
private static final int CMD_GET_VALUE = 100;private static final int EVENT_GET_VALUE_DONE = 101;private static final int CMD_SET_VALUE = 102;private static final int EVENT_SET_VALUE_DONE = 103;- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
以及在內(nèi)部類MainThreadHandler的handleMessage()方法中添加對這四個(gè)消息的處理:
//發(fā)送get請求時(shí)的處理 case CMD_GET_VALUE:request = (MainThreadRequest) msg.obj;//將在sendRequest()方法中創(chuàng)建的MainThreadRequest對象封裝進(jìn)新的Message中。onCompleted = obtainMessage(EVENT_GET_VALUE_DONE, request);//在這里調(diào)用Phone中的接口mPhone.getValueFromModem(onCompleted);break;//對于get請求modem返回結(jié)果的處理 case EVENT_GET_VALUE_DONE:ar = (AsyncResult) msg.obj;//取出發(fā)送請求時(shí)創(chuàng)建的MainThreadRequest對象request = (MainThreadRequest) ar.userObj;//如果沒有出現(xiàn)異常且返回的結(jié)果不為空if (ar.exception == null && ar.result != null) {request.result = ar.result;// String} else {//get請求出現(xiàn)異常,返回默認(rèn)值request.result = "";if (ar.result == null) {loge("getValueFromModem: Empty response");} else if (ar.exception instanceof CommandException) {loge("getValueFromModem: CommandException: " +ar.exception);} else {loge("getValueFromModem: Unknown exception");}}synchronized (request) {//喚醒所有正在等待該對象的線程,退出wait的狀態(tài)request.notifyAll();}break;//get請求,同理 case CMD_SET_VALUE:request = (MainThreadRequest) msg.obj;onCompleted = obtainMessage(EVENT_SET_VALUE_DONE, request);mPhone.setValueToModem((Integer) request.argument, onCompleted);break;case EVENT_SET_VALUE_DONE:ar = (AsyncResult) msg.obj;request = (MainThreadRequest) ar.userObj;if (ar.exception == null) {request.result = true;} else {request.result = false;if (ar.exception instanceof CommandException) {loge("setValueToModem: CommandException: " + ar.exception);} else {loge("setValueToModem: Unknown exception");}}synchronized (request) {request.notifyAll();}break;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
在PhoneInterfaceManager.java中的代碼是本文的核心。在sendRequest()方法中會(huì)進(jìn)入死循環(huán),調(diào)用object.wait()強(qiáng)行阻塞線程,直到modem返回結(jié)果上來后,object的notifyAll()才停止,最后直接把結(jié)果返回給APP,所以這就是將異步請求強(qiáng)行轉(zhuǎn)換成同步的解決方案。?
sendRequest()方法是android原生的,不用我們添加代碼:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
接著在TelephonyManager.java (frameworks\base\telephony\java\android\telephony)中封裝Phone Service的方法:
/**@hide*/public String getValueFromModem() {try {ITelephony telephony = getITelephony();if (telephony != null)return telephony.getValueFromModem();} catch (RemoteException ex) {Rlog.e(TAG, "getValueFromModem RemoteException", ex);} catch (NullPointerException ex) {Rlog.e(TAG, "getValueFromModem NPE", ex);}return ""; }/**@hide*/public boolean setValueToModem(int input) {try {ITelephony telephony = getITelephony();if (telephony != null)return telephony.setValueToModem(input);} catch (RemoteException ex) {Rlog.e(TAG, "setValueToModem RemoteException", ex);} catch (NullPointerException ex) {Rlog.e(TAG, "setValueToModem NPE", ex);}return false;}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
整個(gè)過程的時(shí)序圖如下:?
2. APP如何使用接口
在APP中可以這樣調(diào)用并調(diào)試接口:
//set值 boolean setResult = TelephonyManager.getDefault().setValueToModem(1); //get值 String getResult = TelephonyManager.getDefault().getValueToModem();- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
在APP側(cè)來看,確實(shí)簡單省事了很多,調(diào)用接口就可以馬上得到返回值,但是有點(diǎn)需要注意的是,為了防止這種接口阻塞主線程,所以最好在子線程中調(diào)用這類接口。
3. 總結(jié)
將異步請求轉(zhuǎn)換成同步請求,緊緊依賴著Object類的wait和notifyAll方法才能實(shí)現(xiàn)。當(dāng)然Android代碼中不僅僅只有PhoneInterfaceManager.java這個(gè)地方使用了這種方法,高通也實(shí)現(xiàn)了類似的代碼提供API給APP側(cè)調(diào)用,進(jìn)而可以動(dòng)態(tài)修改某些NV的值,這里只能點(diǎn)到為止。最后附上wait和notifyAll方法的詳解:?
void wait() :?
導(dǎo)致線程進(jìn)入等待狀態(tài),直到它被其他線程通過notify()或者notifyAll喚醒。該方法只能在同步方法中調(diào)用。如果當(dāng)前線程不是鎖的持有者,該方法拋出一個(gè)IllegalMonitorStateException異常。?
void notifyAll() :?
解除所有那些在該對象上調(diào)用wait方法的線程的阻塞狀態(tài)。該方法只能在同步方法或同步塊內(nèi)部調(diào)用。如果當(dāng)前線程不是鎖的持有者,該方法拋出一個(gè)IllegalMonitorStateException異常。
原文地址: http://blog.csdn.net/linyongan/article/details/52189217
總結(jié)
以上是生活随笔為你收集整理的Android Telephony分析(七) ---- 接口扩展(异步转同步)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Telephony分析(
- 下一篇: 进程间通信--IPC