Android性能優化(高級)
-
簡述Android的系統架構?
- android的系統架構從下往上分為Linux內核層,運行庫,應用程序框架層和應用程序層。
-
如何對Android應用進行性能分析;
- 使用ddms工具中的traceview,heap,allocation tracker工具。traceview是Android平臺特有的數據采集和分析工具,可以用來分析耗時操作等。heap視圖工具可以幫助我們檢查代碼中是否存在有造成內存泄漏的地方,allocation tracker工具是內存分配跟蹤工具。
-
什么情況下會導致內存泄露;
- Android的虛擬機是基于寄存器的Dalvik,它的最大堆內存是16M,部分機器是24M,因此能利用的內存空間是有限的,一旦超出就會造成OutOfMemory異常。
- 內存泄漏的幾點原因:1)資源釋放問題,程序代碼的問題,長期保持某些資源,如context,cursor,io流的引用,資源得不到釋放就造成內存泄漏。2)對象內存過大問題,保存了多個耗用內存過大的對象(如bitmap,xml文件),造成內存超出限制。3)static關鍵字的使用,static在Java中,當用來修飾成員變量的時候,那么該變量就屬于該類,而不是該類的實例,因此用static修飾的變量,生命周期很長。針對static的解決方案:盡量避免static成員變量引用資源耗費過多的實例,比如context,context盡量使用ApplicationContext,因為Application的context的生命周期比較長,引用他不會出現內存泄漏的問題。4)線程導致內存泄漏,線程的生命周期不可控。
-
OOM是什么?應如何避免?
內存溢出,要避免OOM異常需要先知道是什么原因導致的異常,
-
圖片過大導致OOM,在Android中用bitmap很容易導致內存溢出,比如報如下錯誤:
Java.lang.OutOfMemoryError : bitmap size exceeds VM budget。-
解決方法:
//1)等比例縮小圖片 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)對圖片采用弱引用,及時的進行recycle()操作。 SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap); if(bitmap != null){ if(bitmap.get() != null && !bitmap.get().isRecycled()){ bitmap.get().recycle(); bitmap = null; } } 3)使用圖片加載框架處理圖片。
-
-
界面切換的時候導致OOM,一般情況下,開發中都會禁止橫屏,一旦橫豎屏切換的多了,activity的生命周期就會重新銷毀然后創建。切換的次數多了,就會導致OOM。這種問題沒有固定的解決方案,可以從一下幾方面著手分析,
-
1)看頁面布局中有沒有大的圖片,如背景圖之類的,去除xml文件中相關設置,改在代碼中設置(放在onCreate()方法中)
Drawable drawable = getResources().getDrawable(R.drawable.id); ImageView imageView = new ImageView(this); imageView.setBackgroundDrawable(drawable); //在activity destory的時候注意,要drawable.setCallback(null),防止得不到及時的釋放。
-
查新數據庫時沒有關閉游標。
構造adapter時,沒有使用緩存convertView,使用convertView的好處:
當convertView 為空時,用setTag()方法為每個View 綁定一個存放控件的ViewHolder 對象。當convertView 不為空,重復利用已經創建的view 的時候,使用getTag()方法獲取綁定的ViewHolder 對象,這樣就避免了findViewById 對控件的層層查詢,而是快速定位到控件。bitmap對象不再使用的時候調用recycle()方法釋放內存。
使用廣播沒有注銷的時候也會產生OOM。
-
ANR是什么? 應如何避免和解決?
- application not responding 程序無響應。ANR一般有三種類型: activity 5秒,broadcastReceiver10秒,services20秒。超時的原因一般有兩種:1)當前的事件沒有機會得到處理(UI線程正在處理前一個事件沒有及時完成或者looper被某種原因阻塞?。?)當前的事件正在處理,但沒有及時完成,UI線程盡量只做UI相關的工作,耗時操作(數據庫操作,io流,連接網絡或者其他可能阻礙UI線程的操作)放入單獨的線程處理,盡量用handler來處理UI thread和thread之間的交互。
-
Android中線程間通信有那幾種方式?
- 共享內存(變量),文件,數據庫,handler,Java中wait(),notify(),notifyAll()。
-
線程和進程之間的區別?
- 一個應用程序至少有一個進程,一個進程至少有一條線程,一個線程可以創建和撤銷另一個線程,同一個進程中的多個線程可以并發執行。從邏輯角度講,多線程的意義在于一個應用程序中,有多個執行部分可以同時執行,但操作系統并沒有將多個線程看成多個獨立的應用,來實現進程的調度,管理和資源分配。
android的屏幕適配 :
-
屏幕適配的方式有哪些?
- 適配方式有:權重weight適配,layout適配,代碼使配,dp適配(layout中定義布局設置的參數使用dp),dimens適配。
- 在values-1280x720目錄中的dimens。xml文件中定義同樣的尺寸名稱,但是使用不同的尺寸,當在布局文件中使用長或寬單位時,用@dimens/width來定義。如果在values-1280x720中放置了dimens常量,一定要記得將該常量的對應值在values目錄中的dimens.xml中也放一份,因為該文件是默認配置,當用戶的手機不是1280*720的時候,系統應用用的是默認values目錄中的dimens.xml。
-
屏幕適配的處理技巧?
- 在分辨率大小不同的問題上,推薦使用權重weight適配,一般應用于線性布局中。
- 盡量使用線性布局,相對布局,如果屏幕放不下數據,可以使用ScrollView來拖動。
- 盡量使用9-patch圖片,可以自動的根據圖片上面顯示的內容被拉伸和收縮。
AIDL
-
什么是ALDI?應如何使用?
- AIDL是android interface definition language 意思是Android接口定義語言。使用aidl可以幫助我們發布以及調用遠程服務,實現跨進程通信。
-
AIDL如何工作,能處理哪些類型數據?
- 編譯器可以通過aidl文件生成一段代碼,通過預先定義的接口達到兩個進程內部通信進程跨進程對象訪問的目的,需要完成兩件事:一是引入aidl的相關類;二是調用aidl產生的class文件,理論上,參數可以傳遞基本數據類型和String,還有就是Bundle的派生類。
android 的事件處理 :
handler消息機制:
Android中主線程主要是用來創建,更新UI的,而耗時操作,網絡請求等則需要在子線程中操作。而handler主要接受子線程發送的數據,并用該數據來配合主線程更新UI,handler運行在主線程中,他和子線程通過message對象來傳遞數據(子線程通過sendMessage()方法來發送消息,數據),將子線程發送來的這些消息放入到主線程中,配合主線程來更新UI。
handleThread,Looper,MessageQueue和Message的關系:handlerThread負責將需要傳遞的信息封裝成Message對象,通過handler對象的sendMesage()方法將消息傳遞給looper,在有looper將message放入messageQueue消息隊列中,當looper對象看見MessageQueue中含有Message時,就將其廣播出去,該handler對象手到該消息之后,調用相應的handler對象的handlerMessage()方法對其進行處理。
-
handler消息機制的底層簡單分析:
- 首先是messageQueue和Looper的創建:當系統啟動的時候,先加載activityThread這個類,在這個類中的main方法會調用Looper.prepareMainLooper()這個方法,來創建一個Looper對象,Looper對象就會通過ThreadLocal把他和當前線程綁定在一起,創建Looper的時候就創建了一個MessageQueue,MessageQueue是個final類型的成員變量。這樣就保證了一個Looper對應一個MessageQueue,所有的MessageQueue創建好了之后,就會一個線程對應唯一的messageQueue。然后MessageQueue在創建的時候通過JNI創建了一個NativeMessageQueue,他又創建了一個c++Looper,所以說Handler的底層是通過C++來實現的。MessageQueue中保存了一個int類型的成員變量mptr,他保存了NativeMessageQueue的指針,這樣就是了MessageQueue和NativeMessageQueue的對應。
- 接下來是從消息隊列中取消息:之后就會調用Looper.loop()來取消息,這里面有一個死循環,在這個死循環里存在著queue.next();的方法他是阻塞主線程的,它實際上就是調用了NativeMessageQueue去C++層取消息,如果取出來這個loop就去執行,沒取出來就會阻塞在這里不去執行,這樣就能是界面能夠停留而不至于代碼執行完界面就跳出;取出消息后調用handler.dispatchMessage()來分發消息,message這里面有一個回調,handler在創建的時候有一個回調,如果兩個回調都為空的那么直接調用handleMessage()來處理消息,這就是取消息。
- 最后就是存消息:也就是向消息隊列中發送消息,不管是sendMessage還是sendMessageDelaty等他們調用都是sendMessageAtTime(),在這個方法里面他實際調用的是messqueue.enqueuemessage()這里面實際上就是拿著當前消息要執行的時間進行排序,然后就會通過消息隊列保存起來,這里面有一個message.next()他們都可以通過這個方法一條指向下一條,這樣一條一條連起來,當有消息需要馬上執行就會調用nativewake(),這個方法就會把Looper.looper()的queue.next()喚醒就能取出消息,他就可以開始工作.
事件分發機制
-
OnTouchEvent的事件傳遞機制:
- 當手指觸摸到屏幕時,系統會調用相應的view的onTouchEvent,傳入一系列的action,那么首先觸發的是activity的dispatchTouchEvent,然后觸發activity的onUserInteraction,在觸Layout的dispatchTouchEvent,然后觸發Layout的onInterceptTouchEvent.
如果dispatchTouchEvent:
事件由此分發,通常會調用super. DispatchTouchEvent.
如果onInterceptTouchEvent(攔截事件):
返回true:表示事件被攔截會傳遞給自己的onTouchEvent處理,
返回false:不進行攔截,會將事件傳遞給下一個view的dispatchTouchEvent()進行判斷.
如果onTouchEvent:
返回結果為true:表示事件由自己處理,消費.
返回結果為false:表示當前事件自己不做處理,交給父view的onTouchEvent處理.
view的繪制流程:
參考博文:http://www.lxweimin.com/p/5a71014e7b1b
-
子線程發消息到主線程更新UI,處理handler,asyncTask還有什么;
-
用activity對象的runOnUiThread()在線程中更新UI。
new Thread() { @Override public void run() { super.run(); //這兒是耗時操作,完成之后更新ui. runOnUiThread(new Runnable() { @Override public void run() { //更新ui ImageView.setImageBitmap(bitmap); } }); } }.start(); //如果是非上下文類中(activity),可以通過傳遞上下文實現調用; //Activity activity = (Activity) imageView.getContext() ; activity.runOnUiThread(new Runable() { @Override public void run() { imageView.setImageBitmap(bitmap); } });
-
-
子線程中能不能new handler,為什么?
- 不能,如果在子線程中直接new Handler() 會拋異常。
Android 中的動畫 :
-
動畫類型有幾種,特點和區別是什么?
- 屬性動畫,補間動畫;補間動畫只是顯示的位置變動,view的實際位置未改變,表現為view移動到其他地方,點擊事件仍在原處才能相應,而屬性動畫在控件移動后時間響應就在控件移動后本身進行處理。
-
如何修改Activity進入和退出的動畫;
- 通過兩種方式:1)通過定義activity的主題,2)通過復寫activity的overridePendingTransition(R.anim.fade,R.anim.hold)方法。
LRUCache的底層原理:
- 通過獲取內存的最大可用值,lrucache通過構造函數傳入緩存值,它是kb為單位,在不超出可使用內存的最大值的情況下,超出就會OOM,通過使用最大緩存值的1/8作為緩存的大小,重寫sizeOf()方法來返回每一張圖片的大小,這就是lurcache的是使用方法,那么lruchche為何這樣強大,原因是它的主要算法原理是將最近最少使用的對象用強引用存儲在LinkedHashMap中,并且將最近最少使用的對象在緩存值達到預設值之前從內存中移除,在過去經常使用一種非常流行的緩存技術實現,就是軟引用和弱引用,但現在不再使用了,因為在Android2.3之后。垃圾回收機制更容易傾向于回收持有軟引用和弱引用的對象,這就讓軟引用和弱引用顯得不可靠,另外在Android3,0之后,圖片的數據會存儲在本地內存中,因而無法用一種可預見的方式將其釋放,這就會潛在的造成應用程序內存溢出或者崩潰,而再有了lruCache這個功能之后,解決這些問題就不在難了。
JNI的調用過程:
- 安裝和下載cygwin,下載Android NDK.
- ndk項目中JNI接口的設計,
- 使用C/C++實現本地方法
- JNI生成動態鏈接庫.so文件
- 將動態鏈接庫復制到Java工程,在Java工程中調用,運行Java工程即可。
圖片加載框架picasso,glide,imageLoader,Fresco之間的區別:
-
共同的優點:
- 使用簡單--都可以通過一句代碼實現圖片的獲取和顯示。
- 可配置度高,自適應行性高--可根據系統性能初始化緩存配置,給句cpu核數確定最大并發數,根據網絡狀態變化來調整最大并發數,根據可用內存確定最大緩存大小,
- 多級緩存--每種框架至少有兩級緩存,可以提高圖片的加載速度。
- 支持多種數據源--網絡,本地,資源文件。
- 支持多種displayer--不僅支持imageView,同時支持多種view以及一些虛擬的imageview。
- 支持動畫。
imageLoader的設計模式:
* 一個強大的圖片加載框架,很好的處理了圖片加載的多線程,緩存,內存溢出等問題。多線程異步加載和顯示圖片(圖片來源于網絡,sd卡,assets文件夾,drawable文件夾,不能加載9patch圖片,可以加載視頻縮略圖)
* ImageLoader 收到加載及顯示圖片的任務,并將它交給 ImageLoaderEngine,ImageLoaderEngine 分發任務到具體線程池去執行,任務通過 Cache 及 ImageDownloader 獲取圖片,中間可能經過 BitmapProcessor 和 ImageDecoder 處理,最終轉換為Bitmap 交給 BitmapDisplayer 在 ImageAware 中顯示。
* imageloader的優點:
*
* 支持下載進度條監聽,支持在view的滾動中暫停圖片的加載,實現了多種內存緩存算法,支持本地緩存文件名規則定義。
* 支持監視加載的過程,可以暫停加載圖片,在經常使用的listview,GridView,可以設置滑動時暫停加載,停止滑動的時候加載圖片。
* 高度可定制化,可以根據自己的需求進行各種配置,(線程池,圖片下載器,內存緩存策略等)
* 支持圖片內存緩存,文件緩存
* 在網絡速度較慢的時候,還可以對圖片進行加載并設置下載監聽。
* 避免同一個uri加載過程中重復開啟任務加載
* 減少加載大圖片出現oom的情況。
* 不足:
*
* 不支持加載GIF圖片。
Picasso的設計模式:
* Picasso 收到加載及顯示圖片的任務,創建 Request 并將它交給 Dispatcher,Dispatcher 分發任務到具體 RequestHandler,任務通過 MemoryCache 及 Handler(數據獲取接口) 獲取圖片,圖片獲取成功后通過 PicassoDrawable 顯示到 Target 中。
* Picasso的優點:
*
* 自帶統計監控功能--支持圖片緩存使用的監控,包括已使用內存大小,節省的流量。
* 支持優先級處理。
* 支持延遲到圖片尺寸計算完成加載,
* 支持飛行模式,并發線程數根據網絡類型而變。
* 無本地緩存--不是說沒有本地緩存,而是Picasso自身沒有定義本地緩存的接口,默認使用http的本地緩存。
* 不足:
*
* 不支持加載GIF圖片,緩存之后的圖片沒有進行縮放
glide的設計模式:
* Glide 收到加載及顯示資源的任務,創建 Request 并將它交給RequestManager,Request 啟動 Engine 去數據源獲取資源(通過 Fetcher ),獲取到后 Transformation 處理后交給 Target。Glide 依賴于 DiskLRUCache、GifDecoder 等開源庫去完成本地緩存和 Gif 圖片解碼工作。
* glide的優點:
* 支持多種圖片緩存,GIF,webP,縮略圖,甚至是video。
* 支持優先級處理
* 支持velloy,okHttp.實際上imageloader。Picasso也支持velloy,OKHttp。
* 內存緩存的是處理之后的圖片,而不是原始圖片,節省內存大小。
fresco的優點:
* 支持流式,支持類似于網頁上的從模糊到清晰加載圖片,漸進式加載JPEG圖片。
* 圖片可以從任意的中心點顯示在imageView,而不僅僅是圖片的中心。
* 支持多幀動畫,GIF,webP.
* 缺點: 框架較大,影響apk的體積,使用較繁瑣。
網絡請求框架Volley 和Ok-http,android-async-http,retrofit的區別:
volley框架:
* google推出的異步網絡請求框架和圖片加載框架,適合數據量小,通信頻繁的網絡操作。
* 能夠使網絡通信更快,更簡單,拓展性更好一點,
* get,post網絡請求以及網絡圖像的高效率異步處理請求。
* 可以對網絡請求進行排序優先級管理。
* 支持網絡請求的緩存
* 多級別取消請求
* 使用volley可以簡化一些網絡通信的開發,不適合大數據和流媒體的網絡請求,例如上百兆文件,視頻上傳。
* volley在Android2.2以下使用httpClient,2.2以上使用的是httpUriConnection.
* Volley的使用:http://blog.csdn.net/sinyu890807/article/details/17482095
基本的使用方法: http://www.kwstu.com/ArticleView/kwstu_20144118313429
直接返回Object的話,用Gson/FastJson與Volley的結合:http://www.cnblogs.com/freexiaoyu/p/3955137.html
* Volley問題收錄:Volley的request默認回調到主線程中,如果有需求是要加載到sqlite等等仍需要在子線程中進行的操作 解決方案 :https://www.zhihu.com/question/36672622/answer/76003423
async-Http框架:
* 清晰地網絡請求回調
* 網絡請求使用線程池ThreadPool,限制并發資源使用情況
* get/post基于參數構建使用(RequestParams)
* 支持Multipart文件上傳,大數據上傳下載。
* 內置響應解析成json.
* 持久化cookie存儲,保存cookie到應用程序的sharedPreferences.
* 支持二進制文件,圖片的下載
* 使用的是httpClient
okhttp框架:
* OKhttp和retrofit都出自于Square公司,是高性能的http庫。
* OKhttp使用okio進行數據傳輸, 包含一般的get,post請求;基于http的文件,圖片上傳,加載;支持請求回調,直接返回對象,對象集合;支持session的保持。
* 支持spdy,http2.0,websocket,支持同步,異步,
* 封裝了線程池,數據轉換,參數使用,錯誤處理等;
* OKhttp使用教程:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html
retrofit框架:
* 出自于Square公司,是對OKhttp做了一層封裝。
* 支持Gson解析,retrofit已經在內部封裝了json解析
異步加載框架handler,asyncTask,RXJava :
-
異步加載框架之asyncTask:
- 需要重寫的四個方法:doInBackground(Params params)運行在后臺線程中;onPreExecute(),onProgressUpdate(progress),onPostExecute(result)這三個方法是運行在UI線程中。
- 使用aysncTack需要遵守的原則:task實例必須在UI線程中創建;execute方法必須在UI線程中調用;不要手動的調用那四個方法。
- asyncTask內部也是handler機制完成的,只不過Android提供了執行框架來提供線程池來執相應的任務,因為線程池的大小的問題,所以asyncTask值應該用來執行耗時較短的任務,比如HTTP請求,大規模的下載和數據庫的更改不適用于asyncTask,因為會導致線程池堵塞,沒有線程來執行其他任務,導致asyncTask根本執行不了。
-
rxjava框架:
- rxjava是一個異步操作庫,在JavaVM上使用可觀測的序列來組成異步的,基于事件的程序的庫,rxjava的優勢在于簡潔,隨著程序邏輯變得越來越復雜,rxJava確一直簡潔,能夠很大程度的提升代碼的閱讀性。他通過拓展的觀察者模式來實現的。rxjava有四個基本的概念:被觀察者Observable,觀察者Observer,訂閱事件subscribe,Observable和observer通過subscribe()來實現訂閱關系,從而Observable可以在需要的時候發出事件來通知Observer。
MVC和MVP的區別;
- MVC是model (模型) view (視圖) controller(控制器),view強依賴于model是MVC的主要問題,使用MVC,將業務邏輯抽離到controller中,讓view層專注于UI.
- MVC指的是model view controller,model著的是數據層,主要負責相關的業務邏輯,包括數據庫,網絡本地緩存等,view是指界面,主要負責UI相關的業務邏輯,包括布局界面,相關控件的顯示,controller是控制層,主要負責處理在對象狀態下調用model和view的方法實現數據和UI展示的相關邏輯.以MVC的設計模式的開發流程在一定程度上提高了代碼的可維護性,比如要修改UI界面的相關數據,就可以找到對應的處理層來處理代碼,但由于model和view的相關邏輯都寫在avtivity控制層了,這樣后期維護起來比較麻煩,因此就產生了一種新的設計模式,MVP,MVP指的是model view presenter,是在MVC的基礎上,將controller層該為了presenter層,它成為了model和view層之間交互的橋梁,他本身不具有任何的邏輯代碼,只是在對應的狀態下調用model和view層的方法來實現數據的相關邏輯和UI展示.
- 兩者的區別在于MVP中view不能直接的使用model層,它們之間的通信是通過Presenter(MVC中的Controller)來進行的,所有的交互都發生在Presenter內部,而在MVC中View會直接從Model中讀取數據而不是通過 Controller。
網絡請求get和post的區別;
- get是從服務器上獲取數據,post是向服務器上傳輸數據。
- get是把參數數據隊列加到提交表單的ACTION屬性所指的URL中,值和表單內各個字段一一對應,在URL中可以看到。post是通過HTTP post機制,將表單內各個字段與其內容放置在HTML HEADER內一起傳送到ACTION屬性所指的URL地址。用戶看不到這個過程。
- 對于get方式,服務器端用Request.QueryString獲取變量的值,對于post方式,服務器端用Request.Form獲取提交的數據。
- get傳送的數據量較小,不能大于2KB。post傳送的數據量較大,一般被默認為不受限制。但理論上,IIS4中最大量為80KB,IIS5中為100KB。
- get安全性非常低,post安全性較高。但是執行效率卻比Post方法好。
- get可以被瀏覽器緩存,post不可以。
- get請求是安全的,post不安全。
Android中常見的解決沖突的方案:
- 多個滑動必然會產生沖突,比如最常見的scrollView中嵌套listview,一般做法是計算出listview的總高度,這樣就不用去滑動listview了。再比如viewpager嵌套fragment,fragment中又有listview,這原本是由滑動沖突的,但是viewpager內部已經幫我們解決了這種沖突,如果需要自己解決的話,可以通過下面兩種方式解決:一是外部攔截法,外部攔截法是指在有點擊事件時都要經過父容器,那么在父容器時如果需要攔截就攔截自己處理,不需要則傳遞給下一層進行處理,主要的攔截是需要重寫onInterceptTouchEvent()方法。二是內部攔截法,是指父容器不攔截任何事件,所有事件都傳遞給子view,如果需要就直接消費掉,不需要在傳給父容器處理。需要重寫dispatchTouchEvent()方法。
- 參考博文:http://blog.csdn.net/lylodyf/article/details/52438997
簡述對Binder機制的理解。
- binder機制是用來實現不同進程之間的通信的。binder屬于一個驅動,工作在linux層,運行在內核態,它的操作完成是基于一段內存,因此我們開發的程序中對binder的調用都是通過系統的調用來完成的,binder的架構由服務端,binder驅動,客戶端三部分組成。處于對程序的安全性,可靠性,傳輸性能的考慮,Android選用binder來實現不同進程之間的通信。
談談對context的理解。
- 從字面意思理解是“上下文"的意思,從類的繼承關系來看,context是一個抽象的基類,它的實現子類有三種:application,activity和service。我們通過它來訪問當前包的資源(getResources,getAssets),啟動其他組件(activity,service,broadCastReceiver)以及得到各種服務(getSystemService)。換句話說,context提供了一個應用運行的環境,在context的大環境中,應用才可以訪問資源,才能完成和其他組件,服務交互。
如何縮減apk的大小,apk的打包;
- Android打包本身會對png圖片進行無損壓縮,但是純粹的進行無損壓縮并不會對apk的減小有任何的效果,因此可以可以通過tinypng進行有損壓縮。
- png換成jpg,如果圖片還大,在不降低畫質的情況下,可以在將jpg換成webp.
- 大圖縮小
- 覆蓋arr中一些默認的大圖,典型的是support-v4包中包含的一些可能用到的圖片,在實際中app是用不到的。并不是吧所有用不到的圖片替換掉,而是把幾張較大的圖片用1x1的圖片替換。
- 刪除armable-v7包中的so文件, armable-v7和armable文件夾可以只保留armable。
- 微信資源壓縮打包。采用微信壓縮方案。
- proground深度混淆代碼
- 深度清理代碼和資源,引入的無用圖片,相同的圖片,圖片可用著色方案替換,用shape替換等。
- 去除重復庫
- 表情包在線化
談談對Android NDK的理解。
- Android NDK是一系列工具的集合,可以快速的幫助開發者開發C/C++的動態庫,并能自動將so文件和Java應用一起打包成apk。
- ndk 提供了一份穩定的,功能有限的API頭文件聲明;
- NDK是Android平臺支持C開發的開端。
Android中進程間通訊的實現方式。
Bundle/Intent傳遞數據:可傳遞基本類型,String,實現了Serializable或Parcellable接口的數據結構。Serializable是Java的序列化方法,Parcellable是Android的序列化方法,前者代碼量少(僅一句),但I/O開銷較大,一般用于輸出到磁盤或網卡;后者實現代碼多,效率高,一般用戶內存間序列化和反序列化傳輸。
文件共享:對同一個文件先后寫讀,從而實現傳輸,Linux機制下,可以對文件并發寫,所以要注意同步。順便一提,Windows下不支持并發讀或寫。
Messenger:Messenger是基于AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連接,維護一個Handler來創建Messenger,在onBind時返回Messenger的binder。
雙方用Messenger來發送數據,用Handler來處理數據。Messenger處理數據依靠Handler,所以是串行的,也就是說,Handler接到多個message時,就要排隊依次處理。AIDL:AIDL通過定義服務端暴露的接口,以提供給客戶端來調用,AIDL使服務器可以并行處理,而Messenger封裝了AIDL之后只能串行運行,所以Messenger一般用作消息傳遞。
通過編寫aidl文件來設計想要暴露的接口,編譯后會自動生成響應的java文件,服務器將接口的具體實現寫在Stub中,用iBinder對象傳遞給客戶端,客戶端bindService的時候,用asInterface的形式將iBinder還原成接口,再調用其中的方法。ContentProvider:系統四大組件之一,底層也是Binder實現,主要用來為其他APP提供數據,可以說天生就是為進程通信而生的。自己實現一個ContentProvider需要實現6個方法,其中onCreate是主線程中回調的,其他方法是運行在Binder之中的。自定義的ContentProvider注冊時要提供authorities屬性,應用需要訪問的時候將屬性包裝成Uri.parse("content://authorities")。還可以設置permission,readPermission,writePermission來設置權限。 ContentProvider有query,delete,insert等方法,看起來貌似是一個數據庫管理類,但其實可以用文件,內存數據等等一切來充當數據源,query返回的是一個Cursor,可以自定義繼承AbstractCursor的類來實現。
Socket:學過計算機網絡的對Socket不陌生,所以不需要詳細講述。只需要注意,Android不允許在主線程中請求網絡,而且請求網絡必須要注意聲明相應的permission。然后,在服務器中定義ServerSocket來監聽端口,客戶端使用Socket來請求端口,連通后就可以進行通信。
實現一個自定義view的基本流程;
- 自定義view的屬性:在res/values/下建立一個attrs.xml文件,在里面定義我們的屬性和聲明我們的整個樣式。在xml文件中一定要引入命名空間。
- 在view的構造方法中獲取到我們的自定義屬性
- 重寫onMersure()方法
- 重寫onDraw()方法
- 參考博文:http://blog.csdn.net/lmj623565791/article/details/24252901/
幾種常見的設計模式;
單例模式:
-
單例模式是確保某個類只有一個實例,有懶漢式和餓漢式,
* 懶漢式,首先得私有化構造函數,防止類在外部被實例化,接下來就是書寫Singleton類型的getInstance()靜態的方法,避免線程不安全可以再靜態方法上加鎖synchronized.以下是線程安全的懶漢式的設計模式. public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } * 餓漢式是在類一加載的時候就直接進行了實例化,本身就是線程安全的. //餓漢式單例類.在類初始化時,已經自行實例化 public class Singleton1 { private Singleton1() {} private static final Singleton1 single = new Singleton1(); //靜態工廠方法 public static Singleton1 getInstance() { return single; } }
什么時候使用單例模式?
* 當這個類的對象在多個地方創建的時候,使得內部的方法多次調用,但是我們希望只要一個對象操作這個方法,或者不希望多個地方同時調用這個方法,我們需要保持這個方法的單一性質,我們就用單利模式。
簡單的工廠類:
適配器模式:
談談你在實際項目中怎樣解決一個BUG;
- 異常附近多打印log信息
- 分析log日志,進行斷點調試,
- 調試不出來,上stack Overflow貼上異常信息,請加大牛
- 多看看代碼,從源碼中分析,查找相關信息。
- 網上搜索相關問題,解決方案,或尋求師傅幫忙。
怎樣對Android進行優化
- listview優化,圖片優化,內存優化,盡量不使用過多的靜態類static,數據庫使用完成之后,要記得關閉cursor。廣播使用完之后要注銷。
談談你對bitmap的理解,什么時候應該手動調用bitmap.recycle().
- bitmap是Android中經常使用的一個類,它代表一個圖片資源,bitmap消耗內存很嚴重,如果不注意優化代碼,經常會出現oom,優化方式通常有:使用緩存;壓縮圖片;及時回收。
- 至于什么時候使用是手動調用bitmap.recycle()方法,這個需要看具體場景了,原則是在不使用bitmap時,就要回收掉,需要注意的是,在Android2.3之前bitmap對象與像素數據是分開存放的,bitmap對象存在Java heap中而像素數據存儲在Native Memory中,這時黑有必要調用recycle回收內存,但是在2.3之后,bitmap對象和像素數據都是存在Heap中,通過GC就可以回收內存。
你一般在開發項目中都是用什么設計模式,如何來重構,優化你的代碼?
- 較為常用的是單例設計模式和工廠設計模式以及觀察者模式,一般需要保證對象在內存中的唯一性時需要使用到單例模式,例如對數據庫操作的sqliteOpenHelpter的對象,工廠模式主要是為創建對象提供過渡接口,以便將創建的對象的具體過程屏蔽隔離起來,達到提高靈活性的目的,觀察者模式定義對象間的一種一對多的依賴關系,當一個對象的裝填發生變化時,所有依賴于它的對象都得到通知并自動更新。
Android中第二次登陸實現自動登錄
- 這是一個實際的案例流程,前提條件是所有用戶相關的接口都走https,非用戶相關的列表類數據走http。
- 第一次登錄的時候getUserInfo的時候帶一個長效的token,該長效的token用來判斷用戶是否登錄和換取短的token;
- 把長效token保存到sharedPreferences中,
- 接口請求用長效的token換取短token,短token服務端可以根據你的接口最后一次請求作為標識,超時時間為一天
- 所有接口都用短效token
- 如果返回短效token失效,執行3步驟在直接標識當前接口,
- 如果長效token失效(用戶換設備或者超過兩周),提示用戶重新登錄。