1 如何導入外部數據庫
把原數據庫包括在項目源碼的 res/raw
android系統下數據庫應該存放在 /data/data/com..(package name)/ 目錄下,所以我們需要做的是把已有的數據庫傳入那個目錄下.操作方法是用FileInputStream讀取原數據庫,再用FileOutputStream把讀取到的東西寫入到那個目錄.
2 本地廣播和全局廣播有什么差別
因廣播數據在本應用范圍內傳播,不用擔心隱私數據泄露的問題。 不用擔心別的應用偽造廣播,造成安全隱患。 相比在系統內發送全局廣播,它更高效。
3 LaunchMode應用場景
standard,創建一個新的Activity。
singleTop,棧頂不是該類型的Activity,創建一個新的Activity。否則,onNewIntent。
singleTask,回退棧中沒有該類型的Activity,創建Activity,否則,onNewIntent+ClearTop。
singleInstance,回退棧中,只有這一個Activity,沒有其他Activity。
singleTop適合接收通知啟動的內容顯示頁面。
例如,某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都打開一個新聞內容頁面是很煩人的。
singleTask適合作為程序入口點。
例如瀏覽器的主界面。不管從多少個應用啟動瀏覽器,只會啟動主界面一次,其余情況都會走onNewIntent,并且會清空主界面上面的其他頁面。
singleInstance應用場景:
鬧鈴的響鈴界面。 你以前設置了一個鬧鈴:上午6點。在上午5點58分,你啟動了鬧鈴設置界面,并按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,并且彈出了一個對話框形式的 Activity(名為 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以 SingleInstance 加載模式打開的),你按返回鍵,回到的是微信的聊天界面,這是因為 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之后這個 Task 的棧空了。如果是以 SingleTask 打開 AlarmAlertActivity,那么當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設置界面。
4 Android事件傳遞流程:
事件都是從Activity.dispatchTouchEvent()開始傳遞
事件由父View傳遞給子View,ViewGroup可以通過onInterceptTouchEvent()方法對事件攔截,停止其向子view傳遞
如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費事件,事件會反向往上傳遞,這時父View(ViewGroup)可以進行消費,如果還是沒有被消費的話,最后會到Activity的onTouchEvent()函數。
如果View沒有對ACTION_DOWN進行消費,之后的其他事件不會傳遞過來,也就是說ACTION_DOWN必須返回true,之后的事件才會傳遞進來
OnTouchListener優先于onTouchEvent()對事件進行消費
5 ANR對話框
應用在5秒內未響應用戶的輸入事件(如按鍵或者觸摸)
BroadcastReceiver未在10秒內完成相關的處理
Service在特定的時間內無法處理完成 20秒
可以使用一下方法
使用AsyncTask處理耗時IO操作。
使用Thread或者HandlerThread時,調用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設置優先級,否則仍然會降低程序響應,因為默認Thread的優先級和主線程相同。
使用Handler處理工作線程結果,而不是使用Thread.wait()或者Thread.sleep()來阻塞主線程。
Activity的onCreate和onResume回調中盡量避免耗時的代碼
BroadcastReceiver中onReceive代碼也要盡量減少耗時,建議使用IntentService處理
6 Requestlayout,onlayout,onDraw,DrawChild
requestLayout()方法 :會導致調用measure()過程 和 layout()過程 。 將會根據標志位判斷是否需要ondraw
onLayout()方法(如果該View是ViewGroup對象,需要實現該方法,對每個子視圖進行布局)
調用onDraw()方法繪制視圖本身 (每個View都需要重載該方法,ViewGroup不需要實現該方法)
drawChild()去重新回調每個子視圖的draw()方法
7 Handler
1 當Android程序第一次創建的時候,在主線程同時會創建一個Looper對象。Looper實現了一個簡單的消息隊列,一個接著一個處理Message對象。程序框架所有主要的事件(例如:屏幕上的點擊時間,Activity生命周期的方法等等)都包含在Message對象中,然后添加到Looper的消息隊列中,一個一個處理。主線程的Looper存在整個應用程序的生命周期內。
2 當一個Handler對象在主線程中創建的時候,它會關聯到Looper的 message queue 。Message添加到消息隊列中的時候Message會持有當前Handler引用,當Looper處理到當前消息的時候,會調用Handler#handleMessage(Message).
3 在java中,no-static的內部類會 隱式的 持有當前類的一個引用。static的類則沒有。
8 onSaveInstanceState,onRestoreInstanceState
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它們不同于 onCreate()、onPause()等生命周期方法,它們并不一定會被觸發。當應用遇到意外情況(如:內存不足、用戶直接按Home鍵)由系統銷毀一個Activity,onSaveInstanceState() 會被調用。但是當用戶主動去銷毀一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。除非該activity是被用戶主動銷毀的,通常onSaveInstanceState()只適合用于保存一些臨時性的狀態,而onPause()適合用于數據的持久化保存。
9 OOM
Out Of Merrory,Android系統的每一個應用程序都設置一個硬性的Dalvik Heap Size最大限制閾值,如果申請的內存資源超過這個限制,系統就會拋出OOM錯誤
內存泄漏,阻止對象回收:
類的靜態變量持有大數據對象
非靜態內部類存在靜態實例
資源對象未關閉
Handler內存泄漏
解決方法:
使用更加輕量的數據結構 例如,我們可以考慮使用ArrayMap/SparseArray而不是HashMap等傳統數據結構
避免在Android里面使用Enum
減小Bitmap對象的內存占用,Bitmap對象的復用
使用更小的圖片
StringBuilder 在有些時候,代碼中會需要使用到大量的字符串拼接的操作,這種時候有必要考慮使用StringBuilder來替代頻繁的“+”。
避免在onDraw方法里面執行對象的創建
10 Asynctask
內存泄露: 非靜態內部類AsynTask會隱式地持有外部類的引用,如果其生命周期大于外部activity的生命周期,就會出現內存泄漏
注意要復寫AsynTask的onCancel方法,把里面的socket,file等,該關掉的要及時關掉
在 Activity 的onDestory()方法中調用Asyntask.cancal方法
Asyntask內部使用弱引用的方式來持有Activity
若Activity已經銷毀,此時AsynTask執行完并且返回結果,會報異常嗎?
當一個App旋轉時,整個Activity會被銷毀和重建。當Activity重啟時,AsyncTask中對該Activity的引用是無效的,因此onPostExecute()就不會起作用,若AsynTask正在執行,折會報 view not attached to window manager 異常
同樣也是生命周期的問題,在 Activity 的onDestory()方法中調用Asyntask.cancal方法,讓二者的生命周期同步