android常用的必備基礎知識

發表時間:2019-01-04  投稿人:余瑛   部門:行政        編輯:    點擊量:1927  

首先從四大組件說起: 
Activity: 
生命周期: 
activity三種狀態:運行(運行在最前端)、停止(不可見,完全被覆蓋)、暫停(可見,但前端還有其他activity) 
生命周期相關的方法:onCreate-onStart-onResume-onPause-onStop-onDestory-onRestart 
切換時如果要保存數據, 可以重寫: onSaveInstanceState(); 
恢復數據時, 重寫: onRestoreInstanceState(); 
啟動模式: 
1.standard:默認的,每次調用startActivity()啟動時都會創建一個新的activity放在棧頂 
2.singleTop:啟動Activity時,指定Activity不在任務棧棧頂就創建,如在棧頂,則不會創建,會調用onNewInstance(),復用已經存在的實例。 
3.singleTask:在任務棧里面只允許一個實例,如果啟動activity不存在就創建,如果存在直接跳轉到指定Activity所在位置。 
4.singleInstance:開啟一個新的任務棧來存放這個Activity的實例,此模式開啟的Activity是運行在自己單獨的任務棧中的。

2.BroadcastReceiver廣播接收者 
有序廣播用過調用abortBroadcast()方法來中斷,接收者之間可以傳遞數據 
動態注冊廣播register,取消unregister 
廣播接收者打開Activity,需要設置一下Intent.FLAG_ACTIVITY_NEW_TASK 
應為廣播接收者是沒有Activity任務棧的 
sendOrderBroadcast()發送有序廣播 
1)靜態注冊:在AndroidManifest.xml注冊,android不能自動銷毀廣播接收器,也就是說當應用程序關閉后,還是會接收廣播。 
2)動態注冊:在代碼中通過registerReceiver()手工注冊.當程序關閉時,該接收器也會隨之銷毀。當然,也可手工調用unregisterReceiver()進行銷毀。

3.Service服務 
Service中的生命周期方法(Context調用執行): 
1)startService() 如果沒創建就先onCreate()再startCommand(), 如果已創建就只執行startCommand(); 
2)stopService() 執行onDestroy() 
3)bindService() 如果沒有創建就先onCreate()再onBind() 
4)unbindService() 如果服務是在綁定時啟動的, 先執行onUnbind()再執行onDestroy(). 如果服務在綁定前已啟動, 那么只執行onUnbind(); 
3、開啟服務的2種方式 
2種不同開啟方式的區別: 
1)startService: 
開啟服務,服務一旦開啟,就長期就后臺運行,即使調用者退出來,服務還會長期運行; 
資源不足時,被殺死,資源足夠時,又會復活; 
2)bindService: 
綁定服務,綁定服務的生命周期會跟調用者關聯起來,調用者退出,服務也會跟著銷毀; 
通過綁定服務,可以間接的調用服務里面的方法(onBind返回IBinder); 
4、服務混合調用生命周期 
一般的調用順序: 
①、start -> stop 開啟 –> 結束 
②、bind -> unbind 綁定(服務開啟) -> 解綁(服務結束) 
混合調用: 
①、start –> bind -> stop->unbind->ondestroy 通常不會使用這種模式 
開啟 –> 綁定 –> 結束(服務停不了)->解除綁定(服務才可停掉) 
②、start –> bind -> unbind -> stop 經常使用 
開啟 –> 綁定 –> 解綁(服務繼續運行)-> stop(不用時,再停止服務) 
這樣保證了服務長期后臺運行,又可以調用服務中的方法

4、內容提供者 
這個問的非常少,但是一旦問道還是要知道怎么回事的。 
ContentProvider: 
在數據庫中有對應的增刪改查的方法,如果要讓別的應用程序訪問,需要有一個路徑uri 
通過content:路徑對外暴露,uri寫法:content://主機名/表名 
1)ContentProvider:內容提供者 
把一個應用程序的私有數據(如數據庫)信息暴露給別的應用程序,讓別的應用程序可以訪問; 
在數據庫中有對應的增刪改查的方法,如果要讓別的應用程序訪問,需要有一個路徑uri: 
通過content:// 路徑對外暴露,uri寫法:content://主機名/表名 
2)ContentResolver:內容解析者 
根據內容提供者的路徑,對數據進行操作(crud); 
3)ContentObserver:內容觀察者 
可以理解成android系統包裝好的回調,數據發送變化時,會執行回調中的方法; 
ContentResolver發送通知,ContentObserver監聽通知; 
當A的數據發生變化的時候,A就會顯示的通知一個內容觀察者,不指定觀察者,就會發消息給一個路徑 
ContentProvider和sql的實現上的區別: 
1,Contentprovider屏蔽了數據存儲的細節,內部實現對用戶完全透明,用戶只需要i、關心操作數據的uri就可以了,ContentProvider可以實現不同app之間的共享 
2,Sql也有增刪改查的方法,但是sql只能查詢本應用下的數據庫。而Comtentprovider還可以去增刪改查本地文件.xml文件的讀取等

異步加載網絡數據(AsyncTask) 
AsyncTask類,這個類中的任務是運行在后臺線程中的,并可以將結果放在UI線程中去處理 
它定義了三種泛型,分別是Params、Progress和Result,分別表示請求的參數、任務的進度和獲取的結果數據 
執行過程:1.onPreExecte():執行在主線程。這步操作是用于準備好任務的,作為任務加載的準備工作。建議在這個方法中彈出一個提示框。 
2.doInBackground():執行在子線程中。需要將請求的參數傳遞進來,發送給服務器,并將獲取到的數據返回,數據回傳給下一步的onProgressUpdate()中進行進度更新。 
3.onProgressUpdate():進度更新 
4.onPostExectue():界面更新 
實現原理: 
1.線程池的創建:默認創建一個線程池ThreadPoolExecutor,并默認創建出5個線程放入到線程池中,最多可放128個線程,且這個線程池是公共的唯一一份。 
2.任務的執行:執行run方法,執行完run方法后,會調用scheduleNext()不斷的從雙端隊列中輪詢,獲取下一個任務并繼續放到一個子線程中執行,直到異步任務執行完畢。 
3.消息的處理:在AsyncTask中維護了一個InternalHandler的類,這個類是繼承Handler的,獲取的數據是通過handler進行處理和發送的。其中handleMessage方法中,將消息傳遞給onProgressUpdate()進行進度的更新,也可以將結果發送到主線程中,進行界面的更新了。

LisView優化: 
ListView如何提高其效率 
1.復用ContentView 
2.自定義靜態類viewholder 
3.使用分頁加載 
4.使用weakReference引用ImageView對象 
listView可以顯示多種類型的條目: 
Listview顯示的每個條目都是通過baseAdapter的getView來展示的,理論上我們完全可以讓每個條目都是不同類型的view,除此之外adapter還提供了getViewTypeCount()和getItemViewType(int position)兩個方法。在getview方法中我們可以根據不同的viewtype加載不同的布局文件。

ListView中的數據分批及分頁加載: 
設置ListView的滾動監聽器:setOnScrollListener 
1.在監聽器中有兩個方法:滾動狀態發生變化的方法onScrollStateChanged和listView被滾動時調用的方法 
2.在滾動狀態發生改變的方法有三個狀態:觸摸滑動、慣性滾動、靜止狀態 
3.對不同的狀態進行處理:分批加載數據,只關心靜止狀態:如果最后一個可見條目就是數據適

配器里的最后一個,此時可加載更多的數據。

ListView圖片優化 
1.不要直接拿路徑去循環decodeFile();使用Option保存圖片大小,不要加載圖片到內存 
2.拿到圖片一定要經過邊界壓縮 
3.在listView去圖片是也不要直接拿個路徑去取圖片,而是以WeakReference代替強引用 
4.在getView中做圖片轉換時,產生的中間變量一定及時釋放 
異步加載圖片基本思想: 
1.先從內存緩存中獲取圖片顯示(內存緩沖) 
2.獲取不到的話從SD卡里獲取(SD卡緩存) 
3.都獲取不到的話從網絡下載圖片并保存到SD卡同時加入內存并顯示 
圖片錯位問題: 
本質是因為listView使用了緩存convertView。可見則顯示,不可見則不顯示。在imageLoader里有個imageViews的map對象,用于保存當前顯示區域圖像對應的url集,在顯示前判斷處理一下即可。 
內存緩沖機制: 
首先限制內存圖片緩沖的堆內存大小,每次有圖片往緩存里加時判斷是否超過限制大小,超過的話取最少使用的圖片并將其移除 
二級緩存:從LinkedHashMap里移除的緩存放在SoftReference里 
LinkedHashMap緩存在沒有移除出去之前是不會被GC回收的,而SoftRefernce里的圖片緩存在沒有其他引用保存時隨時都會被GC回收。 
ListView的其他優化: 
1.盡量避免在BaseAdapter中使用static來定義全局靜態變量 
2.盡量使用getApplicationContext 
3.盡量避免在ListView適配器中使用線程

ScrollView和ListView的沖突問題: 
在ScrollView添加ListView會導致listView控件顯示不全,兩個控件的滾動事件沖突導致。通過listView中的item數量去計算listView的顯示高度。

熟悉XML/Json解析數據,以及數據存儲方式 
數據存儲方式包括:File、SharedPreference、XML/Json、數據庫、網絡 
XML/Json解析數據

Handler機制和事件分發機制 
Message:消息,由MessageQueue統一列隊,終由Handler處理 
Handler:處理者,負責Message發送消息及處理。Handler通過與Looper進行溝通,從而使用Handler時,需要實現handlerMessage方法來對特定的Message進行處理 
MessageQuene:消息隊列,用來存放Handler發送過來的消息,按照先入先出規則執行。 
Looper:消息泵,不斷從MessageQueue中取出Message執行。因此,一個線程中的MessaeQueue需要一個Looper進行管理。 
耗時操作,比如網絡請求、文件處理、多媒體處理需要在子線程中操作,手機顯示的刷新頻率60Hz,一秒鐘刷新60次,沒16.7毫秒刷新一次,為了不丟幀,主線程處理代碼最好不要超過16毫秒。 
Handler消息機制 
在主線程中 Android 默認已經調用了 Looper.preper()方法,調用該方法的目的是在 Looper 中創建MessageQueue 成員變量并把 Looper 對象綁定到當前線程中。當調用 Handler 的 sendMessage(對象)方法的時 
候就將 Message 對象添加到了 Looper 創建的 MessageQueue 隊列中,同時給 Message 指定了 target 對象,其實這個 target 對象就是 Handler 對象。主線程默認執行了 Looper.looper()方法,該方法從 Looper 的成員變量MessageQueue 中取出 Message,然后調用 Message 的 target 對象的 handleMessage()方法。這樣就完成了整個消息機制。

事件分發機制 
onTouch和onTouchEvent 
這兩個方法都是在View的dispathTouchEvent中調用的,onTouch優先于onTouchEvent執行,在onTouch中返回true將事件消費掉,onTouchEvent將不會再執行。 
依次下發,下發的過程是調用View的dispatchTouchEvent方法實現的。簡單來說,就是viewgroup遍歷包含者的子view,調用每個View的dispatchTouchEvent方法,而當子view為viewgroup時,又會調用viewgroup的dispatchTouchEvent方法繼續調用內部的view的dispatchTouchEvent方法。 
touch事件分發有兩個主角:viewGroup和view。 
viewgroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent 
view包含dispatchTouchEvent、onTouchEvent兩個 
onInterceptTouchEvent有兩個作用:1.攔截down事件的分發 2.中止Up和move事件向目標view傳遞,使得目標view所在的viewgroup捕獲up和move事件 
觸摸事件是有action_Down、Action_Move、Action_Up組成,其中一次完整的觸 
摸事件中,Down和Up都只有一個,Move有若干個,可以為0個。

自定義控件 
1.自定義組合控件 
聲明一個view對象,繼承相對布局,或者線性布局或者其他的viewGroup 
在自定義的view對象里面重寫它的構造方法,在構造方法里面把布局初始化 
根據業務需要添加一些api方法,擴展自定義組合控件 
在布局文件里面可以自定義一些屬性 
聲明自定義屬性的命名空間 
在res目錄下的values目錄下創建attrs.xml的文件聲明我們寫的屬性 
在布局文件中寫自定義的屬性 
使用自定義的屬性 
2.view的繪制過程 
mesarue()過程:為整個view樹計算實際的大小 
view : mMeasuredHeight高和mMeasureWidth()寬 
viewGroup:重寫onMeasure()方法,遍歷measure()過程,通過調用父類ViewGroup類里面的measureChildWithMargins()方法去實現 
layout()根據子視圖的大小以及布局參數將view樹放到合適的位置上 
view: 設置該view視圖位于父視圖的坐標抽即mLeft,mTop,mLeft,mBottom,回調onLayout方法 
viewGroup:遍歷每個子視圖childView,調用該子視圖的layout()方法去設置它的坐標值 
3.draw()繪制過程 
viewRoot對象的performTraversals()方法調用draw()方法發起繪制view樹不需要全部重繪只需要繪制需要繪制的部分

這個控件中,父視圖使用unspecified dimensions來將它的每個子視圖都測量一次來算出它們到底需要多大尺寸,而這些子視圖沒被限制的尺寸的和太大或太小,所以會用精確數值再次調用measure()(也就是說,如果子視圖不滿意它們獲得的區域大小,那么父視圖將會干涉并設置第二次測量規則)。其中measure()方法會調用onMeasure()方法。 
代碼中,由于把每行剩余空間重新分配,會調用了requestLayout()方法,這個方法又會導致measure()和onLayout()方法的再次調用。 
最后你會發現 onMeasure()方法調用了 1次*2*2=4次 onLayout()方法調用了 1次*2 =2次

談一談android的安全機制 
1,在安卓是有文件權限的控制,在清單文件聲明 
2,每個android中每個應用都有自己的/data/data/包名 文件夾,該文件夾只能該應用訪問,而其他應用則無權訪問 
3,Android的代碼混淆保護了開發者的勞動成果

多線程斷點續傳下載 
多線程下載的實現過程: 
1,首先得到下載文件的長度,然后設置本地文件的長度。 
HttpURLConnection.getContentLength(); 
RandomAccessFile file = new RandomAccessFile(“FeiQ.exe”,”rwd”); 
file.setLength(filesize); //設置本地文件的長度 
2,根據文件長度和線程數計算每條線程下載的數據長度和下載位置。 
如:文件的長度為6M,線程數為3,那么,每條線程下載的數據長度為2M,每條線程開始下載的位置如圖所示。 
3,使用Http的Range頭字段指定每條線程從文件的什么位置開始下載,下載到什么位置為止. 
如:指定從文件的2M位置開始下載,下載到位置4M為止,代碼如下: 
HttpURLConnection.setRequestProperty(“Range”, “bytes=2097152-4194303”); 
4,保存文件 
使用RandomAccessFile類指定每條線程從本地文件的什么位置開始寫入數據。 
RandomAccessFile threadfile = new RandomAccessFile(“QQWubiSetup.exe “,”rwd”); 
threadfile.seek(2097152); //從文件的什么位置開始寫入數據

數據庫操作 
在Android系統,提供了一個SQLiteOpenHelper抽象類,該類用于對數據庫版本進行管理.該類中常用的方法: 
onCreate 數據庫創建時執行(第一次連接獲取數據庫對象時執行) 
onUpgrade 數據庫更新時執行(版本號改變時執行) 
onOpen 數據庫每次打開時執行(每次打開數據庫時調用,在 onCreate,onUpgrade方法之后) 
Android提供了一個名為SQLiteDatabase的類,該類封裝了一些操作數據庫的API,使用該類可以完成對數據進行添加(Create)、查詢(Retrieve)、更新(Update)和刪除(Delete)操作(這些操作簡稱為CRUD)。對SQLiteDatabase的學習,我們應該重點掌握execSQL()和rawQuery()方法。 execSQL()方法可以執行insert、delete、update和CREATE TABLE之類有更改行為的SQL語句; rawQuery()方法用于執行select語句。

aidl:接口聲明語言,跨進程通信 
bindService有一個ServiceConnec接口覆寫onServiceConnect方法,把第二個參數IBinder對象強制轉換為aidl中的接口類

- 寫服務類

1. 定義一個接口文件, 聲明一個方法forwardPayMoney方法, 把后綴名修改為.aidl, 并且把修飾詞去掉.

2. 在服務中定義一個內部類MyBinder, 繼承Stub類, 并且把抽象方法forwardPayMoney實現了.

3. 在onBind方法中把第二部定義的內部類對象MyBinder返回.

- 另一個程序的Activity

4. 使用隱式的方式綁定服務, 傳遞過去一個連接橋對象.

5. 把服務程序中的aidl文件拷貝當前工程中, 包名要保留一致.

6. 在連接橋對象中的onServiceConnected方法中, 把IBinder對象轉換成aidl接口對象

mAlipayRemoteService = Stub.asInterface(service);

7. 使用aidl接口對象, 調用接口中的抽象方法, 實際上會調用到遠程服務中內部類中的forwardPayMoney方法.
android中的動畫 
1.View Animation: 視圖動畫/ Frame動畫/屬性動畫:這種動畫是可擴展的,

圖片處理框架 
imageLoader:imageLoaderEngine,cache及 
imageDownloader,imageDecoder,bitmaodisplayer,bitmapProcessor五大模塊 
簡單來說就是imageLoader收到加載及顯示圖片的任務,并將它交給 
imageLoaderEngine,ImageLoaderEngine分發任務到具體線程池去執行,任務通過cache及imageDownloder獲取圖片。 
優點:1,支持下載監聽2,可以在view滾動中暫停圖片加載3.默認實現多種內存緩存算法4.支持本地緩存文件名規則定義 
picasso 
這個庫分為dispatcher/requestHandler及Downloader,picassoDrawable等模塊 
picasso收到加載及顯示圖片的任務,創建Request并將他交給 
Dispatcher,dispatcher分發任務到具體的requesthandler,任務memoryCache及Handler獲取圖片,圖片獲取成功后通過picassoDrawable顯示到Target中 
優點:1.自帶統計監控功能2.支持優先級處理3.支持延遲加載4.支持飛行模式、并發線程數根據網絡類型而變

圖片緩存處理: 
LruCache類:主要算法原理是把最近使用的對象用強引用存儲在在LinkedHashMap中,并且把最近最少使用的對象在緩存值達到預定值之前從內存中移除。

內存溢出原因: 
1.資源釋放問題 
2.對象內存過大 
3.static 
4.線程導致內存溢出

圖片占用進程的內存算法簡介 
android中處理圖片的基礎類是Bitmap,顧名思義,就是位圖。占用內存的算法如下: 
圖片的width*height*Config。 
如果Config設置為ARGB_8888,那么上面的Config就是4。一張480*320的圖片占用的內存就是480*320*4 byte。 
在默認情況下android進程的內存占用量為16M,因為Bitmap除了Java中持有數據外,底層C++的 skia圖形庫還會持有一個SKBitmap對象,因此一般圖片占用內存推薦大小應該不超過8M。這個可以調整,編譯源代碼時可以設置參數。

Activity的啟動與生命周期的監控 
應用程序被開啟后,是需要開啟并創建Activity,加載相應的view,從而展示出應用程序 
1、Activity是通過startActivity開啟起來的,startActivity是由有Context調用的,其具體的實現類是ContextImpl 
在ContextImpl中的startActivity方法中,會調用ActivityThread的相關方法【mMainThread.getInstrumentation().execStartActivity()】;可以追溯到Instrumentation這個類,其中的execStartActivity()的方法中實現了startActivity的調用:ActivityManagerNative.getDefault().startActivity,由此可以看出是底層進行處理。 
2、ActivityMonitor監控Activity 
當Activity實例創建的時候,就會給Activity配置一個監視器ActivityMonitor,監控Activity的聲明周期: 
在Instrumentation的execStartActivity()的方法中,上來先判斷ActivityMonitor是否為null:在第一次開啟Activity的時候,ActivityMonitor還是null的,就會調用ActivityManagerNative.getDefault().startActivity(…..),是在操作native底層的信息,從而執行startActivity,再去開啟一個Activity。 
簡單來說,就是通過調用JNI,調用startActivity方法,開啟Activity;創建好了之后,隨即也創建好了Activity的監視器ActivityMonitor 
3、在ActivityMonitor中就有Activity各種生命周期的監控 
①、在newActivity方法中: 
可以通過拿到Activity的字節碼,創建一個Activity,并將這個Activity返回 
還會調用attach方法,傳入ActivityThread的線程 
②、在各種生命周期的方法中,調用activity的各自的生命周期的方法

總結: 
1、通過PackageManagerService將所有用到的資源加載進內存中 
2、在Launcher中,將view等控件加載到ViewGroup中,點擊每個item會有相應的操作 
3、在公開的文檔中是找不到具體調用startActivity的類的,而是由系統完成調用的,實現了Activity的啟動
實際就是通過Context的實現類ContextImpl進行調用的,一步步轉到底層(ActivityManagerNative)實現調用 
4、另一個重要的類就是ActivityMonitor,監控Activity生命周期的;在其newActivity方法中創建了Activity,并調用了attach方法; 
也就是說當一個Activity被創建的時候,就會綁定一個ActivityMonitor,用來監控Activity的生命周期
 

青海快3未出号