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,"早去早回")
}
}
- 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
- 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)存中讀值。