1. 程式人生 > >Android面試題【高階工程師版】

Android面試題【高階工程師版】

OOM 記憶體溢位,想要避免OOM 異常首先我們要知道什麼情況下會導致OOM 異常。
1、圖片過大導致OOM
Android 中用 bitmap 時很容易記憶體溢位,比如報如下錯誤:Java.lang.OutOfMemoryError :
bitmap size exceeds VM budget。
解決方法:
方法1: 等比例縮小圖片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
//Options 只儲存圖片尺寸大小,不儲存圖片到記憶體
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2;
Bitmap bmp = null;
bmp = BitmapFactory.decodeResource(getResources(),
mImageIds[position],opts);
//回收
bmp.recycle();//
以上程式碼可以優化記憶體溢位,但它只是改變圖片大小,並不能徹底解決記憶體溢位。
方法2:對圖片採用軟引用,及時地進行recyle()操作
SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap);
if(bitmap != null){
if(bitmap.get() != null && !bitmap.get().isRecycled()){
bitmap.get().recycle();
bitmap = null;
}
}傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
53
方法 3:使用載入圖片框架處理圖片,如專業處理載入圖片的ImageLoader圖片載入框架。還有我
們學的 XUtils的 BitMapUtils來做處理。
2、介面切換導致OOM
一般情況下,開發中都會禁止橫屏的。因為如果是來回切換話,activity 的生命週期會重新銷燬
然後建立。
有時候我們會發現這樣的問題,橫豎屏切換N次後 OOM 了。
這種問題沒有固定的解決方法,但是我們可以從以下幾個方面下手分析。
1、看看頁面佈局當中有沒有大的圖片,比如背景圖之類的。
去除xml中相關設定,改在程式中設定背景圖(放在 onCreate()方法中):
Drawable drawable = getResources().getDrawable(R.drawable.id);
ImageView imageView = new ImageView(this);
imageView.setBackgroundDrawable(drawable);
在Activity destory 時注意,drawable.setCallback(null); 防止 Activity 得不到及時的釋放。
2、跟上面方法相似,直接把 xml 配置檔案載入成 view 再放到一個容器裡,然後直接呼叫
this.setContentView(View view);方法,避免 xml的重複載入。
3、 在頁面切換時儘可能少地重複使用一些程式碼
比如:重複呼叫資料庫,反覆使用某些物件等等......
3、查詢資料庫沒有關閉遊標
程式中經常會進行查詢資料庫的操作,但是經常會有使用完畢 Cursor 後沒有關閉的情況。如果
我們的查詢結果集比較小,對記憶體的消耗不容易被發現,只有在常時間大量操作的情況下才會出現內
存問題,這樣就會給以後的測試和問題排查帶來困難和風險。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
54
4、構造Adapter時,沒有使用快取的 convertView
在使用ListView的時候通常會使用 Adapter,那麼我們應該儘可能的使用ConvertView。
為什麼要使用convertView?
當convertView為空時,用 setTag()方法為每個 View 繫結一個存放控制元件的 ViewHolder物件。
當 convertView 不為空,重複利用已經建立的 view 的時候,使用 getTag()方法獲取繫結的
ViewHolder物件,這樣就避免了 findViewById 對控制元件的層層查詢,而是快速定位到控制元件。
5、Bitmap物件不再使用時呼叫recycle()釋放記憶體
有時我們會手工的操作Bitmap 物件,如果一個 Bitmap 物件比較佔記憶體,當它不再被使用的時
候,可以呼叫Bitmap.recycle()方法回收此物件的畫素所佔用的記憶體,但這不是必須的,視情況而定。
6、其他
Android 應用程式中最典型的需要注意釋放資源的情況是在 Activity 的生命週期中,在
onPause()、onStop()、 onDestroy()方法中需要適當的釋放資源的情況。使用廣播沒有登出也會產
生 OOM。
4、Android 中如何捕獲未捕獲的異常
(一)UncaughtExceptionHandler
1、自 定 義 一 個 Application , 比 如 叫 MyApplication 繼 承 Application 實 現
UncaughtExceptionHandler。
2、覆寫UncaughtExceptionHandler的 onCreate和 uncaughtException方法。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
55
@Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(final Thread thread, final Throwable ex) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
System.out.println(Thread.currentThread());
Toast.makeText(getApplicationContext(), "thread="+thread.getId()+"
ex="+ex.toString(), 1).show();
Looper.loop();
}
}).start();
SystemClock.sleep(3000);
android.os.Process.killProcess(android.os.Process.myPid());
}
}
注意:上面的程式碼只是簡單的將異常打印出來。
在 onCreate 方法中我們給 Thread 類設定預設異常處理 handler,如果這句程式碼不執行則一切
都是白搭。
在uncaughtException 方法中我們必須新開闢個執行緒進行我們異常的收集工作,然後將系統給
殺死。
3、在AndroidManifest中配置該 Application
<application
android:name="com.example.uncatchexception.MyApplication"
---------------------------------------------------------------------------------
(二)Bug收集工具 
56
Crashlytics 是專門為移動應用開發者提供的儲存和分析應用崩潰的工具。國內主要使用的是友
盟做資料統計。
Crashlytics的好處:
1.Crashlytics不會漏掉任何應用崩潰資訊。
2.Crashlytics可以象 Bug 管理工具那樣,管理這些崩潰日誌。
3.Crashlytics 可以每天和每週將崩潰資訊彙總發到你的郵箱,所有資訊一目瞭然。
使用步驟:
1.註冊需要稽核通過才能使用,國內同類產品頂多發個郵箱啟用連結;
2.支援 Eclipse、Intellij IDEA 和 Android Studio等三大 IDE;
3.Eclipse 外掛是iOS 主題風格UI,跟其他plugin 在一起簡直是鶴立雞群;
4.只要登入帳號並選擇專案,會自動匯入 jar包並生成一個序列號,然後在 AndroidManifest.xml
和啟動 Activity 的入口新增初始化程式碼,可以說是一鍵式操作,當然要使用除錯誤統計外的其他功能
還是得自己新增程式碼;
5.不像友盟等國內同類產品,將固定的序列號直接寫入 xml檔案,而是動態自動生成的;當然這個存
放序列號的 xml檔案也是不能修改和提交到版本控制系統的;
6.後臺可以設定郵件提醒,當然這個最好不要開啟,Android開發那數量驚人、千奇百怪的錯誤資訊
你懂的。
7.不僅能統計到 UncaughtException 這種未捕獲的 Crash 異常資訊,只要在 try/catch 程式碼塊的
catch 中新增一行程式碼就能統計到任何異常;傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
57
try{ myMethodThatThrows(); }catch(Exception
e){ Crashlytics.logException(e); //handle your exception here! }
8.相當詳細的錯誤資訊,不僅僅是簡單的列印StackTrace 資訊;並且能看到最近一次crash 的機器
可用記憶體等資訊,而不僅僅是簡單統計機型和版本號。
使用連線:http://blog.csdn.net/smking/article/details/39320695
5、 ANR 是什麼?怎樣避免和解決 ANR(重要)
在 Android 上,如果你的應用程式有一段時間響應不夠靈敏,系統會向用戶顯示一個對話方塊,
這個對話方塊稱作應用程式無響應(ANR:Application Not Responding)對話方塊。使用者可以選擇讓
程式繼續執行,但是,他們在使用你的應用程式時,並不希望每次都要處理這個對話方塊。因此,在程
序裡對響應效能的設計很重要,這樣,系統不會顯示ANR 給使用者。
Activity 5 秒 broadcast10 秒
耗時的操作 worker thread裡面完成, handler message…AsynTask , intentservice.等…
ANR:Application Not Responding,即應用無響應
ANR 一般有三種類型:
1:KeyDispatchTimeout(5 seconds) --主要型別
按鍵或觸控事件在特定時間內無響應
2:BroadcastTimeout(10 seconds)
BroadcastReceiver在特定時間內無法處理完成傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
58
3:ServiceTimeout(20 seconds) --小概率型別
Service在特定的時間內無法處理完成
超時的原因一般有兩種:
(1)當前的事件沒有機會得到處理(UI執行緒正在處理前一個事件沒有及時完成或者looper被某種原
因阻塞住)
(2)當前的事件正在處理,但沒有及時完成
UI執行緒儘量只做跟UI相關的工作,耗時的工作(資料庫操作,I/O,連線網路或者其他可能阻礙 UI
執行緒的操作)放入單獨的執行緒處理,儘量用Handler來處理 UI thread 和 thread 之間的互動。
UI執行緒主要包括如下:
Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick()
AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel()
Mainthread handler: handleMessage(), post(runnable r)
查詢 ANR 的方式: 1. 匯出/data/data/anr/traces.txt,找出函式和呼叫過程,分析程式碼 2. 通過
效能 LOG 人肉查詢
6、Android 執行緒間通訊有哪幾種方式(重要)
 共享記憶體(變數);
 檔案,資料庫;傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
59
 Handler;
 Java裡的 wait(),notify(),notifyAll()
7、Devik 程序,linux 程序,執行緒的區別
Dalvik 虛擬機器執行在 Linux 作業系統之上。Linux 作業系統並沒有純粹的執行緒概念,只要兩個程序
共享一個地址空間,那麼就可以認為它們是同一個程序的兩個執行緒。Linux 系統提供了兩個 fork 和
clone呼叫,其中,前者是用來建立程序的,而後者是用來建立執行緒的。
一般來說,虛擬機器的程序和執行緒都是和目標機器本地作業系統的程序和執行緒一一對應的,這樣的好處
是可以使本地作業系統來排程程序和執行緒。
每個 Android 應用程式程序都有一個 Dalvik 虛擬機器例項。這樣做得好處是 Android 應用程式程序
之間不會互相影響,也就是說,一個 Android 應用程式程序的意外終止,不會影響到其他的應用程
序程序的正常執行。
 每個 Android 應用程式程序都是由一種稱為 Zygote 的程序 fork出來的。Zygote程序是由
init程序啟動起來的,也就是在系統啟動的時候啟動的。Zygnote程序在啟動的時候,會建立一
個虛擬機器例項,並且在這個虛擬機器例項將所有的 Java 核心庫都載入起來。每當 Zygote 程序需
要建立一個Android 應用程式程序的時候,它就通過複製自身來實現,也就是通過 fork 系統調
用來實現。這些被 fork出來的 Android 應用程式程序,一方面是複製了 Zygote 程序中的虛擬
機例項,另外一方面是與 Zygote 程序共享了同一套 Java 核心庫。這樣不僅 Android 程式程序
的建立很快,而且所有的應用程式都共享同一套Java核心庫而節省了記憶體空間。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
60
8、描述一下android 的系統架構?
1. android系統架構分從下往上為linux 核心層、執行庫、應用程式框架層、和應用程式層。
2. linuxkernel:負責硬體的驅動程式、網路、電源、系統安全以及記憶體管理等功能。
3. libraries和 androidruntime:libraries:即 c/c++函式庫部分,大多數都是開放原始碼的
函式庫, 例如 webkit, 該函式庫負責 android 網頁瀏覽器的執行, 例如標準的 c函式庫 libc、
openssl、sqlite等,當然也包括支援遊戲開發2dsgl 和 3dopengles,在多媒體方面有
mediaframework框架來支援各種影音和圖形檔案的播放與顯示,例如mpeg4、h.264、
mp3、 aac、amr、jpg和 png 等眾多的多媒體檔案格式。android 的 runtime 負責解釋和
執行生成的dalvik格式的位元組碼。
4. applicationframework(應用軟體架構),java應用程式開發人員主要是使用該層封裝好的
api進行快速開發。
5. applications:該層是java的應用程式層,android 內建的 googlemaps、e-mail、即時通
信工具、瀏覽器、mp3播放 器等處於該層,java 開發人員開發的程式也處於該層,而且和
內建的應用程式具有平等的位置,可以呼叫內建的應用程式,也可以替換內建的應用程式。
9、android 應用對記憶體是如何限制的?我們應該如何合理使用記憶體?
(2016.01.24)
如何限制的?
Android應用的開發語言為Java,每個應用最大可使用的堆記憶體受到Android系統的限制
•Android每一個應用的堆記憶體大小有限
•通常的情況為 16M-48M傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
61
•通過 ActivityManager的 getMemoryClass()來查詢可用堆記憶體限制
•3.0(HoneyComb)以上的版本可以通過largeHeap=“true”來申請更多的堆記憶體
•NexusS(4.2.1):normal 192, largeHeap 512
•如果試圖申請的記憶體大於當前餘下的堆記憶體就會引發OutOfMemoryError()
•應用程式由於各方面的限制,需要注意減少記憶體佔用,避免出現記憶體洩漏。
獲取這個程式碼:
如何合理使用記憶體?
1、注意資源回收,像資料庫,輸入輸出流,定位操作這樣的物件,要在使用完及時關閉流。
2、少使用靜態變數,因為系統將靜態變數的優先順序設定的很高,會最後回收。所以可能因為靜
態變數導致該回收的沒有回收。而回收了不該回收的記憶體。
3、注意大圖片的縮放,如果載入的圖片很大,要先經過自己程式的處理,降低解析度等。最好
設定多種解析度格式的圖片,以減少記憶體消耗。
4、動態註冊監聽,把一些只有顯示的時候才使用到的監聽放程序序內部,而不是放在 manifesat
中去。
5、減少使用動畫,或者適當減少動畫的幀數。
6、注意自己的程式邏輯,在該關閉自己程式的控制元件的時候,主動關閉,不要交給系統去決定。
(這個要自己把握好, 也不是說都自己搞定, 只有那些自己確定需要關閉的物件, 自己將其關閉。 )傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
62
10、簡述 android 應用程式結構是哪些?(2016.01.24)
Android應用程式結構也就是講我們的工程結構:傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
63
src目錄是原始碼目錄, 所有允許使用者修改的java檔案和使用者自己新增的java檔案都儲存在這個
目錄中
gen目錄是 1.5版本新增的目錄,用來儲存 ADT自動生成的java檔案,例如 R.java或AIDL 文

注意:R.java 檔案(非常重要)
a) R.java 檔案是 ADT 自動生成的檔案,包含對 drawable、layout和 values目錄內的資源的引
用指標,Android程式能夠直接通過R類引用目錄中的資源
b) R.java 檔案不能手工修改,如果向資源目錄中增加或刪除了資原始檔,則需要在工程名稱上右
擊,選擇Refresh來更新 R.java 檔案中的程式碼
c) R類包含的幾個內部類,分別與資源型別相對應,資源ID 便儲存在這些內部類中,例如子類
drawable 表示影象資源,內部的靜態變數icon表示資源名稱,其資源 ID 為 0x7f020000。一般情
況下,資源名稱與資原始檔名相同
android.jar檔案是Android程式所能引用的函式庫檔案,Android 通過平臺所支援 API 都包含
在這個檔案中
assets 目錄用來存放原始格式的檔案,例如音訊檔案、視訊檔案等二進位制格式檔案。此目錄中的
資源不能被 R.java檔案索引。,所以只能以資截流的形式讀取。一般情況下為空
layout目錄用來存放我們為每個介面寫的佈局檔案
Strings.xml檔案是程式中的一些字串的引用
AndroidManifest.xml是 XML格式的 Android 程式宣告檔案,包含了Android 系統執行
Android 程式前所必須掌握的重要資訊,這些資訊包含應用程式名稱、圖示、包名稱、模組組成、
授權和 SDK最低版本等,而且每個Android 程式必須在根目錄下包含一個AndroidManifest.xml
檔案傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
64
注:AndroidMainfest.xml 檔案:
1) AndroidManifest.xml檔案的根元素是 manifest,包含了 xmlns:android、package、
android:versionCode和 android:versionName共 4 個屬性
2) xmlns:android定義了Android 的名稱空間,值為
http://schemas.android.com/apk/res/android
3) package 定義了應用程式的包名稱
4) android:versionCode定義了應用程式的版本號,是一個整數值,數值越大說明版本越新,
但僅在程式內部使用,並不提供給應用程式的使用者
5) android:versionName 定義了應用程式的版本名稱,是一個字串,僅限於為使用者提供一個
版本標識
6) manifest元素僅能包含一個application元素, application元素中能夠宣告 Android 程式中
最重要的四個組成部分,包括Activity、Service、BroadcastReceiver 和 ContentProvider,所定
義的屬性將影響所有組成部分
7) android:icon 定義了 Android應用程式的圖示,其中@drawable/icon是一種資源引用方
式,表示資源型別是影象,資源名稱為icon,對應的資原始檔為 res/drawable 目錄下的 icon.png
8) android:label 則定義了 Android應用程式的標籤名稱
default.properties檔案記錄 Android 工程的相關設定,該檔案不能手動修改,需右鍵單擊工程
名稱,選擇“Properties”進行修改
11、請解釋下 Android 程式執行時許可權與檔案系統許可權的區別?
(2016.01.24)
apk程式是執行在虛擬機器上的,對應的是 Android 獨特的許可權機制,只有體現到檔案系統上時才傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
65
使用 linux的許可權設定。
(一)linux檔案系統上的許可權
-rwxr-x--x system system 4156 2010-04-30 16:13 test.apk
代表的是相應的使用者/使用者組及其他人對此檔案的訪問許可權,與此檔案執行起來具有的許可權完全
不相關。比如上面的例子只能說明system 使用者擁有對此檔案的讀寫執行許可權;system 組的使用者對
此檔案擁有讀、執行許可權;其他人對此檔案只具有執行許可權。而test.apk 執行起來後可以幹哪些事
情,跟這個就不相關了。千萬不要看apk檔案系統上屬於 system/system 使用者及使用者組,或者
root/root使用者及使用者組,就認為apk 具有 system 或 root許可權
(二)Android的許可權規則
(1)Android中的 apk 必須簽名
(2)基於UserID 的程序級別的安全機制
(3)預設apk 生成的資料對外是不可見的
(4)AndroidManifest.xml 中的顯式許可權宣告
12、Framework 工作方式及原理,Activity 是如何生成一個 view 的,
機制是什麼?(2016.01.24)
所有的框架都是基於反射 和 配置檔案(manifest)的。
普通的情況:
Activity 建立一個 view 是通過 ondraw 畫出來的, 畫這個 view 之前呢,還會呼叫 onmeasure
方法來計算顯示的大小.
特殊情況:
Surfaceview 是直接操作硬體的,因為 或者視訊播放對幀數有要求,onDraw 效率太低,不夠傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
66
使,Surfaceview 直接把資料寫到視訊記憶體。
13、多執行緒間通訊和多程序之間通訊有什麼不同,分別怎麼實現?
(2016.01.24)
一、程序間的通訊方式
# 管道( pipe ):管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的
程序間使用。程序的親緣關係通常是指父子程序關係。
# 有名管道 (namedpipe) : 有名管道也是半雙工的通訊方式,但是它允許無親緣關係程序間的
通訊。
# 訊號量(semophore ) : 訊號量是一個計數器,可以用來控制多個程序對共享資源的訪問。它
常作為一種鎖機制,防止某程序正在訪問共享資源時,其他程序也訪問該資源。因此,主要作為進
程間以及同一程序內不同執行緒之間的同步手段。
# 訊息佇列( messagequeue ) : 訊息佇列是由訊息的連結串列,存放在核心中並由訊息佇列識別符號
標識。訊息佇列克服了訊號傳遞資訊少、管道只能承載無格式位元組流以及緩衝區大小受限等缺點。
# 訊號 (sinal ) : 訊號是一種比較複雜的通訊方式,用於通知接收程序某個事件已經發生。
# 共享記憶體(shared memory ) :共享記憶體就是對映一段能被其他程序所訪問的記憶體,這段共享內
存由一個程序建立,但多個程序都可以訪問。共享記憶體是最快的 IPC 方式,它是針對其他程序間
通訊方式執行效率低而專門設計的。它往往與其他通訊機制,如訊號兩,配合使用,來實現程序間
的同步和通訊。
# 套接字(socket ) : 套解口也是一種程序間通訊機制,與其他通訊機制不同的是,它可用於不同
及其間的程序通訊。
二、執行緒間的通訊方式傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
67
# 鎖機制:包括互斥鎖、條件變數、讀寫鎖
*互斥鎖提供了以排他方式防止資料結構被併發修改的方法。
*讀寫鎖允許多個執行緒同時讀共享資料,而對寫操作是互斥的。
*條件變數可以以原子的方式阻塞程序,直到某個特定條件為真為止。對條件的測試是在互斥鎖
的保護下進行的。條件變數始終與互斥鎖一起使用。
# 訊號量機制(Semaphore):包括無名執行緒訊號量和命名執行緒訊號量
# 訊號機制(Signal):類似程序間的訊號處理
執行緒間的通訊目的主要是用於執行緒同步,所以執行緒沒有像程序通訊中的用於資料交換的通訊機
制。
二、 Android螢幕適配
1、螢幕適配方式都有哪些
1.1 適配方式之dp
名詞解釋:
解析度:eg:480*800,1280*720。表示物理螢幕區域內畫素點的總和。(切記:跟螢幕適配沒有
任何關係)
因為我們既可以把 1280*720 的解析度做到 4.0 的手機上面。我也可以把 1280*720 的解析度做
到 5.0英寸的手機上面,如果解析度相同,手機螢幕越小清晰。
px(pix):畫素,就是螢幕中最小的一個顯示單元
dpi(畫素密度):即每英寸螢幕所擁有的畫素數,畫素密度越大,顯示畫面細節就越豐富。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
68
計算公式:畫素密度=√{(長度畫素數^2+寬度畫素數^2)}/ 螢幕尺寸
注:螢幕尺寸單位為英寸 例:解析度為 1280*720 螢幕寬度為 6 英寸 計算所得畫素密度約等
於 245,螢幕尺寸指螢幕對角線的長度。
在 Android手機中 dpi 分類:
ldpi Resources for low-density (ldpi) screens (~120dpi).
mdpi Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)
hdpi Resources for high-density (hdpi) screens (~240dpi).
xhdpi Resources for extra high-density (xhdpi) screens (~320dpi).
在我們的Android工程目錄中有如下 drawable-*dpi目錄, 這些目錄是用來適配不同解析度手機的。
Android 應用在查詢圖片資源時會根據其解析度自動從不同的檔案目錄下查詢(這本身就是
Android 系統的適配策略),如果在低分辨的檔案目錄中比如 drawable-mdpi 中沒有圖片資源,其
他目錄中都有,當我們將該應用部署到 mdpi解析度的手機上時,那麼該應用會查詢解析度較高目錄
下的資原始檔,如果較高解析度目錄下也沒有資源則只好找較低目錄中的資源了。
常見手機螢幕畫素及對應分別率級別:
ldpi 320*240傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
69
mdpi 480*320
hdpi 800*480
xhdpi 1280*720
xxhdpi 1920*1080
dp和 px 之間的簡單換算關係:
ldpi的手機 1dp=0.75px
mdpi的手機 1dp=1.0px
hdpi的手機 1dp=1.5px
xhdpi的手機 1dp=2.0px
xxhdpi的手機 1dp=3.0px
:根據上面的描述我們得出如下結論,對於 mdpi 的手機,我們的佈局通過 dp 單位可以達到適
配效果。
1.2 適配方式之dimens傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
70
跟 drawable 目錄類似的,在 Android 工程的res目錄下有values目錄,這個是預設的目錄,同時
為了適配不同尺寸手機我們可以建立一個 values-1280x720 的資料夾,同時將 dimens.xml 檔案拷
貝到該目錄下。
在 dimens.xml中定義一個尺寸,如下圖所示。
在 values-1280x720 目錄中的 dimens.xml中定義同樣的尺寸名稱,但是使用不同的尺寸,如下圖
所示。
當我們在佈局檔案中使用長或者寬度單位時,比如下圖所示,應該使用@dimen/width 來靈活的定
義寬度。
:在 values-1280x720 中,中間的是大寫字母 X 的小寫形式 x,而不是加減乘除的乘號。如果
我們在 values-1280x720 中放置了dimens常量, 一定記得也將該常量的對應值在 values目錄下的
dimens.xml中放一份,因為該檔案是預設配置,當用戶的手機不是1280*720 的情況下系統應用使
用的是預設 values目錄中的dimens.xml。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
71
1.3 適配方式之layout
跟 values 一樣,在 Android 工程目錄中 layout 目錄也支援類似 values 目錄一樣的適配,在
layout中我們可以針對不同手機的解析度制定不同的佈局,如下圖所示。
1.4 適配方式之java 程式碼適配
為了演示用 java程式碼控制適配的效果,因此假設有這樣的需求,讓一個 TextView 控制元件的寬和高
分別為螢幕的寬和高的一半。
我們新建立一個Android 工程,修改main_activity.xml,佈局檔案清單如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<!-- 當前控制元件寬高為螢幕寬度的各50% -->
<TextView
android:id="@+id/tv"
android:background="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
在 MainActivity.java類中完成用 java程式碼控制 TextView 的佈局效果,其程式碼清單如下:傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
72
public class MainActivity extends Activity {
private static final String tag = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//去掉 title
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
//獲取 TextView 控制元件
TextView tv = (TextView) findViewById(R.id.tv);
//找到當前控制元件的夫控制元件(父控制元件上給當前的子控制元件去設定一個規則)
DisplayMetrics metrics = new DisplayMetrics();
//給當前 metrics 去設定當前螢幕資訊(寬(畫素)高(畫素))
getWindowManager().getDefaultDisplay().getMetrics(metrics);
//獲取螢幕的高度和寬度
Constant.srceenHeight = metrics.heightPixels;
Constant.srceenWidth = metrics.widthPixels;
//日誌輸出螢幕的高度和寬度
Log.i(tag, "Constant.srceenHeight = "+Constant.srceenHeight);
Log.i(tag, "Constant.srceenWidth = "+Constant.srceenWidth);
//寬高各 50%
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
//數學角度上 四捨五入
(int)(Constant.srceenWidth*0.5+0.5),
(int)(Constant.srceenHeight*0.5+0.5));
//給 tv 控制元件設定佈局引數
tv.setLayoutParams(layoutParams);
}
}
其中 Constant類是一個常量類,很簡單,只有兩個常量用來記錄螢幕的寬和高,其程式碼清單如下:
public class Constant {
public static int srceenHeight;
public static int srceenWidth;
}
1.5適配方式之weight 權重適配傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
73
在控制元件中使用屬性android:layout_weight="1"可以起到適配效果,但是該屬性的使用有如下規則:
只能用線上性控制元件中,比如LinearLayout。
豎直方向上使用權重的控制元件高度必須為0dp(Google官方的推薦用法)
水平方向上使用權重的控制元件寬度必須為0dp(Google官方的推薦用法)
2、螢幕適配的處理技巧都有哪些
手機自適應主要分為兩種情況:橫屏和豎屏的切換,以及解析度大小的不同。
2.1橫屏和豎屏的切換
1、Android 應用程式支援橫豎螢幕的切換,Android 中每次螢幕的切換動會重啟 Activity,所
以應該在Activity銷燬 (執行onPause()方法和onDestroy()方法) 前儲存當前活動的狀態; 在Activity
再次建立的時候載入配置, 那樣, 進行中的遊戲就不會自動重啟了! 有的程式適合從豎屏切換到橫屏,
或 者 反 過 來 , 這 個 時 候 怎 麼 辦 呢 ? 可 以 在 配 置 Activity 的 地 方 進 行 如 下 的 配 置
android:screenOrientation="portrait"(landscape 是橫向,portrait 是縱向)。這樣就可以保證
是豎屏總是豎屏了。
2、而有的程式是適合橫豎屏切換的。如何處理呢?首先要在配置 Activity 的時候進行如下的配
置:
android:configChanges="keyboardHidden|orientation" , 另 外 需 要 重 寫 Activity 的
onConfigurationChanged 方法。實現方式如下:傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
74
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
if(this.getResources().getConfiguration().orientation==Configuration.ORIENTATION_
LANDSCAPE){
//TODO
}else
if(this.getResources().getConfiguration().orientation==Configuration.ORIENTATION_
PORTRAIT){
//TODO
}
}
2.2解析度大小不同
對於解析度問題,官方給的解決辦法是建立不同的 layout 資料夾,這就需要對每種解析度的手
機都要寫一個佈局檔案,雖然看似解決了解析度的問題,但是如果其中一處或多處有修改了,就要每
個佈局檔案都要做出修改,這樣就造成很大的麻煩。那麼可以通過以下幾種方式解決:
一)使用layout_weight
目前最為推薦的Android 多螢幕自適應解決方案。
該屬性的作用是決定控制元件在其父佈局中的顯示權重,一般用於線性佈局中。其值越小,則對
應的 layout_width或 layout_height的優先順序就越高(一般到100 作用就不太明顯了);一般橫向
佈局中,決定的是layout_width的優先順序;縱向佈局中,決定的是 layout_height的優先順序。
傳統的 layout_weight 使用方法是將當前控制元件的 layout_width 和 layout_height 都設定成
fill_parent,這樣就可以把控制元件的顯示比例完全交給 layout_weight;這樣使用的話,就出現了
layout_weight越小,顯示比例越大的情況(即權重越大,顯示所佔的效果越小)。不過對於 2 個控
件還好,如果控制元件過多,且顯示比例也不相同的時候,控制起來就比較麻煩了,畢竟反比不是那麼好
確定的。 於是就有了現在最為流行的 0px設值法。 看似讓人難以理解的 layout_height=0px的寫法,
結合 layout_weight,卻可以使控制元件成正比例顯示,輕鬆解決了當前 Android 開發最為頭疼的碎片傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
75
化問題之一。
二)清單檔案配置:【不建議使用這種方式,需要對不同的介面寫不同的佈局】
需要在AndroidManifest.xml檔案的<manifest>元素如下新增子元素
<supports-screensandroid:largeScreens="true"
android:normalScreens="true"
android:anyDensity="true"
android:smallScreens="true"
android:xlargeScreens="true">
</supports-screens>
以上是為我們的螢幕設定多解析度支援(更準確的說是適配大、中、小三種密度)。
Android:anyDensity="true",這一句對整個的螢幕都起著十分重要的作用,值為 true,我們的
應用程式當安裝在不同密度的手機上時,程式會分別載入 hdpi,mdpi,ldpi資料夾中的資源。相反,
如果值設定為false,即使我們在hdpi,mdpi,ldpi,xdpi資料夾下擁有同一種資源,那麼應用也不會
自動地去相應資料夾下尋找資源。而是會在大密度和小密度手機上載入中密度mdpi檔案中的資源。
有時候會根據需要在程式碼中動態地設定某個值, 可以在程式碼中為這幾種密度分別設定偏移量,但是
這種方法最好不要使用,最好的方式是在 xml 檔案中不同密度的手機進行分別設定。這裡地圖的偏
移量可以在 values-xpdi, values-hpdi,values-mdpi,values-ldpi 四種資料夾中的 dimens.xml 檔案
進行設定。
三)、其他:
說明:
在不同解析度的手機模擬器下,控制元件顯示的位置會稍有不同
通過在 layout中定義的佈局設定的引數,使用 dp(dip),會根據不同的螢幕解析度進行適傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
76

但是在程式碼中的各個引數值,都是使用的畫素(px)為單位的
技巧:
1、儘量使用線性佈局,相對佈局,如果螢幕放不下了,可以使用ScrollView(可以上下拖動)
ScrowView使用的注意:
在不同的螢幕上顯示內容不同的情況,其實這個問題我們往往是用滾動檢視來解決的,也就是
ScrowView; 需要注意的是 ScrowView 中使用 layout_weight是無效的, 既然使用ScrowView 了,
就把它裡面的控制元件的大小都設成固定的吧。
2、指定寬高的時候,採用dip 的單位,dp 單位動態匹配
3、由於android 程式碼中寫的單位都是畫素,所有需要通過工具類進行轉化
4、儘量使用 9-patch 圖,可以自動的依據圖片上面顯示的內容被拉伸和收縮。其中在編輯的時
候,灰色區域是被拉伸的,上下兩個點控制水平方向的拉伸,左右兩點控制垂直方向的拉伸
3、dp 和px之間的關係
dp:是 dip 的簡寫,指密度無關的畫素。
指一個抽象意義上的畫素,程式用它來定義介面元素。一個與密度無關的,在邏輯尺寸上,
與一個位於畫素密度為160dpi 的螢幕上的畫素是一致的。要把密度無關畫素轉換為螢幕畫素,可以
用這樣一個簡單的公式:pixels=dips*(density/160)。舉個例子,在 DPI 為 240 的螢幕上,1 個 DIP
等於 1.5個物理畫素。
佈局時最好使用dp 來定義我們程式的介面, 因為這樣可以保證我們的UI在各種解析度的螢幕上
都可以正常顯示。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
77
/**
* 根據手機的解析度從 px(畫素) 的單位 轉成為 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 根據手機的解析度從 dip 的單位 轉成為 px(畫素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
三、AIDL
1、什麼是 AIDL 以及如何使用
①aidl是 Android interface definition Language 的英文縮寫,意思 Android 介面定義語言。
②使用 aidl可以幫助我們釋出以及呼叫遠端服務,實現跨程序通訊。
③將服務的 aidl放到對應的src目錄,工程的gen 目錄會生成相應的介面類
我們通過 bindService(Intent,ServiceConnect,int)方法繫結遠端服務,在 bindService
中 有 一 個 ServiceConnec 接 口 , 我 們 需 要 覆 寫 該 類 的
onServiceConnected(ComponentName,IBinder)方法,這個方法的第二個引數 IBinder物件其實
就是已經在 aidl中定義的介面,因此我們可以將IBinder物件強制轉換為 aidl中的介面類。
我們通過IBinder獲取到的物件(也就是 aidl檔案生成的介面)其實是系統產生的代理物件,該
代理物件既可以跟我們的程序通訊, 又可以跟遠端程序通訊, 作為一箇中間的角色實現了程序間通訊。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
78
2、AIDL 的全稱是什麼?如何工作?能處理哪些型別的資料?
AIDL 全稱 Android Interface Definition Language(AndRoid 介面描述語言) 是一種介面描述
語言; 編譯器可以通過aidl 檔案生成一段程式碼,通過預先定義的介面達到兩個程序內部通訊程序跨界
物件訪問的目的。需要完成2件事情: 1. 引入 AIDL 的相關類.; 2. 呼叫 aidl 產生的 class.理論上, 參
數可以傳遞基本資料型別和String, 還有就是Bundle的派生類, 不過在Eclipse中,目前的ADT不支
持 Bundle做為引數。
四、Android中的事件處理
1、Handler 機制
Android 中主執行緒也叫UI執行緒,那麼從名字上我們也知道主執行緒主要是用來建立、更新 UI的,
而其他耗時操作,比如網路訪問,或者檔案處理,多媒體處理等都需要在子執行緒中操作,之所以在子
執行緒中操作是為了保證UI 的流暢程度,手機顯示的重新整理頻率是60Hz,也就是一秒鐘重新整理 60 次,每
16.67 毫秒重新整理一次,為了不丟幀,那麼主執行緒處理程式碼最好不要超過 16 毫秒。當子執行緒處理完數
據後,為了防止 UI 處理邏輯的混亂,Android 只允許主執行緒修改 UI,那麼這時候就需要 Handler
來充當子執行緒和主執行緒之間的橋樑了。
我們通常將 Handler宣告在Activity 中,然後覆寫 Handler中的 handleMessage 方法,當子線
程呼叫 handler.sendMessage()方法後 handleMessage 方法就會在主執行緒中執行。
這裡面除了 Handler、Message外還有隱藏的Looper和 MessageQueue物件。
在主執行緒中Android 預設已經呼叫了 Looper.preper()方法,呼叫該方法的目的是在 Looper中
建立 MessageQueue 成員變數並把 Looper 物件繫結到當前執行緒中。當呼叫 Handler 的傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
79
sendMessage(物件)方法的時候就將 Message 物件新增到了 Looper 建立的 MessageQueue
佇列中,同時給 Message 指定了 target物件,其實這個target物件就是Handler物件。主執行緒默
認執行了Looper.looper () 方法, 該方法從Looper的成員變數 MessageQueue 中取出 Message,
然後呼叫Message 的 target物件的 handleMessage()方法。這樣就完成了整個訊息機制。
2、事件分發機制
2.1 事件分發中的onTouch和onTouchEvent有什麼區別,又該如何使用?
這兩個方法都是在 View 的 dispatchTouchEvent 中呼叫的,onTouch 優先於 onTouchEvent
執行。如果在onTouch方法中通過返回 true 將事件消費掉,onTouchEvent將不會再執行。
另外需要注意的是,onTouch 能夠得到執行需要兩個前提條件,第一 mOnTouchListener的值
不能為空,第二當前點選的控制元件必須是 enable 的。因此如果你有一個控制元件是非 enable 的,那麼給
它註冊 onTouch事件將永遠得不到執行。對於這一類控制元件,如果我們想要監聽它的touch 事件,就
必須通過在該控制元件中重寫onTouchEvent方法來實現。
2.2 請描述一下Android的事件分發機制
Android 的事件分發機制主要是 Touch 事件分發,有兩個主角:ViewGroup 和 View。Activity
的 Touch事件事實上是呼叫它內部的ViewGroup的 Touch事件,可以直接當成 ViewGroup處理。
View在ViewGroup內, ViewGroup也可以在其他ViewGroup內, 這時候把內部的ViewGroup
當成 View 來分析。
先分析ViewGroup的處理流程:首先得有個結構模型概念:ViewGroup 和 View 組成了一棵樹
形結構,最頂層為 Activity 的 ViewGroup,下面有若干的 ViewGroup 節點,每個節點之下又有若
乾的 ViewGroup節點或者 View 節點,依次類推。如圖:傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
80
當一個Touch 事件(觸控事件為例)到達根節點,即 Acitivty 的 ViewGroup時,它會依次下發,
下發的過程是呼叫子 View(ViewGroup)的 dispatchTouchEvent 方法實現的。簡單來說,就是
ViewGroup遍歷它包含著的子 View,呼叫每個 View 的 dispatchTouchEvent方法,而當子 View
為 ViewGroup 時,又會通過呼叫 ViwGroup的 dispatchTouchEvent方法繼續呼叫其內部的 View
的 dispatchTouchEvent 方法。上述例子中的訊息下發順序是這樣的:①-②-⑤-⑥-⑦-③-④。
dispatchTouchEvent方法只負責事件的分發,它擁有 boolean 型別的返回值,當返回為 true 時,
順序下發會中斷。在上述例子中如果⑤的 dispatchTouchEvent返回結果為 true,那麼⑥-⑦-③-④
將都接收不到本次Touch事件。
1.Touch 事 件 分 發 中 只 有 兩 個 主 角 :ViewGroup 和 View 。 ViewGroup 包 含
onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent 三個相關事件。View 包含
dispatchTouchEvent、onTouchEvent兩個相關事件。其中 ViewGroup又繼承於 View。
2.ViewGroup和 View 組成了一個樹狀結構,根節點為Activity 內部包含的一個ViwGroup。
3.觸控事件由 Action_Down、Action_Move、Aciton_UP 組成,其中一次完整的觸控事件中,
Down和 Up 都只有一個,Move有若干個,可以為 0 個。
4.當 Acitivty 接收到Touch 事件時,將遍歷子 View 進行 Down 事件的分發。ViewGroup 的遍
歷可以看成是遞迴的。分發的目的是為了找到真正要處理本次完整觸控事件的 View,這個 View 會傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
81
在 onTouchuEvent結果返回 true。
5.當某個子View返回true時, 會中止Down事件的分發, 同時在ViewGroup中記錄該子View。
接下去的Move和 Up 事件將由該子 View 直接進行處理。 由於子 View 是儲存在 ViewGroup 中的,
多層 ViewGroup 的節點結構時,上級 ViewGroup 儲存的會是真實處理事件的 View 所在的
ViewGroup物件:如 ViewGroup0-ViewGroup1-TextView 的結構中,TextView 返回了 true,它將
被儲存在 ViewGroup1 中,而 ViewGroup1 也會返回 true,被儲存在 ViewGroup0 中。當 Move
和 UP事件來時,會先從 ViewGroup0傳遞至 ViewGroup1,再由 ViewGroup1傳遞至 TextView。
6.當 ViewGroup 中所有子 View 都不捕獲 Down事件時,將觸發 ViewGroup 自身的 onTouch
事件。觸發的方式是呼叫 super.dispatchTouchEvent 函式,即父類 View 的 dispatchTouchEvent
方法。在所有子View 都不處理的情況下,觸發Acitivity 的 onTouchEvent方法。
7.onInterceptTouchEvent有兩個作用:1.攔截 Down 事件的分發。2.中止 Up 和 Move 事件向
目標 View 傳遞,使得目標 View 所在的 ViewGroup 捕獲 Up和 Move事件。
3、子執行緒發訊息到主執行緒進行更新 UI,除了 handler 和 AsyncTask,
還有什麼?
1、用Activity 物件的 runOnUiThread 方法更新
在子執行緒中通過runOnUiThread()方法更新UI:傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
82
如果在非上下文類中(Activity),可以通過傳遞上下文實現呼叫;
2、用View.post(Runnable r)方法更新UI
4、子執行緒中能不能new handler?為什麼?
不能,如果在子執行緒中直接 new Handler()會丟擲異常 java.lang.RuntimeException: Can't
create handler inside thread that has not called傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
83
在沒有呼叫 Looper.prepare()的時候不能建立 Handler,因為在建立 Handler 的原始碼中做了
如下操作
Handler的構造方法中
public static Looper myLooper() {
return sThreadLocal.get();
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
五、Android中的動畫
1、Android中的動畫有哪幾類,它們的特點和區別是什麼
Android 中動畫分為兩種,一種是Tween 動畫、還有一種是 Frame 動畫。
Tween動畫,這種實現方式可以使檢視元件移動、放大、縮小以及產生透明度的變化;
Frame 動畫,傳統的動畫方法,通過順序的播放排列好的圖片來實現,類似電影。
2、如何修改Activity進入和退出動畫
可 以 通 過 兩 種 方 式 , 一 是 通 過 定 義 Activity 的 主 題 , 二 是 通 過 覆 寫 Activity 的傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
84
overridePendingTransition方法。
通過設定主題樣式
在styles.xml中編輯如下程式碼:
<style name="AnimationActivity" parent="@android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">@anim/slide_in_left</item>
<item name="android:activityOpenExitAnimation">@anim/slide_out_left</item>
<item name="android:activityCloseEnterAnimation">@anim/slide_in_right</item>
<item name="android:activityCloseExitAnimation">@anim/slide_out_right</item>
</style>
新增themes.xml檔案:
<style name="ThemeActivity">
<item name="android:windowAnimationStyle">@style/AnimationActivity</item>
<item name="android:windowNoTitle">true</item>
</style>
在AndroidManifest.xml中給指定的 Activity 指定 theme。
覆寫 overridePendingTransition方法
overridePendingTransition(R.anim.fade, R.anim.hold);
3、屬性動畫,例如一個 button從A 移動到B 點,B 點還是可以響應點
擊事件,這個原理是什麼?
補間動畫只是顯示的位置變動,View 的實際位置未改變,表現為 View 移動到其他地方,點選事
件仍在原處才能響應。而屬性動畫控制元件移動後事件相應就在控制元件移動後本身進行處理傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
85
六、ContentObserver 內容觀察者作用及特點
一、 ContentObserver 目的是觀察(捕捉)特定 Uri引起的資料庫的變化, 繼而做一些相應的處理。
它類似於資料庫技術中的觸發器(Trigger),當 ContentObserver 所觀察的 Uri 發生變化時,便
會 觸發 它 。 觸發 器 分為 表 觸發 器 、 行觸 發 器, 相 應地 ContentObserver 也 分為 “表
“ContentObserver、“行”ContentObserver,當然這是與它所監聽的 Uri MIME Type 有關的。
1) 註冊ContentObserver 方法
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer)
功能:為指定的 Uri 註冊一個 ContentObserver 派生類例項,當給定的 Uri 發生改變時,回撥
該例項物件去處理。
引數: uri 表示需要觀察的 Uri
notifyForDescendents 為 false 表示精確匹配,即只匹配該 Uri。 為 true 表示可以同時匹配
其派生的Uri。
取消註冊ContentObserver 方法
public final void unregisterContentObserver(ContentObserver observer)
功能:取消對給定Uri的觀察
引數: observer ContentObserver的派生類例項
ContentObserver 類介紹
構造方法 ContentObserver(Handler h)
void onChange(boolean selfChange) 功能:當觀察到的 Uri 發生變化時,回撥該方法去處理。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
86
所有 ContentObserver 的派生類都需要過載該方法去處理邏輯。
3.觀察特定 Uri 的步驟如下:
1、建立我們特定的ContentObserver 派生類,必須過載父類構造方法,必須過載 onChange()
方法去處理回撥後的功能實現
2 、 利 用 context.getContentResolover() 獲 ContentResolover 對 象 , 接 著 調 用
registerContentObserver()方法去註冊內容觀察者
3、在不需要時,需要手動的呼叫 unregisterContentObserver()去取消註冊。
例子:監聽簡訊內容變化
在 Activity 中:
public class Day0108_contentobserverActivity extends Activity {
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 100:
String body = (String) msg.obj;
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(body);
break;
}
}
};傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
87
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ContentResolver cr = getContentResolver();
ContentObserver smsObserver = new
SmsContentObserver(this,handler);
//第二個引數,true表示觀察所有有關簡訊的
cr.registerContentObserver(Uri.parse("content://sms"),
true, smsObserver);
//content://sms/inbox //收件箱
//content://sms/sent //已傳送
//content://sms/draft //草稿箱
//content://sms/outbox //發件箱
//content://sms/failed //失敗簡訊
//content://sms/queued //代發佇列
}
}
//SmsContentObserver程式碼如下:
public class SmsContentObserver extends ContentObserver {
private Handler handler;
private Context context;傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
88
public SmsContentObserver(Context context,Handler
handler) {
super(handler);
this.handler = handler;
this.context = context;
}
@Override
public void onChange(boolean selfChange) {
ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(Uri.parse("content://sms/inbox"),
null, "0", null, "date desc");
StringBuilder sb = new StringBuilder();
while(c.moveToNext()){
//發件人手機號碼
String sendNumber = c.getString(
c.getColumnIndex("address"));
//資訊內容
String body =
c.getString(c.getColumnIndex("body"));
//readType 表示是否已經讀
int hasRead = c.getInt(c.getColumnIndex("read"));傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
89
if(hasRead == 0){//表示簡訊未讀
System.out.println("簡訊未讀"+sendNumber);
}
sb.append(sendNumber+":"+body+"\n");
}
handler.obtainMessage(100,sb.toString()).sendToTarget();
}
}
專案框架的使用(★★★)
一、 自我介紹
從姓名,工作多長時間,及專案開發的週期來說。
(1)姓名
(2)工作時間
(3)開發週期
例如, 你好,我是 XXX,到現在為止我工作了一年半,期間有做過三款 app。最近的一個專案開
發了兩個月。(這時候可以把你準備好的手機裡的app 開啟給面試官看)傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
90
二、 開發中都使用過哪些框架、平臺
1.EventBus(事件處理)
2.xUtils(網路、圖片、ORM)
xUtils 分為四大模組:
1 DbUtils模組:Android中的orm框架(物件關係對映,它的作用是在關係型
資料庫和業務實體物件之間作為一個對映),一行程式碼就可以進行增刪改查。(Logo
新聞內容快取到資料庫 當沒有網路的時候)
2 ViewUtils模組:android中的ioc框架(生命週期由框架控制),完全註解的方
式就可以進行對UI繫結和事件的繫結。
3 HttpUtils模組:(請求伺服器 客戶端 傳過去標示 head=”md5”)
a. 支援同步,非同步方式的請求。
b. 支援大檔案上傳,上傳大檔案不會oom(記憶體溢位)。
c. 支援 GET,POST,DELETE 請求。
4 BitmapUtil模組:
可以先說下三級快取的原理:
1. 從快取中載入。
2. 從本地檔案中載入(資料庫,SD)
3. 從網路載入。
a.載入bitmap的時候無需考慮bitmap載入過程中出現的oom(記憶體溢位)和android容器快速傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
91
滑動的時候出現的圖片錯位等現象。(16M)
b. 支援載入網路圖片和本地圖片。
c. 記憶體管理使用的 lru演算法(移除裡面是有頻率最少的物件),更好的管理bitmap 的記憶體。
d.可配置執行緒載入的數量,快取的大小,快取的路徑,載入顯示的動畫等。
清除快取是怎麼做的?
(1)清除記憶體的快取。
(2)資料庫,SD。
注:需要新增一下許可權<uses-permission android:name="android.permission.INTERNET" /> <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
3.JPush(推送平臺)
推送的好處:
a. 及時主動性。(這是推送服務最基本的特點,即當有新的資訊需要提交時,依據傳送資訊的型別
和重要性不同,推送軟體會主動提醒使用者接收新資訊。從而提高了使用者獲取資訊的及時性。)
b. 針對目的性。(推送服務提供的資訊是根據使用者的特定需求定的,這充分體現了使用者的個性化需
求。這種個性化的服務還是動態的,使用者只需在定製之初描述資訊需求,推送軟體就會自動跟蹤
使用者的使用傾向,實時地完成特定資訊的推送。)
c. 便捷高效性。(使用者只需輸入一次資訊請求,就可獲得連續的資訊服務。推送服務還採用資訊代
理機制,可以自動跟蹤使用者的資訊需求。這樣的推送服務既節省了使用者主動拉取的時間,又減少
了冗餘資訊的傳遞提高了資訊的匹配度,從而大大方便了使用者,提高了效率。)
我們在專案中主要使用的是極光推送, 在極光的官網裡 (https://www.jpush.cn/) 下載 android傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
92
的 demo,將 demo中的 aapid 換成自己申請的,測試推送,然後整合到自己的專案中去。
4.友盟(統計平臺)
5.有米(優米)(廣告平臺)
6.百度地圖
1) 下載百度地圖移動版API(Android)開發包
要在 Android 應用中使用百度地圖API,就需要在工程中引用百度地圖API 開發包,這個開發包包
含兩個檔案:baidumapapi.jar和 libBMapApiEngine.so。下載地址:
http://dev.baidu.com/wiki/static/imap/files/BaiduMapApi_Lib_Android_1.0.zip
2) 申請API Key
和使用 Google map api 一樣,在使用百度地圖 API 之前也需要獲取相應的 API Key。百度地圖 API
Key 與你的百度賬戶相關聯,因此您必須先有百度帳戶,才能獲得 API Key;並且,該 Key 與您引用
API 的程式名稱有關。
百度 API Key 的申請要比 Google的簡單多了,其實只要你有百度帳號,應該不超過 30秒就能完成
API Key 的申請。申請地址:http://dev.baidu.com/wiki/static/imap/key/
3) 建立一個Android工程
這裡需要強調一點:百度地圖移動版api 支援 Android 1.5 及以上系統,因此我們建立的工程應
基於 Android SDK 1.5 及以上。
工程建立完成後,將 baidumapapi.jar 和 libBMapApiEngine.so 分別拷貝到工程的根目錄及
libs/armeabi 目錄下,並在工程屬性->Java Build Path->Libraries 中選擇“Add JARs”,選
定 baidumapapi.jar,這樣就可以在應用中使用百度地圖API 了。傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
93
7.bmob(伺服器平臺、簡訊驗證、郵箱驗證、第三方支付)
8.阿里雲OSS(雲端儲存)
9.ShareSDK(分享平臺、第三方登入)
SDK 簡介: ShareSDK 是為 iOS 的 APP 提供社會化功能的一個元件,開發者只需 10 分鐘
即可整合到自己的APP 中,它不僅支援如 QQ、微信、新浪微博、騰訊微博、開心網、人人網、
豆瓣、網易微博、搜狐微博、facebook、twitter、google+等國內外主流社交平臺,還有強大
的統計分析管理後臺,可以實時瞭解使用者、資訊流、迴流率、傳播效應等資料,有效的指導日常
運營與推廣,同時為APP引入更多的社會化流量。
主要功能:
a. 支援分享到主流的各大平臺上。 (國內主要的分享平臺: QQ ,微信 , 新浪微博 , 騰訊微博 國
外的:facebook twitter google+)
b. 支援獲取授權使用者資料及其他使用者資料,可以通過sdk 製作使用新浪微博登入,QQ 登入等。
c. 支援關注官方微博,支援@好友,插入話題,圖片。
d. 支援一鍵分享,使用者可以一次性將內容分享至全部的社交平臺。
使用:
(1)獲取SharedSDK。(SharedSDK官網:http://wiki.mob.com/)
(2)將SharedSDK 整合(匯入)到專案的libs目錄下。
(3)配置AndroidManifest.xml 許可權
1
2
3
4
5
6
7
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
94
8
9
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
(4)新增程式碼,啟動SDK。SMSSDK.initSDK(this, "<您的 appkey>", "<您的 appsecret>");
10.Gson(解析json資料框架)
根據伺服器返回的Gson 資料來設計類的模型,讓 Gson 解析字串為對應的物件模型。簡
單來講就是 根據 json的資料結構定義出相應的 javabean --->"new"出 Gson 的例項
gson---->gson.fromJson( jsonString,JavaBean.class) 即可.
面試概要:
可以先說下 Gson 的作用,然後在向後拓展下。(Gson 呢,是 google 提供的一個快速解析 json
資料的開源框架,原來我們解析資料的時候都是jsonObject jsonArray 一層層解析, 我發現這樣層層
解析很浪費時間,於是我在業餘時間研究了 Gson,Gson 滿足了我們快速開發的特性,只要從服務
器拿到 json資料用 Gson 解析,Gson 就會返回一個數據物件,我們就可以直接對資料進行操作了。
原來解析可能需要十幾分鐘的事,現在兩三分鐘就搞定了)
補充:為什麼資料要以json形式傳輸?
1 易讀性
2 高效率
11.imageLoader (圖片處理框架)
12.zxing (二維碼掃描)傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
95
三、 都使用過哪些自定義控制元件
1.pull2RefreshListView
2.LazyViewPager
3.SlidingMenu
4.SmoothProgressBar
5.自定義組合控制元件
6.ToggleButton
7.自定義吐司(Toast)
四、 自定義控制元件:繪製圓環的實現過程
使用自定義控制元件繪製一個圓環,需要重現的方法是OnDraw()實現對view 的繪製, 從而
輸出符合自己需求的view 控制元件
觀察圓環的組成部分:
外層圓+中間百分比文字+不斷變化進度的弧形圈
--->分析:每一個組成部分需要的屬性,構成幾個關鍵的自定義屬性
1:外層圓的顏色
2:弧形進度圈的顏色
3:中間百分比文字的顏色
4:中間百分比文字的大小
5:圓環的寬度(作為進度弧形圈的寬度)傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
96
6:*首頁當中也有一個圓環進度,為了相容使用首頁的圓環進度,增加一個自
定義屬性,繪製進度弧形圈的風格(實心[Fill],空心[Stroken])
分析完畢-->繪製步驟:
1:構造方法當中初始化畫筆物件,獲取自定義的屬性值.
2:重寫Ondraw方法
---2.1:繪製最外層的圓
-關鍵方法canvas.drawCircle(center, center, radius, paint); //畫出圓環
*:計算半徑、中心點座標、畫筆設定
paint.setColor(roundColor); //設定圓環的顏色
paint.setStyle(Paint.Style.STROKE); //設定空心
paint.setStrokeWidth(roundWidth); //設定圓環的寬度---這個寬度也是提
供給進度弧形圈繪製的時候覆蓋的寬度
paint.setAntiAlias(true); //消除鋸齒
中心點座標
int center = getWidth() / 2; //獲取圓心的x座標
半徑:傳智播客武漢校區就業部出品 務實、創新、質量、分享、專注、責任
97
int radius = (int) (center - roundWidth/2) ---畫圖說明最容易理解
---2.2:繪製中間的百分比文字
--關鍵方法:canvas.drawText(percent + "%", center - textWidth / 2,
center + textSize / 2, paint); //畫出進度百分比
測量畫筆上的文字寬度
float textWidth = paint.measureText(percent + "%");
畫筆設定
paint.setStrokeWidth(0);
paint.setColor(textColor);
paint.setTextSize(textSize);
paint.setTypeface(Typeface.DEFAULT_BOLD); //設定字型
繪製的文字的位置,由引數2,3 的X,Y 座標值決定--圓環的中心點位置顯示
X:表示從哪開始繪製,如果你直接中心點開始繪製-->畫圖說明最容易理解
-->正確的 X=center - textWidth / 2;Y = center + textSize / 2 --(因為
android座標系與數學座標系Y 軸值是相反的,也可以畫圖說明,這裡的textsize就可
以代表高度,paint.measureText