筆記記錄

001.Android 高級開發(fā)面試題以及答案整理
002.Android 高級面試高頻知識點
003.106道Android核心面試題及答案匯總

1.AsyncTask 用法

onPreExecute()
在UI thread調(diào)用 顯示一個進度條

doInBackground(void......params)
通過調(diào)用publishProgress()方法實時更新進度- 觸發(fā)onProgressUpdate

onProgressUpdate(Integer...values)

onPostExecute(Boolean result) 更新UI

public class JniTest{

private JniTest (){}
}

2.JNI用法
(1).新建一個jniTest文件
public class JniTest{
private JniTest(){}
private static JniTest instance=null;

public static JniTest getInstance(){
    if(instance==null){
         instance=new JniTest();
     }
     return instance;
}
 static{
     System.loadLibrary("JniTest");
 }  
 public static native String getJniString();

}

(2).build--->make project 在build目錄下找到生成的JniTest.class文件

(3).切換到更目錄下,執(zhí)行javah -jni com.example.firstndk.JniTest 生成
com_example_firstndk_JniTest.h文件

(4).新建一個JNI文件夾扑庞,并在此文件夾下來新建一個.c文件舞虱,將.h文件中的內(nèi)容拷貝到
.c文件中,并且實現(xiàn)里面的空方法歹河。

(5).在JNI文件下新建android.mk和application.mk文件,然后Terminal切換到JNI目錄下奠滑,
執(zhí)行ndk-build ,生成so庫文件

1.新建一個JniTest class類
public class JniTest{
public static native JniString(){}
static{
System.loadLibrary("JniTest")
}
}

2.執(zhí)行build--make project 在bulid文件夾下來會
生產(chǎn) jniTest.class文

3.在命令終端中,cd 切換到當前目錄,執(zhí)行
javah -jni com.example.JniTest.class
生成 com_example_JniTest.h文件,

4.新建一個JNI文件夾骄蝇,創(chuàng)建一個.c文件,把.h文件里面的代碼
復制到.c文件,實現(xiàn)里面的 getJniString()方法鞠苟,

5.執(zhí)行build---->rebulid project乞榨,會在build文件夾下面生產(chǎn)多個.so文件】

3.AIDL用法
3.1.新建一個aidl的文件,同時建立一個aidl的接口文件当娱,比如BookManager.aidl吃既,如果是Bean類型,必須parcelable序列化跨细,客戶端和服務端aidl文件同時存在鹦倚,且是一樣的。

3.2.服務端的AIDLService 要實現(xiàn)這個Booknamager.aidl接口冀惭,并通過onBind()方法返回該接口的實例化對象

3.3.客戶端通過bindService方法建立鏈接震叙,實現(xiàn)ServiceConnection接口,在onServiceConnected方法中把IBinder對象轉(zhuǎn)換成
aidl接口的實例化對象散休,一旦鏈接成功媒楼,客戶端就可以和服務端進行通信了。

private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.lypeer.aidl");
intent.setPackage("com.lypeer.ipcserver");
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

1.新建一個aidl文件夾戚丸,然后新建一個.aidl的接口文件划址,比如BookManager.aidl文件,里面有一個BookManager接口
interface BookManager{
float getBookPrice()
String getBookName()
}
客戶端和服務端同時持有aidl文件.
2.在服務端新建一個AidlService 服務限府,在onBind()方法中返回
BookManager接口實例
】夺颤,在AndroidManifest文件中配置AidlService的Action
3.客戶端通過bindService方法連接遠程遠程AIDL服務,實現(xiàn)ServiceConnection接口胁勺,onServiceConnect()
中拿到IBinder對象世澜,將IBinder對象轉(zhuǎn)換成BookManager接口實例,
就可是服務端的getBookPrice和getBookName方法了

4.BroadCastReceiver
(1).常駐型廣播-->靜態(tài)注冊(manifes中注冊)
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>

(2).非常駐型廣播-->動態(tài)注冊

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(String); //為BroadcastReceiver指定action署穗,使之用于接收同action的廣播
registerReceiver(BroadcastReceiver,intentFilter);

一般動態(tài)注冊的廣播寥裂,要在onDestory中解除注冊嵌洼,否則會導致內(nèi)存泄露。

常駐型廣播(靜態(tài)注冊)和非常駐型廣播(動態(tài)注冊
【registerReceiver(broadcastReceiver封恰,intentFilter)】)

5.ContentProvider
http://www.reibang.com/p/5e13d1fec9c9

(1).ContentProvider的作用是為不同的應用之間的數(shù)據(jù)共享咱台,提供統(tǒng)一的接口

(2).自定義
MyContentPovider extends ContentProvider{

指定authority="com.shuijian.authority"

實現(xiàn) inster,delete俭驮,update,query

}

(3).其他應用操作ContentProvider中的數(shù)據(jù)

獲得contentResolver=getContentResolver();

根據(jù)authority="com.shui.jian.authority"生成一個Uri,contentResolver通過
這個Uri就可以操作
其他應用中的ContentProvider中的數(shù)據(jù)了春贸,實現(xiàn)了數(shù)據(jù)的共享混萝。

6.設計模式

A:單例模式7種(getInstance 方法一定要是public)
餓漢式
(1).
public class SingleTon{
private SingleTon(){}
private static SingleTon instance=new SingleTon();

private static getInstance(){xxxxxxxxx

 return instance;

}

}

(2).靜態(tài)代碼塊
public class SingleTon{
private SingleTon(){}
private static SingleTon instance;
static{
instance=new SingleTon()
}
private static getInstance(){ xxxxxx
return instance;
}

}
(3).靜態(tài)內(nèi)部類(holder)
public class SingleTon{
private SingleTon(){}
private static class SingleTonHolder{
private static SingleTon instance=new SingleTon();

}
private static getInstance(){ xxxxxx
return SingleTonHolder.instance;
}

}

(4)懶漢線程不安全
public class SingleTon{
private SingleTon(){}
private static SingleTon instance;

private static getInstance(){xxxxx
if(instance==null){
instance=new SingleTon();
}

 return instance;

}

}

(5)懶漢線程安全
public class SingleTon{
private SingleTon(){}
private static SingleTon instance;

private static synchrozied getInstance(){xxxxxxxx
if(instance==null){
instance=new SingleTon();
}

 return instance;

}

}
(6)懶漢線程安全
public class SingleTon{
private SingleTon(){}
private static SingleTon instance;

private static synchrozied getInstance(){xxxxxx
if(instance==null){
synchrozied(SingleTon.class){
if(instance==null){
instance=new SingleTon();
}
}
}

 return instance;

}

}
(7)
public enum SingleTon{
Instance;
}

B.工廠模式
public interface Sender{
public void send()
}

public Sender SMSSender implements Sender{

public void send(){
    System.out.print("sms);

}

}

public Sender QQSender implements Sender{

public void send(){
    System.out.print("QQsms);

}

}

(1).普通工廠模式

public class FactoryOne{

 poublic Sender produce(String type){
   if(type equals "sms"){
         return new SmsSender();
    }else if(type equals "QQ"){
 

      return new QQSmsSender();
    }

}

}

(2).工廠方法模式
public class FactoryTwo{
public Sender smsSender(){

        return SmsSender();
 }
  public Sender qqSender(){

        return QQSender();
 }         

}

(3).靜態(tài)工廠方法模式
public class FactoryTwo{
public static Sender smsSender(){
return SmsSender();
}
public staic Sender qqSender(){
return QQSender();
}
}

(4).抽象工廠模式

public interface Provider{
void produce();

}

public class FactorySms implements Provider{

public Sender produce(){
        return new SmsSender();

 }

}

public class FactoryQq implements Provider{

public Sender produce(){
        return new QQSender();

 }

}

3.觀察者模式
public interface Observer {
void update();
}

public interface Observerable(){

void registerObserver(Observer observer);
void removerObserver(Observer observer);
void notifyObservers();

}

public class User1 implements Observer(){
public void update(){
System.print.out("收到消息1");
}
}

public class User2 implements Observer(){
public void update(){
System.print.out("收到消息2");
}
}
public class Watcher implements Observerable{
public List<Observer> list=new ArrayList<Observer>();

public registerObserver(Observer observer){
    list.add(observer);
}
  public removeObserver(Observer observer){
    list.remove(observer);
}

public void notifyObservers(){
   for(list:item){
     item.update();
   }   
}

public void opration(){

    notifyObservers();

}
}

4.適配器模式
interface PS2{ void isPS2}
interface USB { void isUsb}
public class Usber implements usb{ public void isUsb(){ }}

(1).類適配器

public AdapterOne extends Usber implements PS2{ public void isPs2{ isUsb()}}

(2).對象適配器

public AdapterOne implements PS2{ public AdapterOne(Usber usber){ this.usber=usber;} public void isPs2{ usber.isUsb()}}
(3).接口適配器

interface A { void A(),void B()萍恕,void C ,
void D()逸嘀,void E(),void F()}

public abstract class Adapter implemntA{
void A(){} void B(){} void C(){}

}

public class MyAdapter extends Adpater{

  void A(){}......

}


abstract FragmentStatePageAdapter getPageTitle()

5.策略模式

6.Builder模式(AlertDialog)
AlertDialog.Builder bulider= new AlertDialog.Builder(context).setTitle(R.string.app_name).setMessage("此版本已是最新版本")
.setPositiveButton("好的", null);
AlertDialog alertDialog=bulider.show();

7.責任鏈模式

(1).構(gòu)造Request{ name ,reason,days, groupLeaderInfo ,managerInfo,departLeaderInfo}對象和Result{ isRatify ,info}結(jié)果對象

(2).interface Chain {
Request request();//獲取當前的Request
Result proceed(Request request)//轉(zhuǎn)發(fā)Request
}

(3).interface Ratify{ Result deal(Chain chain)}

(4). GroupLeader implements Ratify ( Result deal( return chain.proceed()or new Result))
Manager implements Ratify
CustomeLeader implements Ratify

(5)
RealChain implements Chain{
List<Ratify> list;
RealChain(List<Ratify> list,Requst requst ,int index){}
request(){ return this.request}
proceed(Request request){
Result result=null;
if(list.size>index){
Ratify ratify=list.get(index);//得到當前的責任人
Realchain chain=new Realchain(list,request,index+1);//初始化責任的位置,以便轉(zhuǎn)發(fā)過來的時候使用新的責任人
result= ratify.deal(chain);
}
return result

        }

}
(6).新建鏈條客戶端類
ChainClient {

List<Ratify> list;
addRatify(){ list.add()}//增加自定義的責任人

void executed(Request request){
List<Ratify> listNew= new List<Ratify>()
listNew.addAll(list);
listNew.add(new GroupLeader());
listNew.add(new Mannger());
listNew.add(new departLeader());
RealChain chain=new RealChain(list,request,0);
}
}

1.Request請求
2.Interface Chain{
Request request(){}
Result proceed(Request request){}
}
3.Interface Ratify{ Result deal(Reqeust request)}

4.GroupLeader ,DepartLeader{
Result deal(Chain chain){
Request request=chain.request;
if(request.getDays>3){
return chain.proceed(request);
}
return Result(true,"早去早回")
}
}

  1. RealChain implement Chain{
    RealChain (list,index,request){}
    Request request(){}
    Result proceed(Request request){
    RealChian chain=new RealChain(list ,request,index+1)
    Ratify ratify=list.get(index)
    Resutl result= ratify.deal(chain);
    return result;
    }
    }
    new RealChain(list,request,index).process(request)

8.代理模式

public DynamicProxyHandle implements InvocationHandler{
//invocationHandler持有被代理類的對象
public DynamicProxyHandle(Object obj){
this.obj=obj;
}
public Object invoke(Object proxy,Method method,Object[] args){

     Object proxy=method.invoke(obj,args);

     return proxy;

}
}

IBuy home=new Home();

DynamicProxyHandler dynamicHandler=new DynamicProxy(home);

Ibuy dynamicProxy=Proxy.newProxyInstance(home.getclass.getclassLoader,new Class[]{IBuy.class},dynamicHandler);

dynamicProxy.buy();

【Proxy.newProxyInstance(classLoader,class[],myInvocationHandler)】

10.SQLite
(1).創(chuàng)建一個extends SQLiteOpenHelper的類允粤,并實現(xiàn)onOnCreate(建立表格的代碼)和onUpgrade(刪除原來表格崭倘,重新建立表格)方法。

當表結(jié)構(gòu)發(fā)生變化的時候类垫,會自動觸發(fā)onUpgrad()方法司光,刪除原來的表,并重寫創(chuàng)建新的表結(jié)構(gòu)悉患。

(2).在創(chuàng)建一個OrderDao用于處理所有的數(shù)據(jù)操作残家。
insert ,delete ,update, search

11.XML解析 解析速度快,占用內(nèi)存少售躁,一旦開始無法暫停
(1).Sax解析坞淮,基于DefaultHandler,繼承DefaultHandler 實現(xiàn)5大方法

5大方法:startDocument endDocument startElement endElement characters 函數(shù)驅(qū)動型

(2).Dom解析 占用的內(nèi)存比較大陪捷,容易OOM 雙層for循環(huán)回窘, getElementByTagName()遍歷

(3).解析速度快,消耗內(nèi)存少市袖,很靈活,Pull解析 提供了開始標簽
4大標簽:START_DOCUMENT, END_DOCUMENT,START_TAG,END_TAG啡直,while循環(huán),更具標簽進行解析,可以根據(jù)需要跳出解析(parse.next)

12.Git常用命令

git init
git add index.html
git commit -m " beizhu"

git commit -am "添加并提交"

git log git status 項目目前的狀態(tài)

git branch 查看當前分支

git branch develop 創(chuàng)建分支

git branch develop origin/test

git checkout develop 切換倒develop分支

git checkout -b develop 創(chuàng)建develop并切換到develop

git merge develop

git branch -d develop 刪除本地分支

git branch -r -d origin/develop 刪除遠程分支

git push -u origin master

git remote add origin http://自己的倉庫地址 注冊遠程版本庫的地址

git remote remove origin 刪除遠程版本庫地址

git tag 1.0

git push origin 1.0

git show 1.0

13.Java面向?qū)ο?/p>

(1)封裝
屬性封裝(private protected public )
方法封裝
內(nèi)部類(成員內(nèi)部類凌盯,靜態(tài)內(nèi)部類付枫,方法內(nèi)部類)

(2)繼承

(3)多態(tài)

引用多態(tài):Animal animal=new Animal()
Animal dog=new Dog();
方法多態(tài):

Animal animal=new Animal() 可以訪問Animal本類中的非private屬性和方法

Animal dog=new Dog(); 可以只能訪問Animal本類中的非private屬性和方法,如果有重寫父類的方法驰怎,調(diào)用的時調(diào)用的自己重寫的阐滩,還有自己添加的方法和屬性

14.Java泛型
(1).泛型類
public class Generics<T>{ private T key ; }
(2).泛型接口
public Interface Generics<T> { public T next();}
(3).泛型方法
public <T> T getKey(T t){}
(4).通配符和上下邊界
Generics<?>

上邊界:Generics<? extends T> 只能傳入T的子類
下邊界:Generics<? super T> 只能傳入T的父類

15.抽象類和接口的區(qū)別
(1).抽象類只能單繼承,而接口卻可以多實現(xiàn)

(2).抽象類中啥都有县忌,但是抽象接口中一般不能有非抽象的方法掂榔。

(3).抽象類時對類的抽象继效,接口是對行為的抽象。(Door open close alarm)
【抽象類是對類的抽象装获,接口時對行為的抽象瑞信,抽象類只能單繼承,
而接口可以多實現(xiàn)穴豫,接口中只能有變量或者未實現(xiàn)的方法凡简,
但是抽象類中什么都可以有~】

16.Java集合
(1)List
ArrayList 非同步的 基于動態(tài)數(shù)組 可以隨機訪問

LinkedList 非同步的 基于雙向鏈表 不可以隨機訪問,必須從開頭或者結(jié)尾遍歷列表 Collect.synczoiedList()變成同步列表

Vector 是同步的精肃,其余和ArrayList一樣

Stack 繼承自Vector 秤涩,提供pop push ,peek,empty司抱,search方法
(2).Set 【Set集合都是非線程安全的】
HashSet 非同步筐眷,無序,可以插入null值习柠≡纫ィ【底層HashMap】
LinkedHashSet 非同步,有序资溃,可以插入null值武翎。【底層LinkedHashMap】
TreeSet 非同步,有序肉拓,可以實現(xiàn)自然排序和定制排序后频。【底層TreeMap】
(3).Map
HashMap 非同步暖途,無序卑惜,key,value都可以為null
LinkedHashMap 非同步驻售,有序露久, key,value都可以為null
Hashtable 同步的欺栗, 無序的,key毫痕,value都不能為null
TreeMap 非同步,有序的【支持自然排序和定制排序】 【紅黑二叉樹】

17.Handler和Looper迟几,Message之間的關系
https://juejin.cn/post/6844903783139393550
(1).ActivityThread類 App進程的初始化類,開啟死循環(huán)
Looper.prepareMainLooper() 【創(chuàng)建Looper消请,并通過ThreadLocal類
通過WeakReference,set ,get方法把當當前線程和Looper對象進行綁定】
Looper.loop();【開啟死循環(huán)】

(2).new 一個Hanlder對象的時候,構(gòu)建方法中對Looper和MessageQueue進行了初始化类腮,
當我們調(diào)用handler.sendMessage()---->enqueueMessage()臊泰,將此Message注入到
Looper所在的MessageQueue隊列中

(3).一旦Looper所在的MessageQueue隊列中有message,loop()死循環(huán)方法中蚜枢,通過

queue.next拿到消息缸逃,如果消息不為null针饥,那么msg.target.dispatchMessage()處理消息,

dispatchMessag內(nèi)部會調(diào)用handlerMessage()方法需频。
(4).Handler在子線程中使用:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
(5).Handler為什么不會阻塞主線程:
MessageQueue沒有消息時丁眼,
便阻塞在loop的queue.next()中的nativePollOnce()
時,主線程會釋放CPU資源進入休眠狀態(tài),有消息時昭殉,會調(diào)用
nativeWake喚醒苞七。

Handler導致內(nèi)存泄露怎么解決:
http://www.reibang.com/p/804e774d9f76
靜態(tài)內(nèi)部類+弱引用【java中只有靜態(tài)內(nèi)部類不會持有外部類引用婴削,
而普通內(nèi)部類會持有外部類的引用】
private static class AppHandler extends Handler {
//弱引用较坛,在垃圾回收時,被回收
WeakReference<Activity> activity;

    AppHandler(Activity activity){
        this.activity=new WeakReference<Activity>(activity);
    }

    public void handleMessage(Message message){
        switch (message.what){
            //todo
        }
    }
}

18.自定義View和ViewGroup
(1).4個構(gòu)造方法
new 刷后,AttributeSet 吃靠,view 有style,api>=21且view有style屬性的時候調(diào)用

(2).onMeassure()
specMode=MeasureSpec.Exactly 精確值 match_parent
specMode=MeasureSpec.AT_MOST 取最大值
specMode=MeasureSpec.UNSPECIFIED 父容器對當前的View不限制

setMeasureDimension()設置View大小

onDraw View disPatchDraw ViewGruop

invalidate主線程 postInvalidate子線程

自定義屬性attrs.recycle()// 進行對象回收

onLayout()中child.layout(), rquestLayout();

19.Android間的跨進程通信 https://www.cnblogs.com/andy-songwei/p/10256379.html
(1).Activity可以跨進程調(diào)用其他應用程序的Activity足淆;
打電話 startActivity()來啟動另外一個進程的Activity巢块。

Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678"); 隱式Intent
startActivity(callIntent);
(2)ContentProvider可以跨進程訪問其他應用程序中的數(shù)據(jù)(以Cursor對象形式返回),
當然巧号,也可以對其他應用程序的數(shù)據(jù)進行增族奢、刪、改操作丹鸿;
Android系統(tǒng)本身提供了很多Content Provider越走,例如,音頻靠欢、視頻廊敌、聯(lián)系人信息等等。我們可以通過這些Content Provider獲得相關信息的列表门怪。這些列表數(shù)據(jù)將以Cursor對象返回骡澈。因此,從Content Provider返回的數(shù)據(jù)是二維表的形式掷空。

(3).Broadcast可以向android系統(tǒng)中所有應用程序發(fā)送廣播肋殴,
而需要跨進程通訊的應用程序可以監(jiān)聽這些廣播;
廣播是一種被動跨進程通訊的方式坦弟。當某個程序向系統(tǒng)發(fā)送廣播時护锤,其他的應用程序只能被動地接收廣播數(shù)據(jù)。這就象電臺進行廣播一樣酿傍,聽眾只能被動地收聽烙懦,而不能主動與電臺進行溝通。

(4)Service這種可以跨進程通訊的服務叫AIDL服務拧粪。
注意普通的Service并不能實現(xiàn)跨進程操作修陡,實際上普通的Service和它所在的應用處于同一個進程中沧侥,而且它也不會專門開一條新的線程,因此如果在普通的Service中實現(xiàn)在耗時的任務魄鸦,需要新開線程宴杀。
要實現(xiàn)跨進程通信,需要借助AIDL(Android Interface Definition Language)拾因。Android中的跨進程服務其實是采用C/S的架構(gòu)旺罢,因而AIDL的目的就是實現(xiàn)通信接口。

Socket 其實也可以實現(xiàn)跨進程調(diào)用绢记,但是一般使用在網(wǎng)絡通信中扁达。

20.Android多線程實現(xiàn)
(1).繼承Thread類

(2).實現(xiàn)Runable接口

(3).線程池

Executors.newFixedThreadPool 定長線程池,可以控制最大并發(fā)數(shù)蠢熄,超出的線程會在隊列中等待

Executors.newScheduledThreadPool 帶有周期性質(zhì)的定長線程線程跪解,支持定時和周期任務的執(zhí)行

Executors.newCachedThreadPool 可緩存的線程池,如果線程池長度超多處理的需要签孔,可以靈活回收空閑線程叉讥,
如果沒有可以回收的,也可新建線程饥追。

Executors.newSingleThreadExecutor 單線程化的線程池图仓,他確保了所有的任務都在一個線程中執(zhí)行,不存在線程同步的問題

5個參數(shù)
new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()但绕,
ThreadFactory,
RejectedExecutionHandler


1.newFixedThreadPool coreThread=2 ,nocoreThread=2
2.newSchduledThreadPool coreThread=2 ,nocoreThread=Integer.maxvalue
3.newCacheThreadPool coreThread=0,nocoreThread=Integer.maxvalue
4.newSingleThreadExcutor coreThread=0,nocoreThread=0

21.MVC模式,MVP模式,MVVM模式

MVC模式
Modle JavaBean
View xml
Controler Activity業(yè)務邏輯救崔,數(shù)據(jù)處理,UI處理
特點:所有的數(shù)據(jù)處理捏顺,UI處理都在Activity中六孵,導致Activity上千行代碼,非常冗余

MVP模式 compositeSubscrition(Rxjava1) compositeDisposed(Rxjava2)
BasePresenter{ addDisposed() removeDisposed(compositeDispose.disposed())}

BaseView { showLoading() , hideLoading()}

HomePresenter接口 HomeView接口

abstract BaseActivity<P extends BasePrestener> P createPresenter (){ new HomePresenter(this)};

MVVM模式
BaseViewModel{ addDisposed removeDisposed}

abstract BaseActivity<M extends BaseViewModel> M createViewModel() onDestory { viewModel.removeDisposed()}

HomeViewModel {
HomeViewModel(Activity context,ViewDataBinding databing){}

context.showDialog()
addDisposed{}   處理各種請求
context.disDialog() 

}

RecycleView多布局
onBindViewHolder onCreateViewHolder
ItemFruitBinding itemFruitBinding = DataBindingUtil.inflate(inflater, R.layout.item_fruit, parent, false);
return new FruitViewHolder(itemFruitBinding);

((FruitViewHolder) holder).getBinding().setItem(fruitBean);
((FruitViewHolder) holder).getBinding().executePendingBindings(); //解決databinding閃爍問題

22.框架原理
Glide
(1).三級緩存
內(nèi)存緩存(skipMemoryCache(true))
磁盤緩存 diskCacheStrategy(DiskCacheStrategy.None)

DiskCacheStrategy.None 不緩存

DiskCacheStrategy.All 緩存所有

DiskCacheStrategy.RESULT 緩存轉(zhuǎn)換過的

DiskCacheStrategy.SOURCE 只緩存原圖
網(wǎng)絡讀取
默認的內(nèi)存磁盤緩存目錄:data/data/包名/cache/image_manager_disk

默認的內(nèi)存磁盤緩存目錄:Android/data/包名/cache/

(2).源碼分析
Glide綁定生命周期幅骄,Glide.with()根據(jù)傳入的context對象和當前的線程創(chuàng)建不同的

RequestManager實例狸臣,如果是在UI線程中,context是Activity昌执,則會創(chuàng)建一個能感知

Activity生命周期的RequestManager烛亦,如果context是Fragment,則會創(chuàng)建一個能感知

Fragment生命周期的RequestManager,如果是在非UI線程中或者傳入ApplicationContext懂拾,則會一個applicationManager

對象煤禽,能感知application的生命周期,在創(chuàng)建RequestManager的同時岖赋,也會創(chuàng)建一個

SupportRequestManagerFragment檬果,里面有onAttach,onStart,onStop,onDestory,onDetach等生命周期的方法,停止加載
圖片,釋放資源选脊。

與Picasso的對比:
Glide可以加載Gif杭抠,Picasso不能.

Picasso.with()只能接受context作為參數(shù),但是glide的可以是
context,activity恳啥,fragment glide能根據(jù)context的類型動態(tài)的
加載和釋放資源偏灿,更加靈活。

23.Retrofit2.0
(1).創(chuàng)建和用法
mRetorift=new Retrofit.Builder().baseUrl(Base_URL).client(new OkHttpClient())
.addConvertFactory(GsonConverterFactory.create())
.addCallAdapterFactory(Rxjava2CallAdapterFactory.create()).build().

Get請求
@GET("article/list/{type}?")
Call<QiushiModel> getInfoList(@Path("type") String type, @Query("page") int page);

GET請求提交數(shù)據(jù)
@GET
("MyWeb/RegServlet") Call<ResponseBody> getRegInfo(@QueryMap Map<String, String> map);

@GET
Observable<CheckVersionBean> getCheckVersion(@Url String url);

Post上傳多個文件钝的,同時上傳表單數(shù)據(jù):
@POST("MyWeb/UPloadServlet")
Call<ResponseBody> postUploadFilesMultipartBody(@Body MultipartBody multipartBody);}

@POST("/member/login")
Observable<UserBean> getLogin(@Body RequestBody requestBody);

@FormUrlEncoded
@POST("MyWeb/RegServlet")
Call<ResponseBody> postFormFieldMap(@FieldMap Map<String , String> map);

(2).動態(tài)代理(代理類ApiService在程序運行時動態(tài)生成翁垂,這種方式就叫做動態(tài)代理)
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();

      @Override public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable {
        // If the method is a method from Object then defer to normal invocation.
        if (method.getDeclaringClass() == Object.class) {
          return method.invoke(this, args);
        }
        if (platform.isDefaultMethod(method)) {
          return platform.invokeDefaultMethod(method, service, proxy, args);
        }
        ServiceMethod<Object, Object> serviceMethod =
            (ServiceMethod<Object, Object>) loadServiceMethod(method);
        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
        return serviceMethod.callAdapter.adapt(okHttpCall);
      }
    });

}

Proxy.newProxyInstance(classLoader,class[],new InvocationHanlder({
public object invoke(){
return ;
}

}))

24.Rxjava 類似于觀察者模式,是一個可以完成異步任務硝桩,基于事件的程序庫沿猜。
(1).
Observable(被觀察者)
Observer 觀察者 Consumer 消費者,顧客 ,Subscriber 訂閱者
subscribe 訂閱
Map遍歷List<Student>的每門課程的成績
Observable.form(studentList).map(new Func1(Student,List<Course>){

             public List<Course> call(student){
                   return student.getCourseList();
             }

}).subscribe(new Action1<List<Course>>(){
public void call( List<Course> courseList){
for(){
course.getScore
}
}
})

flatMap遍歷List<Student>的每門課程的成績
Observable.form(studentList).flatmap(new Func1(Student,Observable<Course>){
public Observable<Course> call(student){
return Observable.from(student.getCourseList);
}
}).subscribe(new Action1<Course>(){
public void call(Course course){
course.getScore
}
})

(2).取消訂閱
取消訂閱:
!dispose.isDisposed dispose.disposed();

compositeDispose.disposed();

compositeSubcrition.unScribe();

(3)操作符:
just ,from ,create map floatMap

map:將一種類型的數(shù)據(jù)轉(zhuǎn)換成另外一種類型的數(shù)據(jù)碗脊。Integer, String
Observable.just(666).map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {//Integer---->String
return integer+"";
}
}).map(new Func1<String, Long>() {
@Override
public Long call(String s) {
return Long.parseLong(s);
}
}).subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
Log.i(TAG,"call:"+aLong);
}
});

floatMap:將原數(shù)轉(zhuǎn)換成新的Observable Student, Observable<Course>

List<Student> students= DataUtils.getStudentList();
Observable.from(students).flatMap(new Func1<Student, Observable<Course>>() {
@Override
public Observable<Course> call(Student student) {
return Observable.from(student.getCourses());
}
}).subscribe(new Action1<Course>() {
@Override
public void call(Course course) {
Log.i("TAG","couseName:"+course.getCourseName);
}
});
Map: Observable.form(students).map(new Func1(Student,List<Cource>){
pulbic List<Course> call(Student student){
retrurn student.getCourseList()
}
}).subcribe(new Action1(List<Course> courseList){
courselist.foreach{
course.getName()
}
})

(4).線程調(diào)度
Scheduler.io()
AndroidSchedulers.mainThread()
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});

25.Okhttp (RequestBody,MultipartBody)
(1).構(gòu)建請求的方式
new Okhttp().newCall(new Reuqest.Builder().url.post(requestBody).build()).enqueue(new Callback(){

 onFailture()
 
 onResponse()

}))

(2).原理

new Okhttp().newCall(request)--->RealCall()---->

同步--->execute()

異步---enqueue()----->dispatcher---->execute()

execute---> getResponseWithInterceptorChain()

getResponseWithInterceptorChain()----> new List<interceptors>().addAll(自定義的責任人)

RetryAndFollowUpInterceptor 重試,重定向

BrideInterceptor 橋接啼肩,添加http請求頭【host請求頭】

CacheInterceptor 處理緩存,判斷是否需要緩存

ConnectInterceptor 建立https連接

CallServerInterceptor ----->Response {code ,message ,header,body}

RealInterceptorChain ----->遞歸調(diào)用衙伶,index+1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);

25.熱更新的實現(xiàn)原理
(1).AndroidFix (https://github.com/alibaba/AndFix
A:加載方式(init loadPatch addPatch)

mPatchManager = new PatchManager(this);
mPatchManager.init("1.0");
mPatchManager.loadPatch();
String patchFileString = Environment.getExternalStorageDirectory()
.getAbsolutePath() + APATCH_PATH;
mPatchManager.addPatch(patchFileString);

B:生成補丁的命令

apkpatch.bat -f 新apk -t 舊apk -o 輸出目錄 -k app簽名文件 -p 簽名文件密碼 -a 簽名文件別名 -e 別名密碼

將生成的補丁手動放到SD目錄下或者自己從云端下載下來疟游。

C:原理
通過Native層,使用指針替換的方式替換bug痕支,達到修復。
不能修改xml布局文件蛮原,資源文件無法替換

(2).Bugly熱更新
A:集成方式
重寫SmapleApplicationLike extends DefaultApplicationLike

配置基準thinkId卧须,assembleRelease編譯生成基準包,修改代碼后儒陨,

根據(jù)基線版本生成補丁包花嘶,然后將補丁包patch_signed.apk上傳。

B:原理
通過base.apk(base.dex) 和Fix.apk(fix.dex) 生成 patch.apk(patch.dex)

patch.dex和本地的base.dex 合并生成新的patch_base.dex文件蹦漠,然后重新啟動

就可以了椭员。(patch.dex插入到dexElements數(shù)組的前面,同時刪除舊的base.dex)

C:優(yōu)勢
Tinker熱補丁方案不僅支持類笛园、So以及資源的替換隘击,
Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大組件

25.Jpush推送的實現(xiàn)原理
(1).從寫MyJPushMessageReceiver
處理自定義消息:

if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);

if (!TextUtils.isEmpty(message)) {
PushBean mBean = mGson.fromJson(message, PushBean.class);
mNotificationUtils.simpleNotify(context, mBean);
}

用戶打開通知:

JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())

(2).登錄后使用Id作為綁定的別名研铆。

JPushInterface.setAlias(getApplicationContext(), Integer.parseInt(bean.getResultObject().getUserId());

集成Jpush時埋同,我們已經(jīng)把應用的包名,appkey值棵红,發(fā)到Jpush服務端進行注冊凶赁,然后本地集成了JpushReceiver的BroadCastReceiver,在onReceiver

中,通過官方提供的各種Action虱肄,分類處理各種服務端推送過來的消息致板。

26.Inflate解析文件的原理

inflate() ---->獲取根節(jié)點的名稱--->調(diào)用createViewFragTag通過class.forName反射的方式創(chuàng)建根View,

通過調(diào)用rInflate咏窿,遍歷該View下面的子View斟或,如果子View中還有子View,那么會遞歸性的調(diào)用rInflate()翰灾,

直到遍歷完所有的View缕粹,不在進入while循環(huán),最后調(diào)用parent.onFinishInflate()遍歷完結(jié)

27.Java虛擬機和Delivk虛擬機的區(qū)別

(1)Java虛擬機運行的是java字節(jié)碼纸淮,但是Dalvik運行的是dex文件

(2).Java虛擬機是基于棧平斩,需要用指令來載入和操作數(shù)據(jù),Dalvik是基于寄存器的咽块,能有效減少指令的

分發(fā)和減少內(nèi)存的讀寫訪問绘面。

28.Context 有哪幾種,都有什么區(qū)別

(1)Application繼承自ContextThemeWrap(帶主題的相關類侈沪,內(nèi)部包含了主題相關的接口揭璃,可

以加在主題),Activity和Service繼承自ContextWrap亭罪,并不需要加載主題瘦馍。

(2)生命周期不一樣,applicaton和應用的生命周期綁定应役,但是activity和service的自身的生

命周期綁定情组。

(3)使用的場景也會有不一樣,比如啟動一個activity箩祥,show一個dialog院崇,或者

layotuInflate解析一個文件都只能使用activity用了,application和service不可以袍祖。

(4)applicaton一個底瓣,activity和service有多個。

28.線程中sleep和wait有啥區(qū)別蕉陋。

(1).一個來自Thread類捐凭,一個來自Object類

(2).sleep沒有釋放鎖而wait方法釋放了鎖,使得其他的線程可以使用同步代碼塊凳鬓,或者方法.

sleep不出讓系統(tǒng)資源柑营,wait進入線程池等待,出讓系統(tǒng)資源村视,一直等到notify/notifyAll,

才會從新進入就緒隊列等待OS分配系統(tǒng)資源

(3).使用范圍不同官套,wait,notify和notifyAll只能在同步代碼塊,或者同步方法中使用奶赔,但是

sleep可以在任何地方使用惋嚎。

(4).sleep必須要捕獲異常,但是wait,notify和notifyAll不需要捕獲異常站刑。

29.queue和Stack有啥不同
(1).隊列先進先出另伍,棧先進后出
(2).隊列只能在表尾進行插入,在表頭的進行刪除绞旅,棧只能在表尾(棧頂)進行插入和刪
除操作

(3).遍歷數(shù)據(jù)的速度不同
隊列遍歷的速度更快摆尝,從隊頭或者隊尾開始遍歷,它是基于地址指針進行遍歷因悲,不需要另外的開
辟臨時空間堕汞,不影響數(shù)據(jù)的結(jié)構(gòu)。
棧遍歷的速度比較慢晃琳,只能從棧頂開始遍歷讯检,為了保證遍歷前的一致性,需要另外開辟臨時空間卫旱。

(4).隊列:應用的范圍也不一樣人灼,線程池,消息傳遞機制顾翼,以及系統(tǒng)中的各種資源的管理等用到的一般都是隊列投放。

棧的:問題的求解,函數(shù)調(diào)用和遞歸實現(xiàn),計算機中斷适贸,數(shù)據(jù)保存和恢復灸芳。

30.ArrayList和LinkedList有啥區(qū)別
(1).arrayList是基于動態(tài)數(shù)組,linkedList是基于雙向鏈表取逾。

(2).對于隨機訪問get和set,ArrayList優(yōu)于LinkedList苹支,因為ArrayList可以隨機定位砾隅,
而LinkedList要移動指針一步一步的移動到節(jié)點處。

(3).對于新增和刪除操作add和remove债蜜,LinedList比較占優(yōu)勢晴埂,只需要對指針進行修改即可,

而ArrayList要移動數(shù)據(jù)來填補被刪除的對象的空間.

31.Android項目安全性(混淆,加固)

minifyEanble true

proguard-android.txt

-keep 保留某個類不被混淆

-dontwarn去除警告

android四大組件不應該被混淆

使用了自定義控件那么要保證它們不參與混淆

對第三方庫中的類不進行混淆

使用了 Gson 之類的工具要使 JavaBean 類即實體類不被混淆

32.Android動畫
(1).View動畫
TranslateAnimation
ScaleAnimation
RotateAnimation
AlphaAnimation

AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
view.startAnimation(animation);

(2).屬性動畫 3.0之后

ObjectAnimator
ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).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屬性方法
}
});

AnimatorSet 動畫組合寻定,時播放儒洛、順序播放或延遲播放

ObjectAnimator a1 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0f);
ObjectAnimator a2 = ObjectAnimator.ofFloat(view, "translationY", 0f, viewWidth);
......
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(5000);
animSet.setInterpolator(new LinearInterpolator());
//animSet.playTogether(a1, a2, ...); //兩個動畫同時執(zhí)行
animSet.play(a1).after(a2); //先后執(zhí)行
......//其他組合方式
animSet.start();

(3).幀動畫
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"

android:oneshot=["true" | "false"] >

<item
android:drawable="@[package:]drawable/drawable_resource_name"

android:duration="integer" />

</animation-list>

rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();

(4).6.0之后觸摸反饋動畫

Ripple

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#4285f4">
</ripple>

Reveal 揭露動畫

ViewAnimationUtils.createCircularReveal()

Transition Animation 轉(zhuǎn)場動畫

你需要給共享元素的兩個View設置相同的android:transitionName屬性值

layout/activity_a.xml

<ImageView
android:id="@+id/small_blue_icon"
style="@style/MaterialAnimations.Icon.Small"
android:src="@drawable/circle"
android:transitionName="@string/blue_name" />

layout/activity_b.xml

<ImageView
android:id="@+id/big_blue_icon"
style="@style/MaterialAnimations.Icon.Big"
android:src="@drawable/circle"
android:transitionName="@string/blue_name" />

String transitionName = getString(R.string.blue_name);

    ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
    startActivity(i, transitionActivityOptions.toBundle());

SVG矢量動畫,通過Path路徑構(gòu)建動畫

33.安卓內(nèi)存優(yōu)化
https://blog.csdn.net/tuke_tuke/article/details/52316285

Bitmap不被使用的時候recycle掉

Cursor和I/O流及時關閉

BroadCastReceiver狼速、Service

線程不再需要繼續(xù)執(zhí)行的時候要記得及時關閉,開啟線程的時候琅锻,使用線程池

使用Rxjava做網(wǎng)絡請求的時候,在Activity銷毀的時候,取消訂閱

使用FindBus和Lint代碼檢查工具恼蓬,提高代碼質(zhì)量

34.UDP&TCP的區(qū)別和應用場景
https://www.cnblogs.com/williamjie/p/9390164.html

相同點:UDP協(xié)議和TCP協(xié)議都是傳輸層協(xié)議
打電話之前先撥號
TCP:面向連接的,可靠性高惊完,基于字節(jié)流的,中間會有三次握手來建立連接处硬,但是占用的系統(tǒng)資源高小槐,容易被攻擊,荷辕。
Socket socket = new Socket("111.111.11.11", 12306);//111.111.11.11為我這個本機的IP地址凿跳,端口號為12306.
socket.getInputStream
socket.getOutputStream

實時視頻會議
UDP是面向非連接的,可靠性低疮方,基于字節(jié)流控嗜,在網(wǎng)絡不好的時候,容易丟包案站,但是傳輸速度很快躬审,效率比較高,基于用戶數(shù)據(jù)報的蟆盐。
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, 12306);
socket.send(packet);
socket.receive(receiverPacket);

TCP/IP五層模型詳解
應用層 各種網(wǎng)站承边,App
傳輸層 TCP / UDP協(xié)議
網(wǎng)絡層
數(shù)據(jù)鏈路層
物理層 計算機 + 光纜 +計算機

TCP的三次握手4次揮手過程
https://www.cnblogs.com/bj-mr-li/p/11106390.html

35.http和https協(xié)議
https://juejin.cn/post/6844904065227292685
http://www.reibang.com/p/7a40e874f6c2?utm_source=oschina-app

https客戶端和服務端建立SSL連接的過程:

(1).客戶端發(fā)起請求,服務端會把公鑰發(fā)給客戶端石挂。

(2).android客戶端利用本地證書對公鑰進行校驗博助,合法的話,生成一個隨機值并用服務端給的公鑰進行加密痹愚,

然后傳給服務端富岳,服務端利用私鑰進行解密,此時客戶端和服務端都有這個隨機值拯腮,然后利用這個隨機值作為

二邊的私鑰窖式,建立SSL連接,開始通信动壤。

36.Kotlin

(1).?. null safety,object直接創(chuàng)建單例,compain Object (相當于static,可以通過類.方法名調(diào)用)
屬性委托(protected var isLogin:Boolean by Preference(Constant.LOGIN_KEY,false))

(2).主要構(gòu)造函數(shù)和次級構(gòu)造函數(shù)(Secondary Constructor是定義在類體中萝喘。第二,Secondary Constructor
可以有多個琼懊,而Primary Constructor只會有一個阁簸。)
主要構(gòu)造函數(shù):
class Person constructor(username: String, age: Int){

private val username: String

private var age: Int

init{
this.username = username

this.age = age

   }

}

class Person (username: String, age: Int){

private val username: String

private var age: Int

init{
this.username = username

this.age = age

   }

}
次級構(gòu)造函數(shù):
class User{

private val username: String

private var age: Int

constructor(username: String, age: Int){

this.username = username

this.age = age

}

}

(3).為什么要轉(zhuǎn)戰(zhàn)kotlin
kotlin比Java要簡單。它去除了很多Java里面的冗余代碼,而且有很多新的特性
比如說不用findViewById,在xml定義Id之后哼丈,直接可以在代碼中引用启妹,
類擴展,直接給類添加方法醉旦,而不需要繼承饶米。
fun Activity.showSnackMsg(msg:String){
val snackbar=Snackbar.make(this.window.decorView,msg,Snackbar.LENGTH_SHORT)
val view=snackbar.view
view.findViewById<TextView>(R.id.snackbar_text).setTextColor(ContextCompat.getColor(this,R.color.white))
snackbar.show()
}

(4).聲明變量桨啃,支持面向?qū)ο蠛兔嫦蜻^程編程, range操作符 for(1 in 1...15)
var a:Int  kotlin類缺省是final的咙崎。因為kotlin支持多重類繼承优幸。開放類代價要比final類高很多,
如果一個類可以被繼承或者方法被重寫,必須open

PlayAndroid

設置白天黑夜模式:
value-night DayNight主題
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)

37.啟動模式

https://blog.csdn.net/qq_25901775/article/details/50590309

Standard 標準模式 每次啟動一個Activity都會又一次創(chuàng)建一個新的實例入棧褪猛,無論這個實例是否存在

SingleTop 棧頂復用模式 須要創(chuàng)建的Activity已經(jīng)處于棧頂時网杆,此時會直接復用棧頂?shù)腁ctivity。
不會再創(chuàng)建新的Activity伊滋, onNewIntent會被回調(diào)

SingleTask 棧內(nèi)復用模式 將存在棧中的Activity上面的其他Activity所有銷毀碳却,使它成為棧頂,onNewIntent

SingleInstance 單實例模式 系統(tǒng)會為它創(chuàng)建一個單獨的任務棧笑旺,由于棧內(nèi)復用的特性昼浦,不會創(chuàng)建新的Activity,除非這個獨特的任務棧被系統(tǒng)銷毀

38.Android系統(tǒng)架構(gòu) (https://blog.csdn.net/cpq37/article/details/5708649)

(1).Application 應用層

(2).Application Fragmework

ActivityManager PackageManager WindowManager NotificationManager

(3).Library 系統(tǒng)運行庫

SQLite Webkit

(4).Linx內(nèi)核層
Wifi Driver USB Driver CameraDriver

  1. Android性能分析
    LeakCanary 它能實時的告訴我具體哪個類發(fā)現(xiàn)了內(nèi)存泄漏

TraceView 測量函數(shù)耗時

SysTrace

MAT

Hierarchy(hai:ra:k) Viewer 測量View的布局層次筒主,已經(jīng)每個View的刷新時間关噪。
使用Merge,ViewStub標簽優(yōu)化重復的布局乌妙,盡量多使用Constraintlayout

使用自定義View

40.哪些情況可能會導致內(nèi)存泄露

(1).資源使用完沒有關閉
BroadCastReceiver File Crusor database Bitmap

(2).Timer或者TimeTask不使用的時候使兔,必須取消。

(3).Handler或則Runnable做為非Static內(nèi)部類可能導致內(nèi)存泄漏藤韵。

41.如果避免OOM

(1).減少內(nèi)存對象的暫用虐沥。
盡量少用Bitmap ,減少資源圖片的大小,過大的圖片可以壓縮泽艘,盡量不用Enum

或者設置暫用內(nèi)存較低的解碼格式decode formate
ARGB_888【8bit】
RGB_564 【4bit】

(2).自定義View的時候欲险,盡量不要在onDraw里面new 對象, 自定屬性的時候匹涮,記得recycle().

(3).避免內(nèi)存泄露(內(nèi)存對象的泄漏天试,會導致一些不再使用的對象無法及時釋放,
這樣一方面占用了寶貴的內(nèi)存空間然低,很容易導致后續(xù)需要分配內(nèi)存的時候喜每,空閑空間不足而出現(xiàn)OOM)

42.ANR怎么樣避免和解決?
(1).應該避免在UI線程中處理復雜的邏輯和計算脚翘,還有耗時操作灼卢。
(2).在Activity的onCreate绍哎,onResume里面也不要做耗時的操作来农。盡量把耗時的操作交給異步線程。
(3).如果有耗時炒作崇堰,使用線程池或者AsyncTask處理沃于,協(xié)程也可以~涩咖。

主線程存在耗時操作,導致阻塞
按鍵或觸摸事件在5s內(nèi)主線程沒喲響應
BroadcastReceiver 前臺廣播在10s內(nèi)繁莹,沒有返回值檩互,也會導致ANR
啟動的Service在20s內(nèi)沒有完成,也會導致ANR

43.android線程間的通信

handler runOnUiThread view.post Rxjava .io .mainThread(線程調(diào)度)

44.Android屏幕適配
(1).盡量用dp適配屏幕咨演,sp作為字體單位

(2).xml布局的時候闸昨,盡量使用weight

(3).代碼中獲取屏幕的寬高,按比例動態(tài)設置薄风,

(4).特殊機型饵较,可以使用value-sw1080,mipmap-w600dp

(5).約束布局

46.android進程保活機制
內(nèi)存不足
省電機制
用戶清理

如何痹饴福活進程:
(1).鎖屏的時候循诉,掛1像素的Activity到前臺,提高進程的優(yōu)先級撇他,鎖屏的時候關閉茄猫。

(2).啟動一個前臺Service,Service困肩。SERVICE_ID=1

(3).雙進程拉活划纽。

(4).監(jiān)聽開機,鎖屏等系統(tǒng)廣播拉活僻弹。

(5).監(jiān)聽其他大廠的廣播阿浓,拉活。

47.打包優(yōu)化

代碼混淆
去除無用的資源 shrinkResouce true
圖片壓縮
so 庫配置 abiFilter armeabi armeabi-v7a

把圖片放在云端蹋绽,通過鏈接聯(lián)網(wǎng)加載芭毙。

48.ButterKnife源碼分析 https://www.cnblogs.com/tony-yang-flutter/p/12483127.html

ButterKnife.bind(this)----> 會構(gòu)造一個包名+類名+_ViewBinding的構(gòu)造函數(shù)類,通過constructor.newInstance()返回這個綁定的對象卸耘。

MainActivity_ViewBind.java ,這個類在編譯的時候退敦,通過ButterProcessor生成的,繼承了抽象類AbstractProcessor,AbstractProcessor實現(xiàn)了

Processor接口蚣抗,init getSupportAnnotationTypes getSupportedAnnotations ,process

最重要的就是Process方法侈百,,首先通過findAndParseTarget()得到一個bindingMap對象翰铡,這個對象 類名稱(key)承粤, 注解屬性(BindingSet)巧骚,

BindingSet存儲的是生成類的基本信息以及注解元素的基本信息,通過遍歷這個bindingMap生產(chǎn)對應的java文件。

當我們調(diào)用ButterKnife的bind()方法的時候隔心,它會根據(jù)類的全限定類型踏兜,找到相應的模板代碼军拟。

45.GreenDao ,Realm數(shù)據(jù)庫 對象關系數(shù)據(jù)映射
Realm和GreenDAO有很大的不同,Realm本身就是一種數(shù)據(jù)庫胀葱,而且是可以支持跨平臺的數(shù)據(jù)庫,比SQLite更輕量級笙蒙,速度也更快抵屿,支持JSON格式、數(shù)據(jù)變更通知捅位、數(shù)據(jù)同步等等特性.

http://www.reibang.com/p/12c46d38f6a9

@Entity
public class Student {
@Id(autoincrement = true) Long id;
String name;
int age;
String grades;
@ToMany(referencedJoinProperty = "studentId")
List<Course> courseList;
}
生成 DaoMaster DaoSesion 各種Dao類

Realm.init(this);支持新增字段
Realm.setDefaultConfiguration(configuration);

public class Student extends RealmObject{}
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Student student = new Student();
student.setName("小明");
student.setAge(18);
student.setGrades("一年級");
realm.copyToRealm(student);
}
});

49.Flutter

widget在flutter里基本是一些UI組件

有兩種類型的widget轧葛,分別是statefulWidget 和 statelessWidget兩種

statelessWidget不會自己重新構(gòu)建自己,但是statefulWidget

Hot Reload

50.Glide 三級緩存源碼分析
http://www.reibang.com/p/ba7f38ede854

51.App啟動優(yōu)化艇搀。

1s 左右的白屏閃現(xiàn)朝群, 低版本黑屏

windowBackground windowIsTranslucent

沒有白屏但是中間還是有一小段不可見,增加了Splash 的廣告頁中符,增加了倒計時

TraceView檢測函數(shù)的耗時情況姜胖,一個是懶加載,在一個就是使用線程池初始化 newSingleExcutor

精簡xml布局

52.Lrucachef原理
https://blog.csdn.net/Coo123_/article/details/105143502

52.livedata保存數(shù)據(jù)淀散,可以感知Activity的生命周期右莱,是一個可被觀察的數(shù)據(jù)持有類,
因此可以做到僅在組件處于生命周期的激活狀態(tài)時才更新UI數(shù)據(jù)档插。
子線程:postValue
主線程:setValue
粘性事件
livedata.observer(this,Observer(){
onChange(){

  } 

})

53.Lifycycle使用和原理(解耦頁面和組件)
Activity慢蜓,F(xiàn)ragment 都實現(xiàn)了LifecycleOwner,標志著他們都是
具有l(wèi)ifecycle的組件郭膛。
Lifecycle是抽象類晨抡,唯一的具體實現(xiàn)類為LifecycleRegistry
A:注冊流程:
getLifecycle().addObserver(LifecycleObserver observer)
getLifecycle().addObserver(MyObserver())
public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void prepare(){
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void release(){
}
}
//addObserver注冊干了二件事情
public class LifecycleRegister{
public void addObserver(observer){
ObserverWithState obstate=new ObservverWithState(observer,state)
map.add(observer,obstate);
}
}

ObservverWithState這個類,
(1).把observer轉(zhuǎn)換成LifecycleEventObserver

(2).dispatchEvent(){
observer.onStateChanged(lifecycleOwner,envet)//真正調(diào)用
}

B:調(diào)用流程
1.注入了一個沒有UI的ReportFragment
AppCompatActivity-->FragmentActivity-->ComponentActivity{

 onCreate(){ 
     ReportFragment.injectIfNeededIn(this);
}

}

public class ReportFragment {
onCreate(){ dispath(Lifecycle.Event.ON_CREATE)}
onStart(){dispath(Lifecycle.Event.ON_START)}
onResume(){dispath(Lifecycle.Event.ON_RESUME)}
onPause(){dispath(Lifecycle.Event.ON_PAUSE)}
onStop(){dispath(Lifecycle.Event.ON_STOP)}
onDestory(){dispath(Lifecycle.Event.ON_DESTORY)}
}
public void dispath(event){
getActivity().getLifecycle().handleLifecycleEvent(event)
}

handleLifecycleEvent(){
sync()
}
sync(){
while( map.hasnext){
map.getvalue().dispatchEvent()
}
}

dispatchEvent(){
observer.onStateChanged(licycleOwener,event)
}
class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
Map map=new HashMap(event,method)
public void onStateChanged(LifecycleOwner source, Event event){
switch (event) {
case ON_CREATE:
map.get(event).invoke()//prepare
break;
case ON_START:
break;
case ON_RESUME:
break;
case ON_PAUSE:
break;
case ON_STOP:
break;
case ON_DESTROY:
map.get(event).invoke() //release
break;
case ON_ANY:
throw new IllegalArgumentException("ON_ANY must not been send by anybody");
}
}
}

54.ViewModel 【ViewModel 類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存则剃≡胖】
https://mp.weixin.qq.com/s/-Zxf_560jgjWo_pRhxJBew
獲取ViewModel
ViewModelProvider(this).get(ScoreListViewModel::class.java)
(a):為什么Activity旋轉(zhuǎn)屏幕后ViewModel可以恢復數(shù)據(jù)。
屏幕旋轉(zhuǎn)的時候棍现,會觸發(fā)
onRetainNonConfigurationInstance (){
通過 NonConfigurationInstance 內(nèi)部類保存ViewModelStore實例對象
}
調(diào)用ViewModelProvider(this)调煎,會先調(diào)用this.getViewModelStore(),通過
getLastNonConfigurationInstance (){
從NonConfigurationInstance 內(nèi)部類中取ViewModelStore的實例對象。
}
取ViewModelStore實例對象,如果不存在就new ViewModelStore(),然后return己肮,
因為viewmodelstore沒有變化士袄,所以可以恢復數(shù)據(jù)。

(b):ViewModel 的實例緩存到哪兒了谎僻。
ViewModel 對象存在了 ComponentActivity 的 mViewModelStore 對象中娄柳。

(c):什么時候 ViewModel#onCleared() 會被調(diào)用。
public ComponentActivity(){
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(LifecycleOwner source,Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
ViewModel 類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存艘绍。
ViewModel 只有在正常 Activity finish 時才會被清除赤拒。

55.viewModelScope是如何做到自動解綁網(wǎng)絡請求的
調(diào)用ViewModel中的setTagIfAbsent方法返回CloseableCoroutineScope()實例。
創(chuàng)建一個CloseableCoroutineScope()實例鞍盗,并使用map把CloseableCoroutineScope()實例存起來
(1).viewModelScope get(){
return setTagIfAbsent(JOB_KEY,
CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
}
clear(){
map.foreach{
closeableCoroutine.close()
}
}
public class CloseableCoroutineScope:Closeable,CoroutineScope{
void close(){
coroutineContext.cancel()
}
}

56.DataBinding
雙向綁定 使用ObservableFiled<String,Int,User>
單向綁定 不使用ObservableFiled就是單向綁定
mDataBind=DataBindingUtil.inflate(inflater,layoutId(),container,false)
mDataBind= DataBindingUtil.setContentView(this,layoutId())
RecycleView和DataBinding進行綁定

57.HashMap(https://juejin.cn/post/6844904084219101197
57.1.JDK1.7---數(shù)組+鏈表 JDK1.8---數(shù)組+鏈表+紅黑二叉樹
57.2.map.put(k,v)實現(xiàn)原理
前提條件需了,如果table等于null,那就resize擴容般甲,初始化table
(1)首先將k,v封裝到Node對象當中(節(jié)點)肋乍。
(2)然后它的底層會調(diào)用K的hashCode()方法得出hash值。
(3)通過哈希表函數(shù)/哈希算法敷存,將hash值轉(zhuǎn)換成數(shù)組的下標Index墓造,
下標位置上如果沒有任何元素,就把Node添加到這個位置上锚烦。
如果當前位置有元素觅闽,那就比較當前位置Node節(jié)點的key值和hash值,
如果相等涮俄,說明key存在蛉拙,直接替換值即可,如果不存在彻亲,那說明孕锄,當前的
節(jié)點可能是TreeNode,或者鏈表,如果說下標對應的位置是TreeNode
(instanceof TreeNode)苞尝,直接插入畸肆,
否者就一定是鏈表,此時宙址,就會拿著k和鏈表上每個節(jié)點的k進行equal比較轴脐。
如果所有的equals方法返回都是false,那么這個新的節(jié)點將被添加到鏈表的
末尾(JDK1.8尾插法)抡砂。如果其中有一個equals返回了true大咱,那么這個節(jié)點的
value將會被覆蓋∽⒁妫【如果鏈表的長度大于8且數(shù)組長度大于64的時候徽级,
就會把鏈表轉(zhuǎn)換成紅黑二叉樹】
57.3.map.get(k)實現(xiàn)原理
(1).先調(diào)用k的hashCode()方法得出哈希值,并通過哈希算法轉(zhuǎn)換成數(shù)組的下標聊浅。
(2).通過上一步哈希算法轉(zhuǎn)換成數(shù)組的下標之后餐抢,在通過數(shù)組下標快速定位到某個位置上。
如果這個位置上什么都沒有低匙,則返回null旷痕,如果當前位置有元素,那就比較當前位置Node節(jié)點
的key值和hash值顽冶,如果相等欺抗,說明改節(jié)點就在table數(shù)組中,直接返回强重,否則绞呈,如果這個位置
上是紅黑二叉樹(instanceof TreeNode)贸人,就會調(diào)用getTreeNode(hash,key)返回當前節(jié)點,
否則就是鏈表佃声,那么它就會拿著參數(shù)K和單向鏈表上的每一個節(jié)點的K進行equals艺智,
如果所有equals方法都返回false,則get方法返回null圾亏。如果其中一個節(jié)點的K和參數(shù)K進行equals返回true十拣,
那么此時該節(jié)點的value就是我們要找的value了,get方法最終返回這個要找的value志鹃。

57.4.hash(key)的源碼
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
key.hashCode() 獲取到的hashcode無符號右移16位并和原h(huán)ashCode進行^運算 夭问,
這樣做的目的是為了讓高位與低進行混合,讓兩者都參與運算曹铃,以便讓hash值分布更加均勻缰趋。

57.5數(shù)組索引index的計算采用的都是hash&(table.length-1)

58.ANR的常見場景
(1).5s內(nèi)未響應鍵盤輸入,或者屏幕觸摸事件陕见。
(2).Service TimeOut前臺Service在20s未執(zhí)行完任務埠胖,或者后臺Service在200s內(nèi)未執(zhí)行完任務。
(3).BroadCastReceiver TimeOut前臺BroadCastReceiver在10s內(nèi)未處理完廣播淳玩,后臺BroadCastRecevier在60s
內(nèi)未處理完廣播直撤。
(4).ContentProvider TimeOut在10s內(nèi)沒有處理完成任務
(5).大量的數(shù)據(jù)讀寫,耗時的網(wǎng)絡訪問蜕着,數(shù)據(jù)庫谋竖,硬件操作(比如Camera)

59.JVM內(nèi)存區(qū)域(https://mp.weixin.qq.com/s/8vXENzg580R7F2iNjSdHFw)
虛擬機棧 為虛擬機執(zhí)行Java方法時服務
本地方法棧 為虛擬機執(zhí)行Native方法時服務
程序計數(shù)器 行號指示器
堆 (對象實例和數(shù)組都是在堆上進行分配的,GC也主要對這二類數(shù)據(jù)進行回收)
本地內(nèi)存

59.1.垃圾識別
引用計數(shù)法 String ref=new String("Java") ref=null
可達性分析算法 如果相關對象不在任意一個以 GC Root 為起點的引用鏈中,
則這些對象會被稱為垃圾承匣,被GC回收蓖乘。

59.2.垃圾回收算法
(1).標記清除法(會產(chǎn)生內(nèi)存碎片)
(2).復制算法(內(nèi)存減少一半,效率低下)
(3).標記整理法(沒進行一次垃圾清除韧骗,都要頻繁的移動存活的對象嘉抒,效率十分低下)
(4).分代收集算法
根據(jù)對象存活周期的不同將堆分成新生代(Eden區(qū) 8,S0區(qū) 1袍暴,S1區(qū) 1)和老生代
第一次垃圾回收:會把Eden區(qū)的存活的對象放到S0區(qū)些侍,同時對象的年齡加1
第二次垃圾回收:會把Eden區(qū)和S0區(qū)的存活對象轉(zhuǎn)移到S1區(qū)

59.3.對象何時晉升到老年代
(1).當對象的年齡達到了我們設定的閾值,則會從S0或者S1晉升到老年代
(2).大對象政模,當某個對象分配需要大量連續(xù)的內(nèi)存時岗宣,此時對象的創(chuàng)建不會分配在
Eden區(qū),會直接分配在老年代淋样。

59.Validate和Synchrozied的區(qū)別(https://www.cnblogs.com/paddix/p/5428507.html
1.volatile就是輕量級的Synchrozied耗式,只能修飾變量,方法和代碼塊無法修飾,
實現(xiàn)可見性刊咳,修改了volatile變量時會強制將修改后的值刷新到主內(nèi)存中彪见。
會導致其他線程工作內(nèi)存中對應的變量值失效,因此娱挨,在讀取變量的時候余指,就需要重新
從主內(nèi)存中讀值。

60.靠這70道面試題让蕾,我斬獲了3個offer

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市或听,隨后出現(xiàn)的幾起案子探孝,更是在濱河造成了極大的恐慌,老刑警劉巖誉裆,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顿颅,死亡現(xiàn)場離奇詭異,居然都是意外死亡足丢,警方通過查閱死者的電腦和手機粱腻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斩跌,“玉大人绍些,你說我怎么就攤上這事∫唬” “怎么了柬批?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長袖订。 經(jīng)常有香客問我氮帐,道長,這世上最難降的妖魔是什么洛姑? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任上沐,我火速辦了婚禮,結(jié)果婚禮上楞艾,老公的妹妹穿的比我還像新娘参咙。我一直安慰自己,他們只是感情好硫眯,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布昂勒。 她就那樣靜靜地躺著,像睡著了一般舟铜。 火紅的嫁衣襯著肌膚如雪戈盈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音塘娶,去河邊找鬼归斤。 笑死,一個胖子當著我的面吹牛刁岸,可吹牛的內(nèi)容都是我干的脏里。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼虹曙,長吁一口氣:“原來是場噩夢啊……” “哼迫横!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酝碳,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤矾踱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后疏哗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呛讲,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年返奉,在試婚紗的時候發(fā)現(xiàn)自己被綠了贝搁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡芽偏,死狀恐怖雷逆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情污尉,我是刑警寧澤关面,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站十厢,受9級特大地震影響等太,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蛮放,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一缩抡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧包颁,春花似錦瞻想、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至岳悟,卻和暖如春佃迄,著一層夾襖步出監(jiān)牢的瞬間泼差,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工呵俏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留堆缘,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓普碎,卻偏偏與公主長得像吼肥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子麻车,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

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