2018.03.十二、Android知識點-Android篇

一、Activity相關:

一、Activity的生命週期

image


二、Activity的啓動模式以及使用場景

啓動模式javascript

  1. standard:默認的啓動模式,每次建立都會產生新的實例,誰啓動了該模式的Activity,該Activity就屬於啓動它的Activity的任務棧中
  2. singleTop:棧頂複用模式,若是新的activity已經位於棧頂,那麼這個Activity不會被重寫建立,同時它的onNewIntent(Intent intent)方法會被調用,經過此方法的參數咱們能夠去除當前請求的信息,該 Activity的實例不在該棧或者不在棧頂 時,其行爲同standard啓動模式
  3. singleTask:棧內複用模式,若是棧中存在這個Activity的實例就會複用這個Activity,無論它是否位於棧頂,複用時,會將它上面的Activity所有出棧,而且會回調該實例的onNewIntent方法。
  4. singleInstance:全局惟一模式,具有singleTask模式的全部特性外,與它的區別就是,這種模式下的Activity會單獨佔用一個Task棧,具備全局惟一性,即整個系統中就這麼一個實例,因爲棧內複用的特性,後續的請求均不會建立新的Activity實例,除非這個特殊的任務棧被銷燬了,當複用該實例 會回調onNewIntent方法

三、Activity的啓動過程(不要回答生命週期)

Activity 啓動流程圖

Activity的啓動過程 必須掌握的Activity啓動過程html

四、在Activity中如何保存/恢復狀態?

分別調用onSaveInstanceState(Bundle outState)和 
onRestoreInstanceState(Bundle outState)  2個方法保存和恢復狀態。
複製代碼

五、在Activity中如何保存/恢復狀態?

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

六、Activity上有Dialog的時候按Home鍵時的生命週期?

按Home鍵,再開啓activity. java

七、Application 和 Activity 的 Context 對象的區別

  • 一、生命週期不一樣,Application的context隨應用存在而存在,activity的context隨該activity的存在而存在。
  • 二、適用範圍不一樣,Application的context 不能用在 show dialog()、start activity()、Layout inflation().ativity 可使用。

二、Service相關

1. Service的startService(Intent)啓動方式

  • 使用這種start方式啓動的Service的生命週期以下: onCreate()--->onStartCommand()(onStart()方法已過期) ---> onDestory()
  • 若是服務已經開啓,不會重複的執行onCreate(), 而是會調用onStart()和onStartCommand()
  • 服務中止的時候調用 onDestory()。服務只會被中止一次。
  • 特色:一旦服務開啓跟調用者(開啓者)就沒有任何關係了。 開啓者退出了,開啓者掛了,服務還在後臺長期的運行。 開啓者不能調用服務裏面的方法。

2. 採用bind的方式開啓服務

  • 使用這種start方式啓動的Service的生命週期以下:onCreate() --->onBind()--->onunbind()--->onDestory()
  • bind的方式開啓服務,綁定服務,調用者掛了,服務也會跟着掛掉。 綁定者能夠調用服務裏面的方法

3.service和activity怎麼進行數據交互?

一種是使用broadcast,另外一種是使用bindService。android

  • 一、經過廣播:在service中發送廣播,在activity中建立一個BroadcastReceive()接收;
  • 二、bindService:activity經過Intent傳值給service,並建立ServiceConnection()對象,得到BindService.MyBind。

4.怎麼保證service不被殺死?

  • 1.onStartCommand方法,返回START_STICKY,當service因內存不足被kill,當內存又有的時候,service又被從新建立。
  • 2.提高service優先級,在AndroidManifest.xml文件中對於intent-filter能夠經過android:priority = "1000"這個屬性設置最高優先級,1000是最高值,若是數字越小則優先級越低
  • 三、提高service進程優先級
  • 四、service +broadcast 方式,就是當service走ondestory的時候,發送一個自定義的廣播,當收到廣播的時候,從新啓動service;
  • 五、兩個守護進程

三、Broadcast相關

一、Broadcast註冊方式與區別

  1. Manifest.xml中靜態註冊:
//new出上邊定義好的BroadcastReceiver
MyBroadCastReceiver yBroadCastReceiver = new MyBroadCastReceiver();

//實例化過濾器並設置要過濾的廣播  
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");

//註冊廣播   
myContext.registerReceiver(smsBroadCastReceiver,intentFilter, 
             "android.permission.RECEIVE_SMS", null);

複製代碼
  1. 代碼中動態註冊:

直接在Manifest.xml文件的節點中配置廣播接收者web

<receiver android:name=".MyBroadCastReceiver">  
            <!-- android:priority屬性是設置此接收者的優先級(從-1000到1000) -->
            <intent-filter android:priority="20">
            <actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>  
            </intent-filter>  
</receiver>

複製代碼

二、兩種註冊廣播的不一樣

  • 第一種不是常駐型廣播,也就是說廣播跟隨程序的生命週期。
  • 第二種是常駐型,也就是說當應用程序關閉後,若是有信息廣播來,程序也會被系統調用自動運行。

三、發送廣播的兩種方式

  • 無序廣播:全部的接收者都會接收事件,不能夠被攔截,不能夠被修改。
  • 有序廣播:按照優先級,一級一級的向下傳遞,接收者能夠修改廣播數據,也能夠終止廣播事件。

Android 兩種註冊、發送廣播的區別算法


補一、ContentProvider相關:

ContentProvider的基本使用方法和做用。ContentValue的使用方法,他和HashMap的區別是什麼?數據庫

ContentProvider 是Android系統中提供的專門用戶不一樣應用間進行數據共享的組件,提供了一套標準的接口用來獲取以及操做數據,准許開發者把本身的應用數據根據需求開放給其餘應用進行增刪改查,而無須擔憂直接開放數據庫權限而帶來的安全問題。數組

ContentValue: 存儲數據封裝的HashMap,提供 put、get等方法瀏覽器

一、說說ContentProvider、ContentResolver、ContentObserver 之間的關係?

  • 1.ContentProvider 內容提供者,用於對外提供數據
  • 2.ContentResolver 內容解析者,用於獲取內容提供者提供的數據
  • 3.ContentObserver 內容監聽器,能夠監聽數據的改變狀態
  • 4.ContentResolver.notifyChange(uri)發出消息
  • 5.ContentResolver.registerContentObserver()監聽消息。

二、ContentProvider與數據庫(SQL)的區別?

  • 一、ContentProvider 屏蔽了數據存儲細節,能夠在不一樣應用間進行數據操做。
  • 二、SQL也有增刪改查的方法,只能對本應用的數據進行操做。

Android ContentProvider基本用法緩存

四、網絡相關

一、HttpClient與HttpUrlConnection的區別 2

  1. 功能上:
  • Http Client:適用於web瀏覽器,擁有大量靈活的API,提供了不少工具,封裝了http的請求頭,參數,內容體,響應,還有一些高級功能,代理、COOKIE、鑑權、壓縮、鏈接池的處理正所以,在不破壞兼容性的前提下,其龐大的API也令人難以改進。
  • HttpURLConnection: 對於大部分功能都進行了包裝,Http Client的高級功能代碼會較複雜,

2.性能上:

  • HttpURLConnection直接支持GZIP壓縮,默認添加"Accept-Encoding: gzip"頭字段到請求中,並處理相應的迴應,
  • 而Http Client雖然支持,但須要本身寫代碼處理。

3.選用:

  • Volley裏用的哪一種請求方式(2.3前HttpClient,2.3後HttpUrlConnection)

二、HTTPS和HTTP的區別 2

一、什麼是 HTTPS

HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。

即HTTP下加入SSL (Secure Socket Layer)層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。


二、HTTPS 和 HTTP 的區別
  • https 用的 443 端口, http 用的 80 端口
  • https協議須要到ca申請證書,通常免費證書不多,須要交費。
  • http是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的ssl加密傳輸協議。
  • http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
  • http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

Android使用OkHttp請求自簽名的https網站 Android Https相關徹底解析 當OkHttp遇到Https HTTPS和HTTP的區別


五、View相關

一、view的Touch事件傳遞機制

一、和touch相關的三個方法
  1. public boolean dispatchTouchEvent(MotionEvent ev); //用來分派event
  2. public boolean onInterceptTouchEvent(MotionEvent ev); //用來攔截event
  3. public boolean onTouchEvent(MotionEvent ev); //用來處理event
方 法 解析
dispatchTouchEvent() 用來分派事件。其中調用了onInterceptTouchEvent()和onTouchEvent(),通常不重寫該方法,返回true則表示該事件被消費
onInterceptTouchEvent() 用來攔截事件。ViewGroup類中的源碼實現就是{return false;}表示不攔截該事件,事件將向下傳遞(傳遞給其子View);若手動重寫該方法,使其返回true則表示攔截,事件將終止向下傳遞,事件由當前ViewGroup類來處理,就是調用該類的onTouchEvent()方法
onTouchEvent() 用來處理事件。返回true則表示該View能處理該事件,事件將終止向上傳遞(傳遞給其父View);返回false表示不能處理,則把事件傳遞給其父View的onTouchEvent()方法來處

Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()


六、動畫相關

一、Android中有幾種動畫?

Android3.0以前有2種,3.0後有3種。
複製代碼
  • FrameAnimation(逐幀動畫):將多張圖片組合起來進行播放,相似於早期電影的工做原理,不少App的loading是採用這種方式。
  • TweenAnimation(補間動畫):是對某個View進行一系列的動畫的操做,包括淡入淡出(AlphaAnimation),縮放(ScaleAnimation),平移(TranslateAnimation),旋轉(RotateAnimation)四種模式。
  • PropertyAnimation(屬性動畫):屬性動畫再也不僅僅是一種視覺效果了,而是一種不斷地對值進行操做的機制,並將值賦到指定對象的指定屬性上,能夠是任意對象的任意屬性。

注1:AnimationSet 繼承自Animation,是上面四種的組合容器管理類,沒有本身特有的屬性,他的屬性繼承自Animation,因此特別注意,當咱們對set標籤使用Animation的屬性時會對該標籤下的全部子控件都產生影響。

注2:補間動畫執行以後並未改變View的真實佈局屬性值。切記這一點,譬如咱們在Activity中有一個Button在屏幕上方,咱們設置了平移動畫移動到屏幕下方而後保持動畫最後執行狀態呆在屏幕下方,這時若是點擊屏幕下方動畫執行以後的Button是沒有任何反應的,而點擊原來屏幕上方沒有Button的地方卻響應的是點擊Button的事件。


二、屬性動畫

  • ObjectAnimator:繼承自ValueAnimator,容許你指定要進行動畫的對象以及該對象的一個屬性。
  • 大多數的狀況使用ObjectAnimator就足夠了,由於它使得目標對象動畫值的處理過程變得足夠簡單,不用像ValueAnimator那樣本身寫動畫更新的邏輯
  • ObjectAnimator的動畫原理是不停的調用setXXX方法更新屬性值,全部使用ObjectAnimator更新屬性時的前提是Object必須聲明有getXXX和setXXX方法
ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0,  1).setDuration(2000);
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                //int value = animation.getAnimatedValue();  能夠獲取當前屬性值
                //view.postInvalidate();  能夠主動刷新
                //view.setXXX(value);
                //view.setXXX(value);
                //......能夠批量修改屬性
            }
        });
複製代碼
ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
複製代碼
  • PropertyValuesHolder:多屬性動畫同時工做管理類。有時候咱們須要同時修改多個屬性,那就能夠用到此類
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);  
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);  
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
複製代碼
  • ValueAnimator:屬性動畫中的時間驅動,管理着動畫時間的開始、結束屬性值,相應時間屬性值計算方法等。包含全部計算動畫值的核心函數以及每個動畫時間節點上的信息、一個動畫是否重複、是否監聽更新事件等,而且還能夠設置自定義的計算類型。
ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight);  //定義動畫
animator.setTarget(view);   //設置做用目標
animator.setDuration(5000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation){
        float value = (float) animation.getAnimatedValue();
        view.setXXX(value);  //必須經過這裏設置屬性值纔有效
        view.mXXX = value;  //不須要setXXX屬性方法
    }
});
複製代碼

特別注意:ValueAnimator只是動畫計算管理驅動,設置了做用目標,但沒有設置屬性,須要經過updateListener裏設置屬性纔會生效。

  • AnimationSet:動畫集合,提供把多個動畫組合成一個組合的機制,並可設置動畫的時序關係,如同時播放、順序播放或延遲播放。具體使用方法比較簡單,以下:

Android應用開發之全部動畫使用詳解

七、Android中跨進程通信

android系統中應用程序之間不能共享內存。 所以,在不一樣應用程序之間交互數據(跨進程通信)就稍微麻煩一些

  • 一、訪問其餘應用程序的Activity
如調用系統通話應用
Intent callIntent=new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);
複製代碼
  • 二、Content Provider

Content Provider提供了一種在多個應用程序之間數據共享的方式(跨進程共享數據)。應用程序能夠利用Content Provider完成下面的工做

  1. 查詢數據
  2. 修改數據
  3. 添加數據
  4. 刪除數據

雖然Content Provider也能夠在同一個應用程序中被訪問,但這麼作並無什麼意義。Content Provider存在的目的向其餘應用程序共享數據和容許其餘應用程序對數據進行增、刪、改操做。 Android系統自己提供了不少Content Provider,例如,音頻、視頻、聯繫人信息等等。咱們能夠經過這些Content Provider得到相關信息的列表。這些列表數據將以Cursor對象返回。所以,從Content Provider返回的數據是二維表的形式。

如訪問系統相冊
複製代碼
  • 三、廣播(Broadcast)
廣播是一種被動跨進程通信的方式。當某個程序向系統發送廣播時,其餘的應用程序只能被動地接收廣播數據。這就象電臺進行廣播同樣,聽衆只能被動地收聽,而不能主動與電臺進行溝通。例如獲取手機電量信息
複製代碼
  • 四、AIDL服務

二、AIDL理解

一、定義:Android系統中的進程之間不能共享內存,所以,須要提供一些機制在不一樣進程之間進行數據通訊。 爲了使其餘的應用程序也能夠訪問本應用程序提供的服務,Android系統採用了遠程過程調用(Remote Procedure Call,RPC)方式來實現。與不少其餘的基於RPC的解決方案同樣,Android使用一種接口定義語言(Interface Definition Language,IDL)來公開服務的接口。咱們知道4個Android應用程序組件中的3個(Activity、BroadcastReceiver和ContentProvider)均可以進行跨進程訪問,另一個Android應用程序組件Service一樣能夠。所以,能夠將這種能夠跨進程訪問的服務稱爲AIDL(Android Interface Definition Language)服務。


三、Binder理解

一、什麼是binder:

Binder是Android實現 跨進程通信(IPC)的方式,是一種虛擬的物理設備驅動,實現了IBindler 接口。

二、知識概念
  1. 一個進程空間分爲 用戶空間 & 內核空間(Kernel),即把進程內 用戶 & 內核 隔離開來

區別:

  1. 進程間,用戶空間的數據不可共享,因此用戶空間 = 不可共享空間
  2. 進程間,內核空間的數據可共享,因此內核空間 = 可共享空間
  1. 進程隔離:保證 安全性 & 獨立性,一個進程 不能直接操做或者訪問另外一個進程,即Android的進程是相互獨立、隔離的
  2. 跨進程通訊( IPC ):隔離後,因爲某些需求,進程間 須要合做 / 交互
  3. 跨進程間通訊的原理
  • 先經過 進程間 的內核空間進行 數據交互
  • 再經過 進程內 的用戶空間 & 內核空間進行 數據交互,從而實現 進程間的用戶空間 的數據交互
    image
  • 而Binder,就是充當 鏈接 兩個進程(內核空間)的通道。
三、Binder 跨進程通訊機制 模型
  1. 模型原理:

image

四、優勢

對比 Linux (Android基於Linux)上的其餘進程通訊方式(管道、消息隊列、共享內存、 信號量、Socket),Binder 機制的優勢有:

image

Binder學習指南

圖文詳解 Android Binder跨進程通訊的原理


八、Handler相關

一、handler 消息傳遞分析

做用:Handle 進行消息傳遞

  1. Handle發送的msg經過enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)添加進(MessageQueue)消息隊列中.

Android 消息傳遞機制分析


二、Handle、Message、MessageQueue、Looper之間的關係

  • Handle:主要發送 Message
  • Message:消息
  • MessageQueue:消息隊列.保存由Looper發送的消息列表。
  • Looper:用於爲線程運行消息循環的類。Thread默認狀況下沒有與之關聯,經過prepare()循環運行在線程中,經過loop(for(;;))來處理消息。

九、熱修復相關

一、熱修復包含:

  1. 資源替換
  2. 類替換(四大組件、類)
  3. SO補丁

二、資源替換方法:

思路:Andorid APP默認的類加載是PathClassLoader,這個只能加載本身APK的dex文件,因此咱們須要使用DexClassLoader。咱們用DexClassLoader加載外部的APK以後,經過反射獲取對應的資源。


三、類替換(四大組件、類):

  1. 經過PathClassLoader 來加載咱們自身App的dex
  2. 經過DexClassLoader來加載咱們的補丁dex文件,這裏面就是沒有bug的dex
  3. 反射兩個classLoader的<DexPathList pathList;>
  4. 接着咱們來繼續反射兩個classloader中的pathList(注意:是兩個!一個是咱們本身應用的,另外一個是咱們補丁的,PathClassLoader和DexClassLoader都繼承BaseDexClassLoader),DexPathList裏面的<Element[] dexElements;>,沒錯仍是拿到這個數組的值
  5. 合併兩個反射到的Element 數組!這裏是重中之重.咱們須要把咱們的補丁dex放在數組的最前面!
  6. 將合併的新的數組,經過Field從新設置到咱們自身App的DexPathList->dexElements.沒錯!就是合併以後覆蓋有bug那個loader的Element 數組!!
  7. 經過Android build-tools 中的dx命令打包一個沒有bug的dex

Android 熱修復(全網最簡單的熱修復講解)


四、SO補丁:


十、圖片加載緩存相關

一、設計一套圖片異步加載緩存方案

緩存層分爲三層:內存層,磁盤層,網絡層

  • 內存層:內存緩存相對於磁盤緩存而言,速度要來的快不少,但缺點容量較小且會被系統回收,這裏的實現我用到了LruCache。
  • 磁盤層:相比內存緩存而言速度要來得慢不少,但容量很大,這裏的實現我用到了DiskLruCache類。
  • 網絡層:網絡訪問實現我用到了開源框架Volley

十一、內存泄露及管理

一、內存泄漏:

  • 內存泄露:程序在向系統申請分配內存空間後(new),在使用完畢後未釋放。結果致使一直佔據該內存單元,咱們和程序都沒法再使用該內存單元,直到程序結束,這是內存泄露。
  • 內存溢出:程序向系統申請的內存空間超出了系統能給的。好比內存只能分配一個int類型,我卻要塞給他一個long類型,系統就出現oom。又好比一車最多能坐5我的,你卻非要塞下10個,車就擠爆了。
  • 大量的內存泄露會致使內存溢出(oom)

二、內存:

  • 棧(stack):是簡單的數據結構,但在計算機中使用普遍。棧最顯著的特徵是:LIFO(Last In, First Out, 後進先出),棧中只存放基本類型和對象的引用(不是對象)。
  • 堆(heap):堆內存用於存放由new建立的對象和數組。在堆中分配的內存,由java虛擬機自動垃圾回收器來管理。JVM只有一個堆區(heap)被全部線程共享,堆中不存放基本類型和對象引用,只存放對象自己。
  • 方法區(method):又叫靜態區,跟堆同樣,被全部的線程共享。方法區包含全部的class和static變量。

三、內存優化

  1. 單例致使內存泄露
public class AppSettings {

    private static AppSettings sInstance;
    private Context mContext;

    private AppSettings(Context context) {
        this.mContext = context;
        
        //this.mContext = context.getApplicationContext();
    }

    public static AppSettings getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new AppSettings(context);
        }
        return sInstance;
    }
}

複製代碼

二、靜態變量致使內存泄露

public class MainActivity extends AppCompatActivity {

    private static Info sInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (sInfo != null) {
            sInfo = new Info(this);
        }
    }
}

class Info {
    public Info(Activity activity) {
    }
}

複製代碼

Info做爲Activity的靜態成員,而且持有Activity的引用,可是sInfo做爲靜態變量,生命週期確定比Activity長。因此當Activity退出後,sInfo仍然引用了Activity,Activity不能被回收,這就致使了內存泄露。

三、非靜態內部類致使內存泄露

非靜態內部類(包括匿名內部類)默認就會持有外部類的引用,當非靜態內部類對象的生命週期比外部類對象的生命週期長時,就會致使內存泄露。

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start();
    }

    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                // 作相應邏輯
            }
        }
    };
}

複製代碼

熟悉Handler消息機制的都知道,mHandler會做爲成員變量保存在發送的消息msg中,即msg持有mHandler的引用,而mHandler是Activity的非靜態內部類實例,即mHandler持有Activity的引用,那麼咱們就能夠理解爲msg間接持有Activity的引用。msg被髮送後先放到消息隊列MessageQueue中,而後等待Looper的輪詢處理(MessageQueue和Looper都是與線程相關聯的,MessageQueue是Looper引用的成員變量,而Looper是保存在ThreadLocal中的)。那麼當Activity退出後,msg可能仍然存在於消息對列MessageQueue中未處理或者正在處理,那麼這樣就會致使Activity沒法被回收,以至發生Activity的內存泄露。

一般在Android開發中若是要使用內部類,但又要規避內存泄露,通常都會採用靜態內部類+弱引用的方式。

public class MainActivity extends AppCompatActivity {

    private Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler = new MyHandler(this);
        start();
    }

    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }

    private static class MyHandler extends Handler {

        private WeakReference<MainActivity> activityWeakReference;

        public MyHandler(MainActivity activity) {
            activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = activityWeakReference.get();
            if (activity != null) {
                if (msg.what == 1) {
                    // 作相應邏輯
                }
            }
        }
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
}
複製代碼

非靜態內部類形成內存泄露還有一種狀況就是使用Thread或者AsyncTask

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 模擬相應耗時邏輯
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}


複製代碼

這種方式新建的子線程Thread和AsyncTask都是匿名內部類對象,默認就隱式的持有外部Activity的引用,致使Activity內存泄露。

四、未取消註冊或回調致使內存泄露

  • 在Activity中註冊廣播,若是在Activity銷燬後不取消註冊

五、Timer和TimerTask致使內存泄露

  • Timer和TimerTask在Android中一般會被用來作一些計時或循環任務

六、集合中的對象未清理形成內存泄露

若是一個對象放入到ArrayList、HashMap等集合中,這個集合就會持有該對象的引用。當咱們再也不須要這個對象時,也並無將它從集合中移除,這樣只要集合還在使用(而此對象已經無用了),這個對象就形成了內存泄露。而且若是集合被靜態引用的話,集合裏面那些沒有用的對象更會形成內存泄露了。因此在使用集合時要及時將不用的對象從集合remove,或者clear集合,以免內存泄漏。

七、資源未關閉或釋放致使內存泄露

在使用IO、File流或者Sqlite、Cursor等資源時要及時關閉。這些資源在進行讀寫操做時一般都使用了緩衝,若是及時不關閉,這些緩衝對象就會一直被佔用而得不到釋放,以至發生內存泄露。所以咱們在不須要使用它們的時候就及時關閉,以便緩衝能及時獲得釋放,從而避免內存泄露。

八、屬性動畫形成內存泄露

動畫一樣是一個耗時任務,好比在Activity中啓動了屬性動畫(ObjectAnimator),可是在銷燬的時候,沒有調用cancle方法,雖然咱們看不到動畫了,可是這個動畫依然會不斷地播放下去,動畫引用所在的控件,所在的控件引用Activity,這就形成Activity沒法正常釋放。所以一樣要在Activity銷燬的時候cancel掉屬性動畫,避免發生內存泄漏。

@Override
protected void onDestroy() {
    super.onDestroy();
    mAnimator.cancel();
}
複製代碼

九、WebView形成內存泄露

關於WebView的內存泄露,由於WebView在加載網頁後會長期佔用內存而不能被釋放,所以咱們在Activity銷燬後要調用它的destory()方法來銷燬它以釋放內存。

@Override
protected void onDestroy() {
    super.onDestroy();
    // 先從父控件中移除WebView
    mWebViewContainer.removeView(mWebView);
    mWebView.stopLoading();
    mWebView.getSettings().setJavaScriptEnabled(false);
    mWebView.clearHistory();
    mWebView.removeAllViews();
    mWebView.destroy();
}

複製代碼

十、總結

1).資源對象沒關閉形成的內存泄漏 2).構造Adapter時,沒有使用緩存的convertView 3).Bitmap對象不在使用時調用recycle()釋放內存 4).試着使用關於application的context來替代和activity相關的context 5).註冊沒取消形成的內存泄漏 6).集合中對象沒清理形成的內存泄漏

查找內存泄漏可使用Android Stdio 自帶的Android Profiler工具,也可使用Square產品的LeadCanary.

十二、android 屏幕適配

  • 在 XML 佈局文件中指定尺寸時使用 wrap_content、match_parent 或 dp 單位 。
  • 不要在應用代碼中使用硬編碼的像素值
  • 不要使用 AbsoluteLayout(已棄用)
  • 爲不一樣屏幕密度提供替代位圖可繪製對象

image

支持多種屏幕

面向多種屏幕的設計

Android 屏幕適配:最全面的解決方案

1三、HybridJAVA 與JS交互

  • Android 調 JS : 一、java
webView.loadUrl("javascript:javacalljs()");
複製代碼

  二、Html

image

**注意:**考慮有返回值狀況;Android在4.4以前並無提供直接調用js函數並獲取值的方法,因此在此以前,經常使用的思路是 java調用js方法,js方法執行完畢,再次調用java代碼將值返回。

// 4.4以後 java代碼時用evaluateJavascript方法調用
private void testEvaluateJavascript(WebView webView) {
  webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {

  @Override
  public void onReceiveValue(String value) {
      Log.i(LOGTAG, "onReceiveValue value=" + value);
  }});
}
複製代碼
  • JS 調 Android : 一、java
webView.addJavascriptInterface(MainActivity.this,"android");
複製代碼

  二、html

<body>
HTML 內容顯示 <br/>
<h1><div id="content">內容顯示</div></h1><br/>
<input type="button"  value="點擊調用java代碼" onclick="window.android.startFunction()" /><br/>
<input type="button"  value="點擊調用java代碼並傳遞參數" onclick="window.android.startFunction('http://blog.csdn.net/Leejizhou')"  />
</body>
複製代碼

Android中Java和JavaScript交互

1四、單例模式(手寫)

//懶漢式
public class Singleton {
    private static Singleton singleton;

    private Singleton() {

    }

    public static synchronized Singleton getSingleton() {
        if (singleton == null) {
            singleton = new Singleton();
        }

        return singleton;
    }
}

複製代碼
//餓漢式
public class Singleton {
    private static final Singleton singleton = new Singleton();

    private Singleton () {

    }

    public static Singleton getSingleton() {
        return singleton;
    }
}
複製代碼
//double-lock
public class Singleton {
    private volatile static Singleton singleton;

    private Singleton() {

    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized(Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }

        return singleton;
    }
}
複製代碼

1四、ANR相關

一、什麼是ANR

在Android上,若是你的應用程序有一段時間響應不夠靈敏,系統會向用戶顯示一個對話框,這個對話框稱做應用程序無響應(ANR:Application Not Responding)對話框。


二、ANR產生的緣由

ANR產生的根本緣由是APP阻塞了UI線程


三、ANR產生的緣由

1:UI線程儘可能只作跟UI相關的工做,但一些複雜的UI操做,仍是須要一些技巧來處理,不如你讓一個Button去setText一個10M的文本,UI確定崩掉了,不過對於此類問題,分段加載貌似是最好的方法了。 2:讓耗時的工做(好比數據庫操做,I/O,鏈接網絡或者別的有可能阻礙UI線程的操做)把它放入單獨的線程處理。 3:儘可能用Handler來處理UIthread和別的thread之間的交互。


ANR徹底解析

1五、SharedPreference相關

  • SharedPreference三種得到方法和區別:
一、 Activity類中的getPreferences(int mode)文件自動命名爲當前活動的類名。
二、 Context類中getSharedPreferences("fileName", int mode) 此方法能夠指定文件名,mode同上。
三、PreferenceManager類中的getDefaultSharedPreferences(Context context)它只接收一個context參數。
文件用當前應用程序的包名和PreferenceActivity一塊兒來命名。屬於整個應用程序
複製代碼

SharedPreference得到方法對比

  • commit和apply的區別:
    1. apply沒有返回值而commit返回boolean代表修改是否提交成功。
    2. apply是將修改數據原子提交到內存, 然後異步真正提交到硬件磁盤, 而commit是同步的提交到硬件磁盤,所以,在多個併發的提交commit的時候,他們會等待正在處理的commit保存到磁盤後在操做,從而下降了效率。而apply只是原子的提交到內容,後面有調用apply的函數的將會直接覆蓋前面的內存數據,這樣從必定程度上提升了不少效率。
    3. apply方法不會提示任何失敗的提示。 因爲在一個進程中,sharedPreference是單實例,通常不會出現併發衝突,若是對提交的結果不關心的話,建議使用apply,固然須要確保提交成功且有後續操做的話,仍是須要用commit的。

1六、View,SurfaceView,GLSurfaceView的關係和區別:

  • View:顯示視圖,內置畫布,提供圖形繪製函數、觸屏事件、按鍵事件函數等;必須在UI主線程內更新畫面,速度較慢。
  • SurfaceView:基於view視圖進行拓展的視圖類,更適合2D遊戲的開發;是view的子類,相似使用雙緩機制,在新的線程中更新畫面因此刷新界面速度比view快。
  • GLSurfaceView:基於SurfaceView視圖再次進行拓展的視圖類,專用於3D遊戲開發的視圖;是SurfaceView的子類,openGL專用。

1七、其餘

一、Android 中序列化有哪些方式?區別?

  • Serializable(Java自帶): Serializable是序列化的意思,表示將一個對象轉換成可存儲或可傳輸的狀態。序列化後的對象能夠在網絡上進行傳輸,也能夠存儲到本地。
  • Parcelable(android 專用): 不過不一樣於將對象進行序列化,Parcelable方式的實現原理是將一個完整的對象進行分解, 而分解後的每一部分都是Intent所支持的數據類型
  • 區別:
    • Parcelable比Serializable性能高,因此應用內傳遞數據推薦使用Parcelable
    • Serializable代碼量少,寫起來方便,缺點是使用了反射,序列化的過程較慢。這種機制會在序列化的時候建立許多的臨時對象,容易觸發垃圾回收。

二、glide 源碼

三、Android中進程的級別,以及各自的區別。

  • 一、前臺進程

用戶當前正在作的事情須要這個進程。若是知足下面的條件之一,一個進程就被認爲是前臺進程: 1).這個進程擁有一個正在與用戶交互的Activity(這個Activity的onResume()方法被調用)。 2).這個進程擁有一個綁定到正在與用戶交互的activity上的Service。 3).這個進程擁有一個前臺運行的Service(service調用了方法startForeground()). 4).這個進程擁有一個正在執行其任何一個生命週期回調方法(onCreate(),onStart(),或onDestroy())的Service。 5).這個進程擁有正在執行其onReceive()方法的BroadcastReceiver。 一般,在任什麼時候間點,只有不多的前臺進程存在。它們只有在達到沒法調合的矛盾時纔會被殺--如內存過小而不能繼續運行時。一般,到了這時,設備就達到了一個內存分頁調度狀態,因此須要殺一些前臺進程來保證用戶界面的反應.

  • 二、可見進程

一個進程不擁有運行於前臺的組件,可是依然能影響用戶所見。知足下列條件時,進程即爲可見: 這個進程擁有一個不在前臺但仍可見的Activity(它的onPause()方法被調用)。當一個前臺activity啓動一個對話框時,就出了這種狀況。

  • 三、服務進程

一個可見進程被認爲是極其重要的。而且,除非只有殺掉它才能夠保證全部前臺進程的運行,不然是不能動它的。 這個進程擁有一個綁定到可見activity的Service。 一個進程不在上述兩種以內,但它運行着一個被startService()所啓動的service。 儘管一個服務進程不直接影響用戶所見,可是它們一般作一些用戶關心的事情(好比播放音樂或下載數據),因此係統不到前臺進程和可見進程活不下去時不會殺它。

  • 四、後臺進程

一個進程擁有一個當前不可見的activity(activity的onStop()方法被調用)。

  • 五、空進程

一個進程不擁有任何active組件。

四、線程池的相關知識。

Android中的線程池都是之間或間接經過配置ThreadPoolExecutor來實現不一樣特性的線程池.Android中最多見的四類具備不一樣特性的線程池分別爲FixThreadPool、CachedThreadPool、SingleThreadPool、ScheduleThreadExecutor.

  • **FixThreadPool: **只有核心線程,而且數量固定的,也不會被回收,全部線程都活動時,由於隊列沒有限制大小,新任務會等待執行. 優勢:更快的響應外界請求.

  • **SingleThreadPool:**只有一個核心線程,確保全部的任務都在同一線程中按順序完成.所以不須要處理線程同步的問題.

  • **CachedThreadPool:**只有非核心線程,最大線程數很是大,全部線程都活動時,會爲新任務建立新線程,不然會利用空閒線程(60s空閒時間,過了就會被回收,因此線程池中有0個線程的可能)處理任務. 優勢:任何任務都會被當即執行(任務隊列SynchronousQueue至關於一個空集合);比較適合執行大量的耗時較少的任務.

  • **ScheduleThreadExecutor:**核心線程數固定,非核心線程(閒着沒活幹會被當即回收)數沒有限制. 優勢:執行定時任務以及有固定週期的重複任務

Android開發之線程池使用總結

五、怎樣計算一張圖片的大小,加載bitmap過程(怎樣保證不產生內存溢出),二級緩存,LRUCache算法。

一、計算一張圖片的大小

圖片佔用內存的計算公式:圖片高度 * 圖片寬度 * 一個像素佔用的內存大小.因此,計算圖片佔用內存大小的時候,要考慮圖片所在的目錄跟設備密度,這兩個因素其實影響的是圖片的高寬,android會對圖片進行拉昇跟壓縮。

二、加載bitmap過程(怎樣保證不產生內存溢出)

因爲Android對圖片使用內存有限制,如果加載幾兆的大圖片便內存溢出。
Bitmap會將圖片的全部像素(即長x寬)加載到內存中,若是圖片分辨率過大,會直接致使內存OOM,只有在BitmapFactory加載圖片時使用BitmapFactory.Options對相關參數進行配置來減小加載的像素。

三、BitmapFactory.Options相關參數詳解

(1).Options.inPreferredConfig值來下降內存消耗。
  好比:默認值ARGB_8888改成RGB_565,節約一半內存。
(2).設置Options.inSampleSize 縮放比例,對大圖片進行壓縮 。
(3).設置Options.inPurgeable和inInputShareable:讓系統能及時回 收內存。
  A:inPurgeable:設置爲True時,表示系統內存不足時能夠被回 收,設置爲False時,表示不能被回收。
  B:inInputShareable:設置是否深拷貝,與inPurgeable結合使用,inPurgeable爲false時,該參數無心義。

(4).使用decodeStream代替其餘方法。
decodeResource,setImageResource,setImageBitmap等方法


複製代碼

**LRUCache算法:**內部存在一個LinkedHashMap和maxSize,把最近使用的對象用強引用存儲在 LinkedHashMap中,給出來put和get方法,每次put圖片時計算緩存中全部圖片總大小,跟maxSize進行比較,大於maxSize,就將最久添加的圖片移除;反之小於maxSize就添加進來。(400行代碼不到...)

六、layout、Merge、ViewStub的做用。

  • merge: 它能夠刪減多餘的層級,優化UI。例如你的主佈局文件是垂直佈局,引入了一個垂直佈局的include,這是若是include佈局使用的LinearLayout就沒意義了,使用的話反而減慢你的UI表現。這時可使用標籤優化。

  • ViewStub: 標籤最大的優勢是當你須要時纔會加載,使用他並不會影響UI初始化時的性能。各類不經常使用的佈局想進度條、顯示錯誤消息等可使用標籤,以減小內存使用量,加快渲染速度。是一個不可見的,大小爲0的View。

相關文章
相關標籤/搜索