android知識點

基礎

Activity和Fragment生命週期有哪些?javascript


 


橫豎屏切換時候Activity的生命週期java

不設置Activity的android:configChanges時,切屏會從新掉喲過各個生命週期,切橫屏時會執行一次,切豎屏時會執行兩次
設置Activity的android:configChanges=」orientation」時,切屏仍是會調用各個生命週期,切換橫豎屏只會執行一次
設置Activity的android:configChanges=」orientation|keyboardHidden」時,切屏不會從新調用各個生命週期,只會執行onConfigurationChanged方法android

默認狀況下,切換屏幕方向時Activity會銷燬、重建
onPause->onStop->onDestroy->onCreate->onStart->onResume
配置爲android:configChanges=」orientation|screenSize」時web

AsyncTask
源碼解析
AsyncTask的缺陷和問題數據庫

關於線程池:asynctask對應的線程池ThreadPoolExecutor都是進程範圍內共享的,都是static的,因此是asynctask控制着進程範圍內全部的子類實例。因爲這個限制的存在,當使用默認線程池時,若是線程數超過線程池的最大容量,線程池就會爆掉(3.0後默認串行執行,不會出現這個問題)。針對這種狀況,能夠嘗試自定義線程池,配合asynctask使用。json

關於默認線程池:核心線程池中最多有CPU_COUNT+1個,最多有CPU_COUNT*2+1個,線程等待隊列的最大等待數爲128,可是能夠自定義線程池。線程池是由AsyncTask來管理的,線程池容許tasks並行運行,xuyao注意的是併發狀況下數據的一致性問題,新數據可能會被老數據覆蓋掉,相似volatile變量。因此但願tasks可以串行運行的話,使用SERIAL_EXECUTOR。安全

自定義線程池:executeOnExecutor(Executor exec,Params… params) 自定義Executor網絡

execute(Params… params){return executeOnExecutor(sDefaultExecutor,params);}架構

AsyncTask在不一樣的SDK版本中的區別:併發

調用AsyncTask的excute方法不能當即執行程序的緣由分析及改善方案

經過查閱官方文檔發現,AsyncTask首次引入時,異步任務是在一個獨立的線程中順序的執行,也就是說一次只能執行一個任務,不能並行的執行,從1.6開始,AsyncTask引入了線程池,支持同時執行5個異步任務,也就是說同時只能有5個線程運行,超過的線程只能等待,等待前面的線程某個執行完了才被調度和運行。換句話說,若是一個進程中的AsyncTask實例個數超過5個,那麼假如前5個都運行很長時間的話,那麼第6個只能等待機會了。這是AsyncTask的一個限制,並且對於2.3之前的版本沒法解決。若是你的應用須要大量的後臺線程去執行任務,那麼你只能放棄使用AsyncTask,本身建立線程池來管理Thread,或者乾脆不用線程池直接使用Thread也無妨。不得不說,雖然AsyncTask較Thread使用起來方便,可是它最多隻能同時運行5個線程,這也大大侷限了它的實力,你必需要當心設計你的應用,錯開使用AsyncTask的時間,盡力作到分時,或者保證數量不會大於5個,不然就會遇到上次提到的問題。多是Google意識到了AsyncTask的侷限性了,從Android3.0開始對AsyncTask的API做出了一些調整:每次只啓動一個線程執行一個任務,完成以後再執行第二個任務,也就是至關於只有一個後臺線程在執行所提交的任務。

1.生命週期

不少開發者會認爲一個在Activity中建立的AsyncTask會隨着Activity的銷燬而銷燬。然而事實並不是如此。AsyncTask會一直執行,直到doInBackground()方法執行完畢。而後,若是cancel(boolean)被調用,那麼onCancelled(Result result)方法會被執行;不然,執行onPostExecute(Result result)方法。若是咱們的Activity銷燬以前,沒有取消AsyncTask,這有可能讓咱們的AsyncTask崩潰(crash)。由於它想要處理的view已經不在了。因此,咱們老是必須確保在銷燬活動以前取消任務。總之,咱們使用AsyncTask須要確保AsyncTask正確的取消。

2.內存泄漏

若是AsyncTask被聲明爲Activity的非靜態的內部類,那麼AsyncTask會保留一個對Activity的引用。若是Activity已經被銷燬,AsyncTask的後臺線程還在執行,它將繼續在內存裏保留這個引用,致使Activity沒法被回收,引發內存泄漏。

3.結果丟失

屏幕旋轉或Activity在後臺被系統殺掉等狀況會致使Activity的從新建立,以前運行的AsyncTask會持有一個以前Activity的引用,這個引用已經無效,這時調用onPostExecute()再去更新界面將再也不生效。

4.並行仍是串行

在Android1.6以前的版本,AsyncTask是串行的,在1.6至2.3的版本,改爲了並行的。在2.3以後的版本又作了 修改,能夠支持並行和串行,當想要串行執行時,直接執行execute()方法,若是須要執行executeOnExecutor(Executor)。

自定義View的相關方法 1.自定義屬性
2.onLayout(Viewgroup)
3.onMesure
4.onDraw
5.交互: onIntercepterTouchEvent()
onTouchEvent()

android中進程的優先級?
前臺進程
可見進程
服務進程
後臺進程
空進程

Serializable和Parcelable
序列化,表示將一個對象轉換成可存儲或可傳輸的狀態。序列化後的對象能夠在網絡上進行傳輸,也能夠存儲到本地。
Serializable(Java自帶):
Serializable是序列化的意思,表示將一個對象轉換成可存儲或可傳輸的狀態。序列化後的對象能夠在網絡上進行傳輸,也能夠存儲到本地。

Parcelable(android 專用):
除了Serializable以外,使用Parcelable也能夠實現相同的效果,
不過不一樣於將對象進行序列化,Parcelable方式的實現原理是將一個完整的對象進行分解,
而分解後的每一部分都是Intent所支持的數據類型,這樣也就實現傳遞對象的功能了。

文件和數據庫哪一個效率高
大量讀取數據數據庫更高效

Android系統啓動過程,App啓動過程
]從桌面點擊到activity啓動的過程

1.Launcher線程捕獲onclick的點擊事件,調用Launcher.startActivitySafely,進一步調用Launcher.startActivity,最後調用父類Activity的startActivity。

2.Activity和ActivityManagerService交互,引入Instrumentation,將啓動請求交給Instrumentation,調用Instrumentation.execStartActivity。

3.調用ActivityManagerService的startActivity方法,這裏作了進程切換(具體過程請查看源碼)。

4.開啓Activity,調用onCreate方法

事件傳遞機制 詳解
當手指觸摸到屏幕時,系統就會調用相應View的onTouchEvent,並傳入一系列的action。

dispatchTouchEvent的執行順序爲:

首先觸發ACTIVITY的dispatchTouchEvent,而後觸發ACTIVITY的onUserInteraction
而後觸發LAYOUT的dispatchTouchEvent,而後觸發LAYOUT的onInterceptTouchEvent
這就解釋了重寫ViewGroup時必須調用super.dispatchTouchEvent();

(1)dispatchTouchEvent:

此方法通常用於初步處理事件,由於動做是由此分發,因此一般會調用super.dispatchTouchEvent。這樣就會繼續調用onInterceptTouchEvent,再由onInterceptTouchEvent決定事件流向。

(2)onInterceptTouchEvent:

若返回值爲true事件會傳遞到本身的onTouchEvent();若返回值爲false傳遞到下一個View的dispatchTouchEvent();

(3)onTouchEvent():

若返回值爲true,事件由本身消耗,後續動做讓其處理;若返回值爲false,本身不消耗事件了,向上返回讓其餘的父View的onTouchEvent接受處理

三大方法關係的僞代碼:若是當前View攔截事件,就交給本身的onTouchEvent去處理,不然就丟給子View繼續走相同的流程。

public boolean dispatchTouchEvent(MotionEvent ev) { boolean consume = false; if(onInterceptTouchEvent(ev)) { consume = onTouchEvent(ev); } else { consume = child.dispatchTouchEvent(ev); } return consume; }

onTouchEvent的傳遞:

當有多個層級的View時,在父層級容許的狀況下,這個action會一直傳遞直到遇到最深層的View。因此touch事件最早調用的是最底層View的onTouchEvent,若是View的onTouchEvent接收到某個touch action並作了相應處理,最後有兩種返回方式return true和return false;return true會告訴系統當前的View須要處理此次的touch事件,之後的系統發出的ACTION_MOVE,ACTION_UP仍是須要繼續監聽並接收的,而且此次的action已經被處理掉了,父層的View是不可能觸發onTouchEvent的了。因此每個action最多隻能有一個onTouchEvent接口返回true。若是返回false,便會通知系統,當前View不關心這一次的touch事件,此時這個action會傳向父級,調用父級View的onTouchEvent。可是這一次的touch事件以後發出任何action,該View都不在接受,onTouchEvent在這一次的touch事件中不再會觸發,也就是說一旦View返回false,那麼以後的ACTION_MOVE,ACTION_UP等ACTION就不會在傳入這個View,可是下一次touch事件的action仍是會傳進來的。

父層的onInterceptTouchEvent

前面說了底層的View可以接收到此次的事件有一個前提條件:在父層容許的狀況下。假設不改變父層級的dispatch方法,在系統調用底層onTouchEvent以前會調用父View的onInterceptTouchEvent方法判斷,父層View是否要截獲本次touch事件以後的action。若是onInterceptTouchEvent返回了true,那麼本次touch事件以後的全部action都不會向深層的View傳遞,通通都會傳給父層View的onTouchEvent,就是說父層已經截獲了此次touch事件,以後的action也沒必要詢問onInterceptTouchEvent,在此次的touch事件以後發出的action時onInterceptTouchEvent不會再被調用,直到下一次touch事件的來臨。若是onInterceptTouchEvent返回false,那麼本次action將發送給更深層的View,而且以後的每一次action都會詢問父層的onInterceptTouchEvent需不須要截獲本次touch事件。只有ViewGroup纔有onInterceptTouchEvent方法,由於一個普通的View確定是位於最深層的View,只有ViewGroup纔有onInterceptTouchEvent方法,由於一個普通的View確定是位於最深層的View,touch可以傳到這裏已是最後一站了,確定會調用View的onTouchEvent()。

底層View的getParent().requestDisallowInterceptTouchEvent(true)

對於底層的View來講,有一種方法能夠阻止父層的View獲取touch事件,就是調用getParent().requestDisallowInterceptTouchEvent(true)方法。一旦底層View收到touch的action後調用這個方法那麼父層View就不會再調用onInterceptTouchEvent了,也沒法截獲之後的action(若是父層ViewGroup和最底層View須要截獲不一樣焦點,或不一樣手勢的touch,不能使用這個寫死)。

曾經開發過程當中遇到的兩個示例:左邊是處理ViewPager和ListView的衝突,紀錄水平和垂直方向的偏移量,若是水平方向的偏移更多的話就讓ViewPager處理pager滑動

右邊處理的ViewPager和ImageBanner的滑動衝突,一樣是紀錄偏移量,若是發生在ImageBanner上的水平偏移量大於垂直偏移量的話就讓banner滾動

想一想爲何右邊是重寫dispatchTouchEvent方法而不是onInterceptTouchEvent方法?

FixedViewPager
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch(ev.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: mX = ev.getX(); mY = ev.getY(); break; case MotionEvent.ACTION_MOVE: float x = ev.getX(); float y = ev.getY(); float dX = x - mX; float dY = y - mY; float tmp = Math.abs(dX) / Math.abs(dY); mX = x; mY = y; if(tmp > 1) { return true; } else { return super.omInterceptTouchEvent(ev); } } } FixedImageLoadBanner @override public boolean dispatchTouchEvent(MotionEvent ev) { if(mX != 0 || mY != 0) { float dY = ev.getRawY() - mY; float dX = ev.getRawX() - mX; if(Math.abs(dY) > Math.abs(dX)) { requestDisallowInterceptTouchEvent(false); } else { requestDisallowInterceptTouchEvent(true); } } mX = ev.getRawX(); mY = ev.getRawY(); return super.dispatchTouchEvent(ev); }

ART和Dalvik區別

art上應用啓動快,運行快,可是耗費更多存儲空間,安裝時間長,總的來講ART的功效就是」空間換時間」。

ART: Ahead of Time Dalvik: Just in Time

什麼是Dalvik:Dalvik是Google公司本身設計用於Android平臺的Java虛擬機。Dalvik虛擬機是Google等廠商合做開發的Android移動設備平臺的核心組成部分之一,它能夠支持已轉換爲.dex(即Dalvik Executable)格式的Java應用程序的運行,.dex格式是專爲Dalvik應用設計的一種壓縮格式,適合內存和處理器速度有限的系統。Dalvik通過優化,容許在有限的內存中同時運行多個虛擬機的實例,而且每個Dalvik應用做爲獨立的Linux進程執行。獨立的進程能夠防止在虛擬機崩潰的時候全部程序都被關閉。

什麼是ART:Android操做系統已經成熟,Google的Android團隊開始將注意力轉向一些底層組件,其中之一是負責應用程序運行的Dalvik運行時。Google開發者已經花了兩年時間開發更快執行效率更高更省電的替代ART運行時。ART表明Android Runtime,其處理應用程序執行的方式徹底不一樣於Dalvik,Dalvik是依靠一個Just-In-Time(JIT)編譯器去解釋字節碼。開發者編譯後的應用代碼須要經過一個解釋器在用戶的設備上運行,這一機制並不高效,但讓應用能更容易在不一樣硬件和架構上運行。ART則徹底改變了這套作法,在應用安裝的時候就預編譯字節碼到機器語言,這一機制叫Ahead-Of-Time(AOT)編譯。在移除解釋代碼這一過程後,應用程序執行將更有效率,啓動更快。

ART優勢:

系統性能的顯著提高
應用啓動更快、運行更快、體驗更流暢、觸感反饋更及時。
更長的電池續航能力
支持更低的硬件
ART缺點:

更大的存儲空間佔用,可能會增長10%-20%
更長的應用安裝時間

Scroller原理

Scroller執行流程裏面的三個核心方法

mScroller.startScroll()
mScroller.computeScrollOffset()
view.computeScroll()
一、在mScroller.startScroll()中爲滑動作了一些初始化準備,好比:起始座標,滑動的距離和方向以及持續時間(有默認值),動畫開始時間等。

二、mScroller.computeScrollOffset()方法主要是根據當前已經消逝的時間來計算當前的座標點。由於在mScroller.startScroll()中設置了動畫時間,那麼在computeScrollOffset()方法中依據已經消逝的時間就很容易獲得當前時刻應該所處的位置並將其保存在變量mCurrX和mCurrY中。除此以外該方法還可判斷動畫是否已經結束。

Android中Java和JavaScript交互

webView.addJavaScriptInterface(new Object(){xxx}, "xxx"); 1 答案:可使用WebView控件執行JavaScript腳本,而且能夠在JavaScript中執行Java代碼。要想讓WebView控件執行JavaScript,須要調用WebSettings.setJavaScriptEnabled方法,代碼以下: WebView webView = (WebView)findViewById(R.id.webview); WebSettings webSettings = webView.getSettings(); //設置WebView支持JavaScript webSettings.setJavaScriptEnabled(true); webView.setWebChromeClient(new WebChromeClient()); JavaScript調用Java方法須要使用WebView.addJavascriptInterface方法設置JavaScript調用的Java方法,代碼以下: webView.addJavascriptInterface(new Object() { //JavaScript調用的方法 public String process(String value) { //處理代碼 return result; } }, "demo"); //demo是Java對象映射到JavaScript中的對象名 可使用下面的JavaScript代碼調用process方法,代碼以下: <script language="javascript"> function search() { //調用searchWord方法 result.innerHTML = "<font color='red'>" + window.demo.process('data') + "</font>"; }

SurfaceView和View的最本質的區別

SurfaceView是在一個新起的單獨線程中能夠從新繪製畫面,而view必須在UI的主線程中更新畫面。

在UI的主線程中更新畫面可能會引起問題,好比你更新的時間過長,那麼你的主UI線程就會被你正在畫的函數阻塞。那麼將沒法響應按鍵、觸屏等消息。當使用SurfaceView因爲是在新的線程中更新畫面因此不會阻塞你的UI主線程。但這也帶來了另一個問題,就是事件同步。好比你觸屏了一下,你須要SurfaceView中thread處理,通常就須要有一個event queue的設計來保存touchevent,這會稍稍複雜一點,由於涉及到線程安全。

ANR排錯

一、ANR排錯通常有三種類型

  • KeyDispatchTimeout(5 seconds) –主要類型按鍵或觸摸事件在特定時間內無響應
  • BroadcastTimeout(10 secends) –BroadcastReceiver在特定時間內沒法處理完成
  • ServiceTimeout(20 secends) –小几率事件 Service在特定的時間內沒法處理完成
  • 二、如何避免

UI線程儘可能只作跟UI相關的工做
耗時的操做(好比數據庫操做,I/O,鏈接網絡或者別的有可能阻塞UI線程的操做)把它放在單獨的線程處理
儘可能用Handler來處理UIthread和別的thread之間的交互.
三、如何排查

首先分析log
從trace.txt文件查看調用stack,adb pull data/anr/traces.txt ./mytraces.txt
看代碼
仔細查看ANR的成因(iowait?block?memoryleak?)
四、監測ANR的Watchdog

Android 內存溢出解決方案(OOM) 整理總結

  • 在內存引用上作些處理,經常使用的有軟引用、弱引用
  • 在內存中加載圖片時直接在內存中做處理,如:邊界壓縮
  • 動態回收內存
  • 優化Dalvik虛擬機的堆內存分配
  • 自定義堆內存大小

動畫詳解

View繪製流程

斷電續傳

Handler機制
andriod提供了Handler 和 Looper 來知足線程間的通訊。Handler先進先出原則。Looper類用來管理特定線程內對象之間的消息交換(MessageExchange)。
Looper: 一個線程能夠產生一個Looper對象,由它來管理此線程裏的MessageQueue(消息隊列)。
Handler: 你能夠構造Handler對象來與Looper溝通,以便push新消息到MessageQueue裏;或者接收Looper從Message Queue取出)所送來的消息。
Message Queue(消息隊列):用來存放線程放入的消息。
線程:UIthread 一般就是main thread,而Android啓動程序時會替它創建一個MessageQueue。

ListView卡頓緣由
Adapter的getView方法裏面convertView沒有使用setTag和getTag方式;
在getView方法裏面ViewHolder初始化後的賦值或者是多個控件的顯示狀態和背景的顯示沒有優化好,抑或是裏面含有複雜的計算和耗時操做;
在getView方法裏面 inflate的row 嵌套太深(佈局過於複雜)或者是佈局裏面有大圖片或者背景所致;
Adapter多餘或者不合理的notifySetDataChanged;
listview 被多層嵌套,屢次的onMessure致使卡頓,若是多層嵌套沒法避免,建議把listview的高和寬設置爲fill_parent. 若是是代碼繼承的listview,那麼也請你別忘記爲你的繼承類添加上LayoutPrams,注意高和寬都是fill_parent的;

啓動一個程序,能夠主界面點擊圖標進入,也能夠從一個程序中跳轉過去,兩者有什麼區別?
是由於啓動程序(主界面也是一個app),發現了在這個程序中存在一個設置爲

<category android:name="android.intent.category.LAUNCHER" />的activity,

因此這個launcher會把icon提出來,放在主界面上。當用戶點擊icon的時候,發出一個Intent:

Intent intent = mActivity.getPackageManager().getLaunchIntentForPackage(packageName);
mActivity.startActivity(intent);

跳過去能夠跳到任意容許的頁面,如一個程序能夠下載,那麼真正下載的頁面可能不是首頁(也有多是首頁),這時仍是構造一個Intent,startActivity.
這個intent中的action可能有多種view,download都有可能。系統會根據第三方程序向系統註冊的功能,爲你的Intent選擇能夠打開的程序或者頁面。因此惟一的一點
不一樣的是從icon的點擊啓動的intent的action是相對單一的,從程序中跳轉或者啓動可能樣式更多一些。本質是相同的。

優化

界面優化
太多重疊的背景(overdraw)

這個問題其實最容易解決,建議就是檢查你在佈局和代碼中設置的背景,有些背景是隱藏在底下的,它永遠不可能顯示出來,這種不必的背景必定要移除,由於它極可能會嚴重影響到app的性能。若是採用的是selector的背景,將normal狀態的color設置爲」@android:color/transparent」,也一樣能夠解決問題。

太多重疊的View

第一個建議是 :是喲過ViewStub來加載一些不經常使用的佈局,它是一個輕量級且默認是不可見的視圖,能夠動態的加載一個佈局,只要你用到這個重疊着的View的時候才加載,推遲加載的時間。

第二個建議是:若是使用了相似Viewpager+Fragment這樣的組合或者有多個Fragment在一個界面上,須要控制Fragment的顯示和隱藏,儘可能使用動態的Inflation view,它的性能要比SetVisibility好。

複雜的Layout層級

這裏的建議比較多一些,首先推薦使用Android提供的佈局工具Hierarchy Viewer來檢查和優化佈局。第一個建議是:若是嵌套的線性佈局加深了佈局層次,可使用相對佈局來取代。第二個建議是:用標籤來合併佈局。第三個建議是:用標籤來重用佈局,抽取通用的佈局可讓佈局的邏輯更清晰明瞭。記住,這些建議的最終目的都是使得你的Layout在Hierarchy Viewer裏變得寬而淺,而不是窄而深。

使用merge和include,ViewStub。

移動端獲取網絡數據優化的幾個點

鏈接複用:節省鏈接創建時間,如開啓 keep-alive。
對於Android來講默認狀況下HttpURLConnection和HttpClient都開啓了keep-alive。只是2.2以前HttpURLConnection存在影響鏈接池的Bug,具體可見:Android HttpURLConnection及HttpClient選擇

請求合併:即將多個請求合併爲一個進行請求,比較常見的就是網頁中的CSS Image Sprites。若是某個頁面內請求過多,也能夠考慮作必定的請求合併。

減小請求數據的大小:對於post請求,body能夠作gzip壓縮的,header也能夠作數據壓縮(不過只支持http 2.0)。
返回數據的body也能夠作gzip壓縮,body數據體積能夠縮小到原來的30%左右。(也能夠考慮壓縮返回的json數據的key數據的體積,尤爲是針對返回數據格式變化不大的狀況,支付寶聊天返回的數據用到了)
根據用戶的當前的網絡質量來判斷下載什麼質量的圖片(電商用的比較多)



文/maat紅飛(簡書做者) 原文連接:http://www.jianshu.com/p/89f19d67b348 著做權歸做者全部,轉載請聯繫做者得到受權,並標註「簡書做者」。
相關文章
相關標籤/搜索