插件化 – apk 分爲宿主和插件部分,插件在須要的時候才加載進來html
熱修復 – 更新的類或者插件粒度較小的時候,咱們會稱之爲熱修復,通常用於修復bugjava
熱更新 – 2016 Google 的 Android Studio 推出了Instant Run 功能 同時提出了3個名詞android
「暖部署」 – app無需重啓,可是activity須要重啓,好比資源的修改。web
站在app開發者角度的「熱」是指在不發版的狀況來實現更新sql
1.阿里的熱更新框架已經開源 了。但已經好久沒有更新過新版本了。當前的版本只支持到了 Android 4.4。因爲 5.0 起新的 ART 虛擬機、更嚴格的 SELinux 策略以及對 64 位的支持之類的事,使得 Xposed 都在開發上作了不少調整。我不知道 Dexposed 如今是否支持,但至少阿里沒有開源。數據庫
2.在本地動態執行遠端下發的代碼是極度危險的行爲。利用此方法執行非法代碼等或用於繞過 Google Play 等市場的審查是違反相關協議的,也是對用戶極度不負責任的行爲。canvas
3.在一些訪問很是密集的地方使用熱更新可能會對效率產生相對比較大的影響,應該避免使用.設計模式
4.咱們能夠對 Java 的 ScriptEngine 進行一些封裝成爲一個 HotPatch 類使得它更適合作熱更新的工做。瀏覽器
5.首先,檢查熱更新補丁的管道必定要創建在 https 上,由於下發代碼是極其危險的,若是被劫持,後果是沒法想象的。其次,請求時最好自動帶上 Android 版本、手機型號、地區、版本號等信息,以方便更精確地下發,千萬不能下發錯。緩存
6.Java在運行時加載對應的類是經過ClassLoader來實現的,ClassLoader自己是一個抽象來,Android中使用PathClassLoader類做爲Android的默認的類加載器
7.咱們的若是想作hotpatch,必定要保證咱們的hotpacth dex文件出如今dexElements列表的前面。
基於QQ空間的HotFix →→ 要使用到android dex分包方案→拆分dex的項目的話,能夠參考一下谷歌的multidex方案實現.
大衆點評的NuWa←項目補丁自動化作的很完整
alibaba/AndFix
阿里巴巴的DexPosed
dalvik_patch實現multidex
使用React-Native實現app熱部署的一次實踐
alibaba/AndFix
注意:
鎖定屏與解鎖屏幕 只會調用onPause(),而不會調用onStop方法,開屏後則調用onResume()。在實際操做中會有所出入,好比在三星手機測試的時候鎖定手機調用了onPause()和onStop()方法,解鎖時候調用的是:onRestart(),onStart()和 onResume()方法。
啓動Activity:
onCreate()—>onStart()—>onResume(),Activity進入運行狀態。
Activity退居後臺:
當前Activity轉到新的Activity界面或按Home鍵回到主屏: onPause()—>onStop(),進入停滯狀態。
Activity返回前臺:
onRestart()—>onStart()—>onResume(),再次回到運行狀態。
Activity退居後臺,且系統內存不足,
系統會殺死這個後臺狀態的Activity,若再次回到這個Activity,則會走onCreate()–>onStart()—>onResume()
鎖定屏與解鎖屏幕
只會調用onPause(),而不會調用onStop方法,開屏後則調用onResume()
好比屏幕旋轉這個例子,在重建Activity的時候,會回調
Activity.onRetainNonConfigurationInstance()複製代碼
從新傳遞一個新的對象給AsyncTask,完成引用的更新
當一個App旋轉時,整個Activity會被銷燬和重建。
當Activity重啓時,AsyncTask中對該Activity的引用是無效的,所以onPostExecute()就不會起做用
若AsynTask正在執行,折會報 view not attached to window manager 異常
一樣也是生命週期的問題,在 Activity 的onDestory()方法中調用Asyntask.cancal方法,讓兩者的生命週期同步
當應用遇到意外狀況(如:內存不足、用戶直接按Home鍵)由系統銷燬一個Activity,onSaveInstanceState() 會被調用。
可是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。除非該activity是被用戶主動銷燬的
一般onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。
咱們能夠在AndroidManifest.xml配置的android:launchMode屬性爲如下四種之一。
一、standard
standard模式是默認的啓動模式,不用爲配置android:launchMode屬性便可,固然也能夠指定值爲standard。standard啓動模式,無論有沒有已存在的實例,都生成新的實例。
二、 singleTop
咱們在上面的基礎上爲指定屬性android:launchMode=」singleTop」,系統就會按照singleTop啓動模式處理跳轉行爲。跳轉時系統會先在棧結構中尋找是否有一個Activity實例正位於棧頂,若是有則再也不生成新的,而是直接使用。若是系統發現存在有Activity實例,但不是位於棧頂,從新生成一個實例。 這就是singleTop啓動模式,若是發現有對應的Activity實例正位於棧頂,則重複利用,再也不生成新的實例。
三、 singleTask
若是發現有對應的Activity實例,則使此Activity實例之上的其餘Activity實例通通出棧,使此Activity實例成爲棧頂對象,顯示到幕前。
四、singleInstance
這種啓動模式比較特殊,由於它會啓用一個新的棧結構,將Acitvity放置於這個新的棧結構中,並保證再也不有其餘Activity實例進入。
singleTop適合接收通知啓動的內容顯示頁面。
例如,某個新聞客戶端的新聞內容頁面,若是收到10個新聞推送,每次都打開一個新聞內容頁面是很煩人的。
singleTask適合做爲程序入口點。
例如瀏覽器的主界面。無論從多少個應用啓動瀏覽器,只會啓動主界面一次,其他狀況都會走onNewIntent,而且會清空主界面上面的其餘頁面。
singleInstance應用場景:
鬧鈴的響鈴界面。 你之前設置了一個鬧鈴:上午6點。在上午5點58分,你啓動了鬧鈴設置界面,並按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,而且彈出了一個對話框形式的 Activity(名爲 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以
SingleInstance
加載模式打開的),你按返回鍵,回到的是微信的聊天界面,這是由於 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 所以退出以後這個 Task 的棧空了。若是是以 SingleTask 打開 AlarmAlertActivity,那麼當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設置界面。
Android設置是Debug版本,且root,直接將該apk用adb工具push到system/app或system/priv-app
若是是非root設備,須要編譯後燒寫鏡像
有些權限(如WRITE_SECURE_SETTINGS)不開放給第三方應用,只能在對應設備源碼總編譯而後做爲系統app使用
Activity像一個工匠(控制單元)
Window像窗戶(承載模型)
View像窗花(顯示視圖)
LayoutInflater像剪刀
Xml配置像窗花圖紙。
startService:生命週期和調用者不一樣.啓動後若調用者未調用stopService而直接退出,Service仍會運行
bindService:生命週期與調用者綁定,調用者一旦退出,Service就會調用unBind->onDestory
棧通常以包名命名,兩個應用的簽名和udid要相同
Fragment能夠做爲Activity界面的一部分組成出現
其做用是:
碎片整理,局部刷新。
一個Activity中能夠同時出現多個Fragment,並一個Fragment也能夠在多個Activity中使用.
在Activity中能夠添加,刪除,替換Fragment.Fragment能夠響應本身的輸入時間,而且有本身的生命週期,但其生命週期收Activity影響.
利用只讀屬性動畫+WindowManager
/*
*@param from\>=0&&from\<=1.0f
* @param to\>=0&&to\<=1.0f
*
* */
private void dimBackground(final float from, final float to) {
final Window window = getWindow();
ValueAnimator valueAnimator = ValueAnimator.ofFloat(from, to);
valueAnimator.setDuration(500);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
WindowManager.LayoutParams params = window.getAttributes();
params.alpha = (Float) animation.getAnimatedValue();
window.setAttributes(params);
}
});
valueAnimator.start();
}複製代碼
本地廣播在本應用範圍內傳播,不用擔憂隱私數據泄露,不用擔憂別的應用僞造廣播.相比全局廣播,本地廣播更高效.
1.靜態註冊:在清單文件中註冊, 常見的有監聽設備啓動,常駐註冊不會隨程序生命週期改變
2.動態註冊:在代碼中註冊,隨着程序的結束,也就中止接受廣播了
補充一點:有些廣播只能經過動態方式註冊,好比時間變化事件、屏幕亮滅事件、電量變動事件,由於這些事件觸發頻率一般很高,若是容許後臺監聽,會致使進程頻繁建立和銷燬,從而影響系統總體性能
a:從MVC的角度考慮(應用程序內) 其實回答這個問題的時候還能夠這樣問,android爲何要有那4大組件,如今的移動開發模型基本上也是照搬的web那一套MVC架構,只不過是改了點嫁妝而已。
android的四大組件本質上就是爲了實現移動或者說嵌入式設備上的MVC架構
b:程序間互通消息(例如在本身的應用程序內監聽系統來電)
c:效率上(參考UDP的廣播協議在局域網的方便性)
d:設計模式上(反轉控制的一種應用,相似監聽者模式)
IntentService是Service的子類,是一個異步的,會自動中止的服務,很好解決了傳統的Service中處理完耗時操做忘記中止並銷燬Service的問題
生成一個默認的且與線程相互獨立的工做線程執行全部發送到onStartCommand()方法的Intent,能夠在onHandleIntent()中處理.
串行隊列,每次只運行一個任務,不存在線程安全問題,全部任務執行完後自動中止服務,不須要本身手動調用stopSelf()來中止.
在AndroidManifest.xml文件中對於intent-filter能夠經過android:priority = 「1000」這個屬性設置最高優先級,1000是最高值,若是數字越小則優先級越低,同時適用於廣播。
ContentProvider和sql的區別
ContentProvider的主要仍是用於數據共享,其能夠對Sqlite,SharePreferences,File等進行數據操做用來共享數據。而sql的能夠理解爲數據庫的一門語言,可使用它完成CRUD等一系列的操做
文件存儲:
經過Java.io.FileInputStream和java.io.FileOutputStream這兩個類來實現對文件的讀寫,java.io.File類則用來構造一個具體指向某個文件或者文件夾的對象。
SharedPreferences:
SharedPreferences是一種輕量級的數據存儲機制,他將一些簡單的數據類型的數據,包括boolean類型,int類型,float類型,long類型以及String類型的數據,以鍵值對的形式存儲在應用程序的私有Preferences目錄(/data/data/<包名>/shared_prefs/)中,這種Preferences機制普遍應用於存儲應用程序中的配置信息。
SQLite數據庫:
當應用程序須要處理的數據量比較大時,爲了更加合理地存儲、管理、查詢數據,咱們每每使用關係數據庫來存儲數據。Android系統的不少用戶數據,如聯繫人信息,通話記錄,短信息等,都是存儲在SQLite數據庫當中的,因此利用操做SQLite數據庫的API能夠一樣方便的訪問和修改這些數據。
ContentProvider:
主要用於在不一樣的應用程序之間實現數據共享的功能,不一樣於sharepreference和文件存儲中的兩種全局可讀寫操做模式,內容提供其能夠選擇只對哪一部分數據進行共享,從而保證咱們程序中的隱私數據不會有泄漏的風險
在Android中不能直接打開res aw目錄中的數據庫文件,而須要在程序第一次啓動時將該文件複製到手機內存或SD卡的某個目錄中,而後再打開該數據庫文件。
複製的基本方法是使用getResources().openRawResource方法得到res aw目錄中資源的 InputStream對象,而後將該InputStream對象中的數據寫入其餘的目錄中相應文件中。
在Android SDK中可使用SQLiteDatabase.openOrCreateDatabase方法來打開任意目錄中的SQLite數據庫文件。
「aar」包是 Android 的類庫項目的二進制發行包。
文件擴展名是.aar,maven 項目類型應該也是aar,但文件自己是帶有如下各項的 zip 文件:
這些條目是直接位於 zip 文件根目錄的。 其中R.txt 文件是aapt帶參數–output-text-symbols的輸出結果。
jar打包不能包含資源文件,好比一些drawable文件、xml資源文件之類的,aar能夠。
SQLite做爲輕量級的數據庫,比MySQL還小,但支持SQL語句查詢,提升性能能夠考慮經過原始通過優化的SQL查詢語句方式處理
能夠將dictionary.db文件複製到Eclipse Android工程中的res aw目錄中。全部在res aw目錄中的文件不會被壓縮,這樣能夠直接提取該目錄中的文件。能夠將dictionary.db文件複製到res aw目錄中
Service設置成START_STICKY kill 後會被重啓(等待5秒左右),重傳Intent,保持與重啓前同樣
經過 startForeground將進程設置爲前臺進程, 作前臺服務,優先級和前臺應用一個級別,除非在系統內存很是缺,不然此進程不會被 kill
雙進程Service: 讓2個進程互相保護**,其中一個Service被清理後,另外沒被清理的進程能夠當即重啓進程
QQ黑科技: 在應用退到後臺後,另起一個只有 1 像素的頁面停留在桌面上,讓本身保持前臺狀態,保護本身不被後臺清理工具殺死
在已經root的設備下,修改相應的權限文件,將App假裝成系統級的應用 Android4.0系列的一個漏洞,已經確承認行
用C編寫守護進程(即子進程) : Android系統中當前進程(Process)fork出來的子進程,被系統認爲是兩個不一樣的進程。當父進程被殺死的時候,子進程仍然能夠存活,並不受影響。*鑑於目前提到的在Android->- Service層作雙守護都會失敗*,咱們能夠fork出c進程,多進程守護。死循環在那檢查是否還存在,具體的思路以下(Android5.0以上的版本不可行)
用C編寫守護進程(即子進程),守護進程作的事情就是循環檢查目標進程是否存在,不存在則啓動它。
在NDK環境中將1中編寫的C代碼編譯打包成可執行文件(BUILD_EXECUTABLE)。主進程啓動時將守護進程放入私有目錄下,賦予可執行權限,啓動它便可。
聯繫廠商,加入白名單
1 首先嚐試讀取IMEI、Mac地址、CPU號等物理信息(有很多工具能夠修改IMEI);
2 若是均失敗,能夠本身生成UUID而後保存到文件(文件也可能被篡改或刪除)
參考:[blog.csdn.net/xushuaic/ar…]
它只是用來放啓動圖標的,好處就是,你只用放一個mipmap圖標,它就會給你各類版本(好比平板,手機)的apk自動生成相應分辨率的圖標,以節約空間。
重用converView: 經過複用converview來減小沒必要要的view的建立,另外Infalte操做會把xml文件實例化成相應的View實例,屬於IO操做,是耗時操做。
減小findViewById()操做: 將xml文件中的元素封裝成viewholder靜態類,經過converview的setTag和getTag方法將view與相應的holder對象綁定在一塊兒,避免沒必要要的findviewbyid操做
避免在 getView 方法中作耗時的操做: 例如加載本地 Image 須要載入內存以及解析 Bitmap ,都是比較耗時的操做,若是用戶快速滑動listview,會由於getview邏輯過於複雜耗時而形成滑動卡頓現象。用戶滑動時候不要加載圖片,待滑動完成再加載,可使用這個第三方庫glide
Item的佈局層次結構儘可能簡單,避免佈局太深或者沒必要要的重繪
儘可能能保證 Adapter 的 hasStableIds() 返回 true 這樣在 notifyDataSetChanged() 的時候,若是item內容並無變化,ListView 將不會從新繪製這個 View,達到優化的目的
在一些場景中,ScollView內會包含多個ListView,能夠把listview的高度寫死固定下來。 因爲ScollView在快速滑動過程當中須要大量計算每個listview的高度,阻塞了UI線程致使卡頓現象出現,若是咱們每個item的高度都是均勻的,能夠經過計算把listview的高度肯定下來,避免卡頓現象出現
使用 RecycleView 代替listview: 每一個item內容的變更,listview都須要去調用notifyDataSetChanged來更新所有的item,太浪費性能了。RecycleView能夠實現當個item的局部刷新,而且引入了增長和刪除的動態效果,在性能上和定製上都有很大的改善
ListView 中元素避免半透明: 半透明繪製須要大量乘法計算,在滑動時不停重繪會形成大量的計算,在比較差的機子上會比較卡。 在設計上能不半透明就不不半透明。實在要弄就把在滑動的時候把半透明設置成不透明,滑動完再從新設置成半透明。
儘可能開啓硬件加速: 硬件加速提高巨大,避免使用一些不支持的函數致使含淚關閉某個地方的硬件加速。固然這一條不僅是對 ListView。
這個是考靜態內部類和非靜態內部類的主要區別之一。非靜態內部類會隱式持有外部類的引用,就像你們常常將自定義的adapter在Activity類裏,而後在adapter類裏面是能夠隨意調用外部activity的方法的。
當你將內部類定義爲static時,你就調用不了外部類的實例方法了,由於這時候靜態內部類是不持有外部類的引用的。聲明ViewHolder靜態內部類,能夠將ViewHolder和外部類解引用。
你們會說通常ViewHolder都很簡單,不定義爲static也沒事吧。確實如此,可是若是你將它定義爲static的,說明你懂這些含義。萬一有一天你在這個ViewHolder加入一些複雜邏輯,作了一些耗時工做,那麼若是ViewHolder是非靜態內部類的話,就很容易出現內存泄露。
若是是靜態的話,你就不能直接引用外部類,迫使你關注如何避免相互引用。 因此將 ViewHolder內部類 定義爲靜態的,是一種好習慣
逐幀動畫(Drawable Animation):
加載一系列Drawable資源來建立動畫,簡單來講就是播放一系列的圖片來實現動畫效果,能夠自定義每張圖片的持續時間
補間動畫(Tween Animation):
Tween能夠對View對象實現一系列簡單的動畫效果,好比位移,縮放,旋轉,透明度等等。可是它並不會改變View屬性的值,只是改變了View的繪製的位置,好比,一個按鈕在動畫事後,不在原來的位置,可是觸發點擊事件的仍然是原來的座標。
屬性動畫(Property Animation):
動畫的對象除了傳統的View對象,還能夠是Object對象,動畫結束後,Object對象的屬性值被實實在在的改變了
實現原理是每次繪製視圖時View所在的ViewGroup中的drawChild函數獲取該View的Animation的Transformation值
而後調用canvas.concat(transformToApply.getMatrix()),經過矩陣運算完成動畫幀,若是動畫沒有完成,繼續調用invalidate()函數,啓動下次繪製來驅動動畫
動畫過程當中的幀之間間隙時間是繪製函數所消耗的時間,可能會致使動畫消耗比較多的CPU資源,最重要的是,動畫改變的只是顯示,並不能相應事件
SurfaceView中採用了雙緩存技術,在單獨的線程中更新界面
View在UI線程中更新界面
一、 明確需求,肯定你想實現的效果
二、肯定是使用組合控件的形式仍是全新自定義的形式,組合控件即便用多個系統控件來合成一個新控件,你好比titilebar,這種形式相對簡單,參考
三、若是是徹底自定義一個view的話,你首先須要考慮繼承哪一個類,是View呢,仍是ImageView等子類。
四、根據須要去複寫View#onDraw、View#onMeasure、View#onLayout方法
5.根據須要去複寫dispatchTouchEvent、onTouchEvent方法
六、根據須要爲你的自定義view提供自定義屬性,即編寫attr.xml,而後在代碼中經過TypedArray等類獲取到自定義屬性值
七、須要處理滑動衝突、像素轉換等問題
談談View的繪製流程
measure()方法,layout(),draw()三個方法主要存放了一些標識符,來判斷每一個View是否須要再從新測量,佈局或者繪製,主要的繪製過程仍是在onMeasure,onLayout,onDraw這個三個方法中
1.onMesarue() 爲整個View樹計算實際的大小,即設置實際的高(對應屬性:mMeasuredHeight)和寬(對應屬性: mMeasureWidth),每一個View的控件的實際寬高都是由父視圖和自己視圖決定的。
2.onLayout() 爲將整個根據子視圖的大小以及佈局參數將View樹放到合適的位置上。
3.onDraw() 開始繪製圖像,繪製的流程以下
自定義一個view時,重寫onDraw。調用view.invalidate(),會觸發onDraw和computeScroll()。前提是該view被附加在當前窗口.
view.postInvalidate(); //是在非UI線程上調用的
自定義一個ViewGroup,重寫onDraw。onDraw可能不會被調用,緣由是須要先設置一個背景(顏色或圖)。表示這個group有東西須要繪製了,纔會觸發draw,以後是onDraw。所以,通常直接重寫dispatchDraw來繪製viewGroup.自定義一個ViewGroup,dispatchDraw會調用drawChild.
全部Touch事件都被封裝成了MotionEvent對象,包括Touch的位置、時間、歷史記錄以及第幾個手指(多指觸摸)等。
事件類型分爲ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每一個事件都是以ACTION_DOWN開始ACTION_UP結束。
對事件的處理包括三類,分別爲傳遞——dispatchTouchEvent()函數、攔截——onInterceptTouchEvent()函數、消費——onTouchEvent()函數和OnTouchListener()
簡單來講:
事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被中止或攔截,從最上層的View(ViewGroup)開始一直往下(子View)傳遞。子View能夠經過onTouchEvent()對事件進行處理。
事件由父View(ViewGroup)傳遞給子View,ViewGroup能夠經過onInterceptTouchEvent()對事件作攔截,中止其往下傳遞。
若是事件從上往下傳遞過程當中一直沒有被中止,且最底層子View沒有消費事件,事件會反向往上傳遞,這時父View(ViewGroup)能夠進行消費,若是仍是沒有被消費的話,最後會到Activity的onTouchEvent()函數。
若是View沒有對ACTION_DOWN進行消費,以後的其餘事件不會傳遞過來。
= OnTouchListener優先於onTouchEvent()對事件進行消費。
上面的消費即表示相應函數返回值爲true。
onTouch優於onTouchEvent,onTouchEvent優於onClick
觸摸事件的分發機制詳見:
Dalvik虛擬機是Android平臺的核心。
它能夠支持.dex格式的程序的運行
Dalvik 基於寄存器,而 JVM 基於棧。基於寄存器的虛擬機對於更大的程序來講,在它們編譯的時候,花費的時間更短。
Dalvik執行.dex格式的字節碼,而JVM執行.class格式的字節碼
具體參考:
[www.cnblogs.com/mythou/p/32…]
如何解決方法數65k問題?
使用Android Studio 的gradle 能夠構建MutilDex
若是你以爲此文對您有所幫助,歡迎入羣 QQ交流羣 :232203809
微信公衆號:終端研發部