46. 註冊廣播有幾種方式,這些方式有何優缺點?請談談 Android 引入廣播機制的用意。
Android 廣播機制(兩種註冊方法) 在 android 下,要想接受廣播資訊,那麼這個廣播接收器就得我們自己來實現了,我們可以 繼承 BroadcastReceiver,就可以有一個廣播接受器了。有個接受器還不夠,我們還得重寫 BroadcastReceiver 裡面的 onReceiver 方法,當來廣播的時候我們要幹什麼,這就要我們自己 來實現,不過我們可以搞一個資訊防火牆。具體的代碼: public class SmsBroadCastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); Object[] object = (Object[])bundle.get("pdus"); SmsMessage sms[]=new SmsMessage[object.length]; for(int i=0;i<object.length;i++) { sms[0] = SmsMessage.createFromPdu((byte[])object[i]); Toast.makeText(context, "來自"+sms[i].getDisplayOriginatingAddress()+" 的消 息是:"+sms[i].getDisplayMessageBody(), Toast.LENGTH_SHORT).show(); } //終止廣播, 在這裡我們可以稍微處理, 根據使用者輸入的號碼可以實現簡訊防火牆。 abortBroadcast(); } } 當實現了廣播接收器,還要設定廣播接收器接收廣播資訊的類型,這裡是資訊: android.provider.Telephony.SMS_RECEIVED 我們就可以把廣播接收器註冊到系統裡面, 可以讓系統知道我們有個廣播接收器。 這裡有 兩種,一種是代碼動態註冊: //產生廣播處理 smsBroadCastReceiver = new SmsBroadCastReceiver(); //執行個體化過濾器並設定要過濾的廣播 IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); //註冊廣播 BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver, intentFilter); 一種是在 AndroidManifest.xml 中配置廣播 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="spl.broadCastReceiver" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".BroadCastReceiverActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!--廣播註冊--> <receiver android:name=".SmsBroadCastReceiver"> <intent-filter android:priority="20"> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver> </application> <uses-sdk android:minSdkVersion="7" /> <!-- 許可權申請 --> <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission> </manifest> 兩種註冊類型的區別是: 1)第一種不是常駐型廣播,也就是說廣播跟隨程式的生命週期。 2)第二種是常駐型,也就是說當應用程式關閉後,如果有資訊廣播來,程式也會被系 統調用自動運行。
47. 請解釋下在單執行緒模式中 Message、Handler、Message Queue、Looper 之間的關係。 Handler 簡介: 一個 Handler 允許你發送和處理 Message 和 Runable 對象,這些對象和一個線程的 MessageQueue 相關聯。 每一個線程執行個體和一個單獨的線程以及該線程的 MessageQueue 相關 聯。當你建立一個新的 Handler 時,它就和建立它的線程綁定在一起了。這裡,線程我們也 可以理解為線程的 MessageQueue。從這一點上來看,Handler 把 Message 和 Runable 對象傳 遞給 MessageQueue,而且在這些對象離開 MessageQueue 時,Handler 負責執行他們。 Handler 有兩個主要的用途: (1)確定在將來的某個時間點執行一個或者一些 Message 和 Runnable 對象。 (2)在其他線程(不是 Handler 綁定線程)中排入一些要執行的動作。 Scheduling Message,即(1) ,可以通過以下方法完成: post(Runnable):Runnable 在 handler 綁定的線程上執行,也就是說不建立新線程。 postAtTime(Runnable,long): postDelayed(Runnable,long): sendEmptyMessage(int): sendMessage(Message): sendMessageAtTime(Message,long): sendMessageDelayed(Message,long): post 這個動作讓你把 Runnable 對象排入 MessageQueue,MessageQueue 受到這些訊息的時候 執行他們,當然以一定的排序。sendMessage 這個動作允許你把 Message 對象排成隊列,這 些 Message 對象包含一些資訊, Handler 的 hanlerMessage(Message)會處理這些 Message.當然, handlerMessage(Message)必須由 Handler 的子類來重寫。這是編程人員需要作的事。 當 posting 或者 sending 到一個 Hanler 時,你可以有三種行為:當 MessageQueue 準備好就處 理,定義一個延遲時間,定義一個精確的時間去處理。後兩者允許你實現 timeout,tick,和基 於時間的行為。 當你的應用建立一個新的進程時,主線程(也就是 UI 線程)內建一個 MessageQueue,這個 MessageQueue 管理頂層的應用對象(像 activities,broadcast receivers 等)和主線程建立的窗 體。你可以建立自己的線程,並通過一個 Handler 和主線程進行通訊。這和之前一樣,通過 post 和 sendmessage 來完成,差別在於在哪一個線程中執行這麼方法。在恰當的時候,給定 的 Runnable 和 Message 將在 Handler 的 MessageQueue 中被 Scheduled。 Message 簡介: Message 類就是定義了一個資訊,這個資訊中包含一個描述符和任意的資料對象,這個資訊 被用來傳遞給 Handler.Message 對象提供額外的兩個 int 域和一個 Object 域,這可以讓你在 大多數情況下不用作分配的動作。 儘管 Message 的建構函式是 public 的,但是擷取 Message 執行個體的最好方法是調用 Message.obtain(),或者 Handler.obtainMessage()方法,這些方法會從回收對象池中擷取一個。 MessageQueue 簡介: 這是一個包含 message 列表的底層類。Looper 負責分發這些 message。Messages 並不是直接 加到一個 MessageQueue 中,而是通過 MessageQueue.IdleHandler 關聯到 Looper。 你可以通過 Looper.myQueue()從當前線程中擷取 MessageQueue。 Looper 簡介: Looper 類被用來執行一個線程中的 message 迴圈。 預設情況, 沒有一個訊息迴圈關聯到線程。 線上程中調用 prepare()建立一個 Looper,然後用 loop()來處理 messages,直到迴圈終止。 大多數和 message loop 的互動是通過 Handler。 下面是一個典型的帶有 Looper 的線程實現。 class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
48. AIDL 的全稱是什嗎?如何工作?能處理哪些類型的資料? AIDL 的英文全稱是 Android Interface Define Language 當 A 進程要去調用 B 進程中的 service 時,並實現通訊,我們通常都是通過 AIDL 來操作的 A 工程: 首先我們在 net.blogjava.mobile.aidlservice 包中建立一個 RemoteService.aidl 檔案,在裡面我 們自訂一個介面, 含有方法 get。 ADT 外掛程式會在 gen 目錄下自動產生一個 RemoteService.java 檔案,該類中含有一個名為 RemoteService.stub 的內部類,該內部類中含有 aidl 檔案介面的 get 方法。 說明一:aidl 檔案的位置不固定,可以任意 然後定義自己的 MyService 類,在 MyService 類中自訂一個內部類去繼承 RemoteService.stub 這個內部類,實現 get 方法。在 onBind 方法中返回這個內部類的對象, 系統會自動將這個對象封裝成 IBinder 對象,傳遞給他的調用者。 其次需要在 AndroidManifest.xml 檔案中配置 MyService 類,代碼如下: <!-- 註冊服務 --> <service android:name=".MyService"> <intent-filter> <!-- 指定調用 AIDL 服務的 ID --> <action android:name="net.blogjava.mobile.aidlservice.RemoteService" /> </intent-filter> </service> 為什麼要指定調用 AIDL 服務的 ID,就是要告訴外界 MyService 這個類能夠被別的進程訪問, 只要別的進程知道這個 ID,正是有了這個 ID,B 工程才能找到 A 工程實現通訊。 說明:AIDL 並不需要許可權 B 工程: 首先我們要將 A 工程中產生的 RemoteService.java 檔案拷貝到 B 工程中,在 bindService 方法中綁定 aidl 服務 綁定 AIDL 服務就是將 RemoteService 的 ID 作為 intent 的 action 參數。 說明:如果我們單獨將 RemoteService.aidl 檔案放在一個包裡,那個在我們將 gen 目 錄下的該包拷貝到 B 工程中。如果我們將 RemoteService.aidl 檔案和我們的其他類存放在一 起,那麼我們在 B 工程中就要建立相應的包,以保證 RmoteService.java 檔案的報名正確, 我們不能修改 RemoteService.java 檔案 bindService(new Inten("net.blogjava.mobile.aidlservice.RemoteService"), serviceConnection, Context.BIND_AUTO_CREATE); ServiceConnection 的 onServiceConnected(ComponentName name, IBinder service)方法 中的 service 參數就是 A 工程中 MyService 類中繼承了 RemoteService.stub 類的內部類的對象。
49. 請解釋下 Android 程式運行時許可權與檔案系統許可權的區別。 運行時許可權 Dalvik( android 授權) 檔案系統 linux 核心授權
50. 系統上安裝了多種瀏覽器,能否指定某瀏覽器訪問指定頁面?請說明原由。 通過直接發送 Uri 把參數帶過去,或者通過 manifest 裡的 intentfilter 裡的 data 屬性 51. 你如何評價 Android 系統?優缺點。
答:Android 平台手機 5 大優勢:
一、開放性 在優勢方面,Android 平台首先就是其開發性,開發的平台允許任何移動終端廠商加入到 Android 聯盟中來。 顯著的開放性可以使其擁有更多的開發人員, 隨著使用者和應用的日益豐富, 一個嶄新的平台也將很快走向成熟。開放性對於 Android 的發展而言,有利於積累人氣,這 裡的人氣包括消費者和廠商,而對於消費者來講,隨大的受益正是豐富的軟體資源。開放的 平台也會帶來更大競爭,如此一來,消費者將可以用更低的價位購得心儀的手機。
二、掙脫電訊廠商的束縛 在過去很長的一段時間,特別是在歐美地區,手機應用往往受到電訊廠商制約,使用什麼功能 接入什麼網路,幾乎都受到電訊廠商的控制。從去年 iPhone 上市 ,使用者可以更加方便地串連 網路, 電訊廠商的制約減少。 隨著 EDGE、 HSDPA 這些 2G 至 3G 移動網路的逐步過渡和提升, 手機隨意接入網路已不是電訊廠商口中的笑談,當你可以通過手機 IM 軟體方便地進行即時聊 天時,再回想不久前天價的多媒體訊息和圖鈴下載業務,是不是像噩夢一樣?互連網巨頭 Google 推動的 Android 終端天生就有網路特色,將讓使用者離互連網更近。
三、豐富的硬體選擇 這一點還是與 Android 平台的開放性相關,由於 Android 的開放性,眾多的廠商會推出千奇 百怪,功能特色各具的多種產品。功能上的差異和特色,卻不會影響到資料同步、甚至軟體 的相容,好比你從諾基亞 Symbian 風格手機 一下改用蘋果 iPhone ,同時還可將 Symbian 中優秀的軟體帶到 iPhone 上使用、 連絡人等資料更是可以方便地轉移, 是不是非常方便呢?
四、不受任何限制的開發商 Android 平台提供給第三方開發商一個十分寬泛、自由的環境,不會受到各種條條框框的阻 擾,可想而知,會有多少新穎別緻的軟體會誕生。但也有其兩面性,血腥、暴力、情色方面 的程式和遊戲如可控制正是留給 Android 難題之一。
五、無縫結合的 Google 應用 如今叱詫互連網的 Google 已經走過 10 年度曆史,從搜尋巨人到全面的互連網滲透,Google 服務如地圖、郵件、搜尋等已經成為串連使用者和互連網的重要紐帶,而 Android 平台手機將 無縫結合這些優秀的 Google 服務。
再說 Android 的 5 大不足:
一、安全和隱私 由於手機 與互連網的緊密聯絡,個人隱私很難得到保守。除了上網過程中經意或不經意留 下的個人足跡,Google 這個巨人也時時站在你的身後,洞穿一切,因此,互連網的深入將 會帶來新一輪的隱私危機。
二、首先開賣 Android 手機的不是最大電訊廠商 眾所周知,T-Mobile 在 23 日,於美國紐約發布 了 Android 首款手機 G1。但是在北美市場, 最大的兩家電訊廠商乃 AT&T 和 Verizon, 而目前所知取得 Android 手機銷售權的僅有 T-Mobile 和 Sprint,其中 T-Mobile 的 3G 網路相對於其他三家也要遜色不少,因此,使用者可以買賬購 買 G1,能否體驗到最佳的 3G 網路服務則要另當別論了!
三、電訊廠商仍然能夠影響到 Android 手機 在國內市場,不少使用者對購得移動定製機不滿,感覺所購的手機被人塗畫了廣告一般。這樣 的情況在國外市場同樣出現。Android 手機的另一發售電訊廠商 Sprint 就將在其機型中內建其 手機商店程式。
四、同類機型使用者減少 在不少手機論壇都會有針對某一型號的子論壇, 對一款手機的使用心得交流, 並分享軟體資 源。而對於 Android 平台手機,由於廠商豐富,產品類型多樣,這樣使用同一款機型的使用者 越來越少,缺少統一機型的程式強化。舉個稍顯不當的例子,現在山寨機泛濫,品種各異, 就很少有專門針對某個型號山寨機的討論和群組, 除了哪些功能異常搶眼、 頗受追捧的機型 以外。
五、過分依賴開發商缺少標準配置 在使用 PC 端的 Windows Xp 系統的時候,都會內建微軟 Windows Media Player 這樣一個瀏 覽器程式,使用者可以選擇更多樣的播放器,如 Realplay 或暴風影音等。但入手開始使用默 認的程式同樣可以應付多樣的需要。在 Android 平台中,由於其開放性,軟體更多依賴第 三方廠商,比如 Android 系統的 SDK 中就沒有內建音樂 播放器,全部依賴第三方開發,缺 少了產品的統一性。
52. 什麼是 ANR 如何避免它?
答:ANR:Application Not Responding,五秒 在 Android 中,Active Manager和視窗管理器這兩個系統服務負責監視應用程式的響應。當出現 下列情況時,Android 就會顯示 ANR 對話方塊了: 對輸入事件(如按鍵、觸控螢幕事件)的響應超過 5 秒 意向接受器(intentReceiver)超過 10 秒鐘仍未執行完畢 Android 應用程式完全運行在一個獨立的線程中(例如 main)。這就意味著,任何在主線 程中啟動並執行,需要消耗大量時間的操作都會引發 ANR。因為此時,你的應用程式已經沒有 機會去響應輸入事件和意向廣播(Intent broadcast)。
因此,任何運行在主線程中的方法,都要儘可能的只做少量的工作。特別是活動生命周 期中的重要方法如 onCreate()和 onResume()等更應如此。潛在的比較耗時的操作,
如訪問 網路和資料庫;或者是開銷很大的計算,比如改變位元影像的大小,需要在一個單獨的子線程中 完成(或者是使用非同步請求,如資料庫操作)。但這並不意味著你的主線程需要進入阻塞狀態 已等待子線程結束 -- 也不需要調用 Therad.wait()或者 Thread.sleep()方法。 取而代之的是, 主線程為子線程提供一個控制代碼(Handler), 讓子線程在即將結束的時候調用它(xing:可以參看 Snake 的例子,這種方法與以前我們所接觸的有所不同)。使用這種方法涉及你的應用程式, 能夠保證你的程式對輸入保持良好的響應, 從而避免因為輸入事件超過 5 秒鐘不被處理而產 生的 ANR。這種實踐需要應用到所有顯示使用者介面的線程,因為他們都面臨著同樣的逾時 問題。
53. 什麼情況會導致 Force Close ?如何避免?能否捕獲導致其的異常?
答:一般像null 指標啊,可以看起 logcat,然後對應到程式中 來解決錯誤
55. 簡要解釋一下 activity、 intent 、intent filter、service、Broadcase、BroadcaseReceiver
答:一個 activity 呈現了一個使用者可以操作的可視化使用者介面 一個 service 不包含可見的使用者介面,而是在後台無限地運行 可以串連到一個正在啟動並執行服務中, 串連後, 可以通過服務中暴露出來的借口與其進行 通訊 一個 broadcast receiver 是一個接收廣播訊息並作出回應的 component,broadcast receiver 沒有介面 intent:content provider 在接收到 ContentResolver 的請求時被啟用。 activity, service 和 broadcast receiver 是被稱為 intents 的非同步訊息啟用的。 一個 intent 是一個 Intent 對象,它儲存了訊息的內容。對於 activity 和 service 來說,它指 定了請求的操作名稱和待操作資料的 URI Intent 對象可以顯式的指定一個目標 component。如果這樣的話,android 會找到這個 component(基於 manifest 檔案中的聲明)並啟用它。但如果一個目標不是顯式指定的, android 必須找到響應 intent 的最佳 component。 它是通過將 Intent 對象和目標的 intent filter 相比較來完成這一工作的。一個 component 的 intent filter 告訴 android 該 component 能處理的 intent。intent filter 也是在 manifest 檔案中聲明的。
56. IntentService 有何優點?
答:IntentService 的好處 * Acitivity 的進程,當處理 Intent 的時候,會產生一個對應的 Service * Android 的進程處理器現在會儘可能的不 kill 掉你 * 非常容易使用
57. 橫豎屏切換時候 activity 的生命週期?
1、不設定 Activity 的 android:configChanges 時,切屏會重新調用各個生命週期,切橫 屏時會執行一次,切豎屏時會執行兩次 2、設定 Activity 的 android:configChanges="orientation"時,切屏還是會重新調用各個 生命週期,切橫、豎屏時只會執行一次 3、設定 Activity 的 android:configChanges="orientation|keyboardHidden"時,切屏不 會重新調用各個生命週期,只會執行 onConfigurationChanged 方法 如何將 SQLite 資料庫(dictionary.db 檔案)與 apk 檔案一起發布? 解答:可以將 dictionary.db 檔案複製到 Eclipse Android 工程中的 res aw 目錄中。所有 在 res aw 目錄中的檔案不會被壓縮,這樣可以直接提取該目錄中的檔案。可以將 dictionary.db 檔案複製到 res aw 目錄中
58. 如何將開啟 res aw 目錄中的資料庫檔案?
解答:在 Android 中不能直接開啟 res aw 目錄中的資料庫檔案,而需要在程式第一次 啟動時將該檔案複製到手機記憶體或 SD 記憶卡的某個目錄中,然後再開啟該資料庫檔案。複製的 基本方法是使用 getResources().openRawResource 方法獲得 res aw 目錄中資源的 InputStream 對象,然後將該 InputStream 對象中的資料寫入其他的目錄中相應檔案中。在 Android SDK 中可以使用 SQLiteDatabase.openOrCreateDatabase 方法來開啟任意目錄中的 SQLite 資料庫檔案。