Android-知識(shí)點(diǎn)總結(jié)

Java知識(shí)點(diǎn)

抽象類與接口的區(qū)別:

  1. 抽象類可以有方法的具體實(shí)現(xiàn),接口不可以。
  2. 由于Java單繼承的特性,子類只能繼承一個(gè)抽象類,但可以實(shí)現(xiàn)多了接口。
  3. 接口是為類的具體實(shí)現(xiàn)提供一個(gè)通用的規(guī)范,抽象類是為子類提供一個(gè)公共的類型,是為了類的繼承而存在的。

說明:接口可以被接口繼承,接口所有的方法自動(dòng)被聲明為public,接口可以定義成員變量,自動(dòng)被聲明為public static final類型。

集合繼承結(jié)構(gòu)

集合繼承結(jié)構(gòu)圖

1.SparseArray、ArrayList對(duì)比
SparseArray是稀疏數(shù)組,主要是包括兩個(gè)數(shù)組分別用來存放key、value,其中g(shù)et和put元素時(shí)用到了二分查找。
ArrayList比較簡單,就用一個(gè)對(duì)象數(shù)組來存儲(chǔ)元素。
2. ArrayMap、HashMap的對(duì)比
HashMap
Java庫里的HashMap其實(shí)是一個(gè)連續(xù)的鏈表數(shù)組,通過key計(jì)算hash值后插入對(duì)應(yīng)的index里。當(dāng)hash值發(fā)生碰撞時(shí),可以采用線性探測(cè),二次hash,或者后面直接變成鏈表的結(jié)構(gòu)來避免碰撞。
說明:hash值不是連續(xù)的,所以hashmap實(shí)際需要占用的大小會(huì)比它實(shí)際能裝的item的容量要大。
HashMap結(jié)構(gòu)圖

ArrayMap
先看看ArrayMap的結(jié)構(gòu)圖:
ArrayMap結(jié)構(gòu)圖

ArrayMap用兩個(gè)數(shù)組來模擬Map,第一個(gè)數(shù)組存放存放item的hash值,第二數(shù)組是把key,value連續(xù)的存放在數(shù)組里。通過先算hash,在第一個(gè)數(shù)組里找到它的hash index,然后根據(jù)這個(gè)index在去第二個(gè)數(shù)組里找到這個(gè)key-value。
這里,在第一個(gè)數(shù)組里查找hash index的方法是用二分查找(binary search),過程如下圖所示。
ArrayMap元素查找過程

說明:
查找元素達(dá)不到HashMap的O(1)時(shí)間復(fù)雜度。
3. HashMap、HashTable的區(qū)別
1). HashTable是繼承Dictionary類,實(shí)現(xiàn)Map接口,HashMap是繼承AbstractMap類并實(shí)現(xiàn)了Map接口,AbstractMap類也實(shí)現(xiàn)了Map接口。
2). HashTable的方法是同步的,HashMap是非同步。
3). HashTable、HashMap使用的哈希值的不同,HashTable直接使用對(duì)象的hashCode,而HashMap則重新計(jì)算了Hash值。

String、StringBuffer、StringBuilder的區(qū)別

  1. String是字符串常量,StringBuffer、StringBuilder是字符串變量。
  2. StringBuffer是線程安全的,StringBuilder是非線程安全的。
  3. 對(duì)于內(nèi)容經(jīng)常改變的字符串最好使用StringBuffer或者StringBuilder,因?yàn)镾tringBuffer或者StringBuilder是對(duì)字符串對(duì)象本身做修改,String是每次都會(huì)生成一個(gè)新的對(duì)象。

==、equals、hashCode的區(qū)別

  1. == : 它的作用是判斷兩個(gè)變量(基本變量)的值是否相等,或者判斷兩個(gè)對(duì)象的地址是不是相等,即判斷兩個(gè)對(duì)象是不是同一個(gè)對(duì)象。
  2. equals:不重寫equals的時(shí)候,比較的是引用(Reference),也就是內(nèi)存地址。
public boolean equals(Object o) {
        return this == o;
    }
  1. equals相等,則hasCode一定相等,而hashCode相等,equals不一定相等。因此,一般重寫equals,就必須重寫hashCode。

Android知識(shí)點(diǎn)

本地廣播、全局廣播的區(qū)別

本地廣播僅在應(yīng)用內(nèi)發(fā)送,全局廣播是在系統(tǒng)內(nèi)發(fā)送。
本地廣播不用擔(dān)心隱私數(shù)據(jù)泄露的問題,全局廣播需要防止別的應(yīng)用偽造廣播,從而造成不必要的安全隱患。

Service的啟動(dòng)方式

Service的啟動(dòng)方式有兩種:startService,bindService,這兩種啟動(dòng)的方式的區(qū)別如下:

1)startService來啟動(dòng)某個(gè)service,其生命周期與啟動(dòng)方(如Activity)無關(guān),當(dāng)Activity銷毀后,service還在后臺(tái)運(yùn)行,除非執(zhí)行stopService方法。
2)bindService來啟動(dòng)某個(gè)service,其生命周期與啟動(dòng)方(如Activity)有關(guān),當(dāng)Activity銷毀后,service也跟著銷毀,當(dāng)然也可以調(diào)用unbind方法解除綁定。
3)生命周期的回調(diào)方法不同,如下:
startService: onCreate -> onStartCommand -> onDestroy
bindService:onCreate -> onBind -> onUnbind -> onDestroy

說明:Service仍然是在主線程中調(diào)用,還是要開線程才能處理長時(shí)間的工作。

引申:IntentService是處理異步任務(wù),實(shí)現(xiàn)多線程。

Android動(dòng)畫類型

Android動(dòng)畫包括幀動(dòng)畫(Frame Animation)、補(bǔ)間動(dòng)畫(Tween Animation)、屬性動(dòng)畫。

幀動(dòng)畫:連續(xù)地播放圖片序列,有點(diǎn)類似于gif圖,在Android中用AnimationDrawable來加載XML資源文件并進(jìn)行播放。

補(bǔ)間動(dòng)畫:主要分為scale(縮放)、rotate(旋轉(zhuǎn))、translate(位移)、alpha(透明度漸變),一般是在XML文件中寫好,然后通過AnimationUtils進(jìn)行加載。

屬性動(dòng)畫:主要是ObjectAnimator 這個(gè)類,其繼承自ValueAnimator,使用這個(gè)類可以對(duì)任意對(duì)象的任意屬性進(jìn)行動(dòng)畫操作,可以很好地實(shí)現(xiàn)補(bǔ)間動(dòng)畫。

內(nèi)存泄漏

1. 內(nèi)存泄漏

我們知道Java虛擬機(jī)會(huì)幫我們進(jìn)行垃圾回收操作,即GC操作,如果一些無用的對(duì)象沒有被回收,就會(huì)發(fā)生了內(nèi)存泄漏,在講內(nèi)存泄漏之前,我們先來看看Java四種引用類型。

強(qiáng)引用: 如果對(duì)象具有強(qiáng)引用,即便內(nèi)存不足拋出OOM,也不會(huì)回收該對(duì)象,強(qiáng)引用一般是這樣的:Object object = new Object()。

軟引用: 如果對(duì)象具有軟引用,當(dāng)內(nèi)存不足時(shí),虛擬機(jī)會(huì)回收該對(duì)象。

弱引用:軟引用發(fā)生在垃圾回收時(shí),不管內(nèi)存是否不足,都會(huì)對(duì)弱引用的對(duì)象進(jìn)行回收。

虛引用:如果一個(gè)對(duì)象具有虛引用,其實(shí)跟沒有任何引用一樣,任何時(shí)候都會(huì)被垃圾回收器回收。

2. 內(nèi)存泄漏分析

1)長生命周期對(duì)象持有短生命周期對(duì)象的引用

public class SingleInstance {
    private Context mContext;
    private static SingleInstance instance;

    public SingleInstance(Context context){
        mContext = context;
    }

    public static SingleInstance getInstance(Context context){
        if(instance == null){
            instance = new SingleInstance(context);
        }
        return instance;
    }
}

假設(shè),我們這里傳入的是Activity-A的Context,在Activity-A的生命周期內(nèi),上面的單例能夠正常使用,如果Activity-A銷毀了,我們?cè)谄渌胤绞褂蒙厦娴膯卫龝r(shí),就會(huì)出現(xiàn)內(nèi)存泄漏。
我們知道單例的生命周期一般是跟整個(gè)應(yīng)用的生命周期一樣長,因此,我們應(yīng)該傳入Application的Context,為了讓每次使用單例時(shí)不用額外傳入一個(gè)變量,上面的代碼可以修改如下:

public class SingleInstance {
    private final Context mContext = Application.appContext;
    private static SingleInstance instance;

    private  SingleInstance(){
    }

    public static SingleInstance getInstance(){
        if(instance == null){
            instance = new SingleInstance();
        }
        return instance;
    }
}

2) 匿名內(nèi)部類的使用
在Activity或者Fragment中,我們一般會(huì)使用Handler更新UI操作,先來看看下面的代碼有什么問題沒。

public class MainActivity extends Activity {

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler.sendEmptyMessageDelayed(0, 6*1000);
    }
}

上面代碼,在onCreate方法里面發(fā)送一個(gè)延遲Message,這時(shí)如果Activity銷毀,則會(huì)發(fā)生內(nèi)存泄漏。因?yàn)?strong>非靜態(tài)的內(nèi)部類持有外部類的引用,而mHandler的生命周期還沒結(jié)束,其持有MainActivity的引用,但這時(shí)Activity已經(jīng)銷毀。
對(duì)于上面的代碼,我們可以進(jìn)行如下修改:

public class MainActivity extends Activity {
    private final Handler mHandler = new  MyHandler(this);
    public static class MyHandler extends Handler{
        private final WeakReference<MainActivity> mActivity;
        public MyHandler(MainActivity activity){
            mActivity = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            if(mActivity.get() != null){

            }
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler.sendEmptyMessageDelayed(0, 6*1000);
    }
}

引申:線程造成的內(nèi)存溢出
異步任務(wù)AsyncTask和Runnable都是一個(gè)匿名內(nèi)部類,它們對(duì)當(dāng)前Activity都有一個(gè)隱式引用。如果Activity在銷毀之前,任務(wù)還未完成, 那么將導(dǎo)致Activity的內(nèi)存資源無法回收,造成內(nèi)存泄漏。

3) 非靜態(tài)的內(nèi)部類創(chuàng)建靜態(tài)實(shí)例
下面的代碼中,我們創(chuàng)建了一個(gè)靜態(tài)的資源對(duì)象mResouce,每次Activity啟動(dòng)都會(huì)使用該資源的數(shù)據(jù),避免了重復(fù)創(chuàng)建,但是這樣會(huì)造成內(nèi)存泄漏,原因如下:
~ 非靜態(tài)內(nèi)部類默認(rèn)會(huì)持有外部類的引用。
~ 使用了該非靜態(tài)內(nèi)部類創(chuàng)建了一個(gè)靜態(tài)的實(shí)例。
~ 靜態(tài)實(shí)例的生命周期和應(yīng)用的一樣長,這就導(dǎo)致了該靜態(tài)實(shí)例一直會(huì)持有該Activity的引用,導(dǎo)致Activity的內(nèi)存資源不能正常回收。

private static XMLResource mResource = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(mResource == null){
            mResource = new XMLResource();
        }

    }
    class XMLResource {

    }

解決方案:將非靜態(tài)內(nèi)部類XMLResource修改為靜態(tài)內(nèi)部類。

4)使用了靜態(tài)的Activity和View
解決方案:應(yīng)該及時(shí)將靜態(tài)的應(yīng)用 置為null,而且一般不建議將View及Activity設(shè)置為靜態(tài)。

5)其它
注冊(cè)了系統(tǒng)的服務(wù),但onDestory沒有注銷,不需要用的監(jiān)聽器未移除。

3. 應(yīng)用的 Context數(shù)量

Context是一個(gè)抽象類,子類有ContextWrapper,ContextWrapper 的子類有ContextThemeWrapper,ContextWrapper有一個(gè)成員變量mBase,類型是Context,下面我們來看看有哪些組件間接繼承ContextWrapper。

1) Activity

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient

2) Service

public abstract class Service extends ContextWrapper implements ComponentCallbacks2

3) Application

public class Application extends ContextWrapper implements ComponentCallbacks2 

綜上可知:

APP Context總數(shù) = Application數(shù) + Activity數(shù) + Service數(shù)

說明:多進(jìn)程下Application可能被創(chuàng)建多次,因此多進(jìn)程環(huán)境下,Application的Context數(shù)可能不止一個(gè)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容