開發(fā)網(wǎng)站商城流程優(yōu)化的七個(gè)步驟
文章目錄
- 深入理解并熟練運(yùn)用常用設(shè)計(jì)模式及反射原理,能夠自定義注解及泛型,多次通過設(shè)計(jì)模式對(duì) app 代碼進(jìn)行高效重構(gòu),顯著提升代碼的可維護(hù)性與擴(kuò)展性。
- 設(shè)計(jì)模式
- 自定義注解
- 泛型
- Kotlin泛型
- 精通多線程原理,對(duì) ThreadPoolExecutor 進(jìn)行過深度剖析,能夠精準(zhǔn)運(yùn)用多線程技術(shù)提升應(yīng)用性能與響應(yīng)速度。
- 多線程原理
- AQS
- ThreadPoolExecutor深度剖析
- 使用多線程技術(shù)提升應(yīng)用性能與響應(yīng)速度
- 熟練掌握自定義 View 原理,憑借對(duì)事件分發(fā)原理的深刻理解,有效解決各類 UI 交互問題,確保用戶體驗(yàn)的流暢性與友好性。
- 自定義View原理
- 事件分發(fā)機(jī)制
- View的設(shè)計(jì)模式
- 對(duì) Handler、Zygote、Binder、AMS 等機(jī)制有清晰認(rèn)知,長(zhǎng)期保持閱讀 Framework 層源碼的習(xí)慣,為應(yīng)用開發(fā)提供堅(jiān)實(shí)的技術(shù)支撐。
- 談?wù)剬?duì)Handler機(jī)制的理解
- 談?wù)剬?duì)Zygote機(jī)制的理解
- 談?wù)剬?duì)Binder機(jī)制的理解
- 談?wù)剬?duì)AMS機(jī)制的理解
- 談?wù)剬?duì)PMS機(jī)制的理解
- 談?wù)勍ㄟ^閱讀Framework層源碼解決的實(shí)際問題
- Android冷啟動(dòng)App
- Android熱啟動(dòng)App
- 啟動(dòng)一個(gè)Activity
- 熟練使用 systrace、traceview、AS profile 等多種性能監(jiān)控與優(yōu)化工具,在性能優(yōu)化、內(nèi)存泄漏上報(bào)(KOOM)以及用戶體驗(yàn)優(yōu)化方面積累了豐富的實(shí)際調(diào)優(yōu)經(jīng)驗(yàn)。
- systrace的使用
- traceView的使用
- Android sutio Profile的使用
- KOOM
- 熟練掌握 OKHttp/Retrofit 等第三方架構(gòu),精通 TCP/IP、HTTP 協(xié)議,在進(jìn)程?;罴夹g(shù)方面具備扎實(shí)的實(shí)踐經(jīng)驗(yàn),有效提升應(yīng)用的穩(wěn)定性與可靠性。
- 安卓面試 Okhttp源碼解析
- Retrofit源碼解析
- TCP/IP的理解
- TCP/IP協(xié)議棧模型
- TCP/IP的工作原理
- TCP/IP在安卓中的應(yīng)用
- HTTP協(xié)議
- HTTPS協(xié)議
- 進(jìn)程?;?/li>
- 如何提升應(yīng)用的穩(wěn)定性和可靠性
- 熟練掌握 Gradle 插件功能開發(fā),具備開發(fā)高質(zhì)量插件工具的能力,顯著提高項(xiàng)目構(gòu)建與開發(fā)效率。
- android studio gradle插件開發(fā)流程
- 熟練掌握安卓逆向技術(shù),熟練運(yùn)用 JAD、JEB、Frida、AndroidKiller、IDA 等工具,能夠深入分析與優(yōu)化應(yīng)用。
- 手機(jī)HTTPS抓包
- 使用Frida 脫殼
- 熟悉 IOS/Flutter 開發(fā),擁有上線項(xiàng)目經(jīng)驗(yàn);熟悉 uniapp / 鴻蒙開發(fā),具備一定的音視頻開發(fā)基礎(chǔ),為跨平臺(tái)應(yīng)用開發(fā)提供了更廣闊的技術(shù)視野。
- 具備開發(fā) SDK 及編寫對(duì)外 SDK 接口文檔的能力,對(duì)反作弊 sdk 有一定了解,為應(yīng)用安全與功能拓展提供有力保障。
- 熟練使用AI工具進(jìn)行實(shí)際問題查詢與解決,顯著提升工作效率與創(chuàng)新能力。
- 熟悉 jenkins 等項(xiàng)目構(gòu)建搭建流程,確保項(xiàng)目高效穩(wěn)定交付。
- 資料
深入理解并熟練運(yùn)用常用設(shè)計(jì)模式及反射原理,能夠自定義注解及泛型,多次通過設(shè)計(jì)模式對(duì) app 代碼進(jìn)行高效重構(gòu),顯著提升代碼的可維護(hù)性與擴(kuò)展性。
設(shè)計(jì)模式
- 單例模式
// 餓漢式單例模式
class Singleton {// 類加載時(shí)就創(chuàng)建實(shí)例,保證線程安全private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}// 懶漢式單例模式(線程不安全寫法,僅用于示例理解)
class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}// 懶漢式單例模式(線程安全寫法,使用雙重檢查鎖定)
class ThreadSafeLazySingleton {private static volatile ThreadSafeLazySingleton instance;private ThreadSafeLazySingleton() {}public static ThreadSafeLazySingleton getInstance() {if (instance == null) {synchronized (ThreadSafeLazySingleton.class) {if (instance == null) {instance = new ThreadSafeLazySingleton();}}}return instance;}
}
- 簡(jiǎn)單工廠模式
// 產(chǎn)品抽象類
abstract class Product {public abstract void use();
}// 具體產(chǎn)品類A
class ConcreteProductA extends Product {@Overridepublic void use() {System.out.println("使用產(chǎn)品A");}
}// 具體產(chǎn)品類B
class ConcreteProductB extends Product {@Overridepublic void use() {System.out.println("使用產(chǎn)品B");}
}// 工廠類
class SimpleFactory {public static Product createProduct(String type) {if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();}return null;}
}
- 工廠方法模式
// 產(chǎn)品抽象類
abstract class Product {public abstract void use();
}// 具體產(chǎn)品類A
class ConcreteProductA extends Product {@Overridepublic void use() {System.out.println("使用產(chǎn)品A");}
}// 具體產(chǎn)品類B
class ConcreteProductB extends Product {@Overridepublic void use() {System.out.println("使用產(chǎn)品B");}
}// 抽象工廠類
abstract class Factory {public abstract Product createProduct();
}// 具體工廠類A,用于生產(chǎn)產(chǎn)品A
class ConcreteFactoryA extends Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}// 具體工廠類B,用于生產(chǎn)產(chǎn)品B
class ConcreteFactoryB extends Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}
- 抽象工廠模式
// 抽象產(chǎn)品A
interface AbstractProductA {void methodA();
}// 抽象產(chǎn)品B
interface AbstractProductB {void methodB();
}// 具體產(chǎn)品A1
class ConcreteProductA1 implements AbstractProductA {@Overridepublic void methodA() {System.out.println("具體產(chǎn)品A1的方法A");}
}// 具體產(chǎn)品A2
class ConcreteProductA2 implements AbstractProductA {@Overridepublic void methodA() {System.out.println("具體產(chǎn)品A2的方法A");}
}// 具體產(chǎn)品B1
class ConcreteProductB1 implements AbstractProductB {@Overridepublic void methodB() {System.out.println("具體產(chǎn)品B1的方法B");}
}// 具體產(chǎn)品B2
class ConcreteProductB2 implements AbstractProductB {@Overridepublic void methodB() {System.out.println("具體產(chǎn)品B2的方法B");}
}// 抽象工廠
interface AbstractFactory {AbstractProductA createProductA();AbstractProductB createProductB();
}// 具體工廠1
class ConcreteFactory1 implements AbstractFactory {@Overridepublic AbstractProductA createProductA() {return new ConcreteProductA1();}@Overridepublic AbstractProductB createProductB() {return new ConcreteProductB1();}
}// 具體工廠2
class ConcreteFactory2 implements AbstractFactory {@Overridepublic AbstractProductA createProductA() {return new ConcreteProductA2();}@Overridepublic AbstractProductB createProductB() {return new ConcreteProductB2();}
}
- 代理模式
// 抽象主題(接口)
interface Subject {void request();
}// 真實(shí)主題
class RealSubject implements Subject {@Overridepublic void request() {System.out.println("真實(shí)主題處理請(qǐng)求");}
}// 代理主題
class ProxySubject implements Subject {private RealSubject realSubject;@Overridepublic void request() {if (realSubject == null) {realSubject = new RealSubject();}// 可以在這里添加一些額外的處理,比如權(quán)限驗(yàn)證等System.out.println("代理主題預(yù)處理請(qǐng)求");realSubject.request();System.out.println("代理主題后續(xù)處理請(qǐng)求");}
}
- 裝飾器模式
// 抽象主題(接口)
interface Subject {void request();
}// 真實(shí)主題
class RealSubject implements Subject {@Overridepublic void request() {System.out.println("真實(shí)主題處理請(qǐng)求");}
}// 代理主題
class ProxySubject implements Subject {private RealSubject realSubject;@Overridepublic void request() {if (realSubject == null) {realSubject = new RealSubject();}// 可以在這里添加一些額外的處理,比如權(quán)限驗(yàn)證等System.out.println("代理主題預(yù)處理請(qǐng)求");realSubject.request();System.out.println("代理主題后續(xù)處理請(qǐng)求");}
}
- 觀察者模式
import java.util.ArrayList;
import java.util.List;// 抽象主題(被觀察者)
abstract class Subject {private List<Observer> observers = new ArrayList<>();public void attach(Observer observer) {observers.add(observer);}public void detach(Observer observer) {observers.remove(observer);}public void notifyObservers() {for (Observer observer : observers) {observer.update(this);}}
}// 抽象觀察者
interface Observer {void update(Subject subject);
}// 具體主題(實(shí)現(xiàn)類)
class ConcreteSubject extends Subject {private int state;public int getState() {return state;}public void setState(int state) {this.state = state;notifyObservers();}
}// 具體觀察者
class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(Subject subject) {if (subject instanceof ConcreteSubject) {System.out.println(name + "收到更新,新狀態(tài)為: " + ((ConcreteSubject) subject).getState());}}
}
- 策略模式
// 策略接口
interface Strategy {int doOperation(int num1, int num2);
}// 具體策略:加法策略
class AddStrategy implements Strategy {@Overridepublic int doOperation(int num1, int num2) {return num1 + num2;}
}// 具體策略:減法策略
class SubtractStrategy implements Strategy {@Overridepublic int doOperation(int num1, int num2) {return num1 - num2;}
}// 上下文類,使用策略
class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public int executeStrategy(int num1, int num2) {return strategy.doOperation(num1, num2);}
}
- 命令模式
// 命令接口
interface Command {void execute();
}// 具體命令類
class ConcreteCommand implements Command {private Receiver receiver;public ConcreteCommand(Receiver receiver) {this.receiver = receiver;}@Overridepublic void execute() {receiver.action();}
}// 接收者類
class Receiver {public void action() {System.out.println("接收者執(zhí)行操作");}
}// 調(diào)用者類
class Invoker {private Command command;public void setCommand(Command command) {this.command = command;}public void executeCommand() {command.execute();}
}
- 動(dòng)態(tài)代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 定義接口
interface Subject {void doSomething();
}// 實(shí)現(xiàn)接口的具體類,作為目標(biāo)對(duì)象
class RealSubject implements Subject {@Overridepublic void doSomething() {System.out.println("真實(shí)對(duì)象執(zhí)行具體操作");}
}// 實(shí)現(xiàn)InvocationHandler接口,用于處理代理對(duì)象的方法調(diào)用邏輯
class DynamicProxyHandler implements InvocationHandler {private Object target;public DynamicProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 在目標(biāo)方法調(diào)用前添加額外邏輯System.out.println("代理對(duì)象在調(diào)用方法前的額外處理");// 調(diào)用目標(biāo)對(duì)象的方法Object result = method.invoke(target, args);// 在目標(biāo)方法調(diào)用后添加額外邏輯System.out.println("代理對(duì)象在調(diào)用方法后的額外處理");return result;}
}public class DynamicProxyExample {public static void main(String[] args) {// 創(chuàng)建目標(biāo)對(duì)象RealSubject realSubject = new RealSubject();// 創(chuàng)建動(dòng)態(tài)代理處理器,傳入目標(biāo)對(duì)象DynamicProxyHandler handler = new DynamicProxyHandler(realSubject);// 通過Proxy類創(chuàng)建代理對(duì)象,指定要代理的接口、類加載器以及代理處理器Subject proxySubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),new Class[]{Subject.class},handler);// 調(diào)用代理對(duì)象的方法,此時(shí)會(huì)觸發(fā)代理處理器中的invoke方法邏輯proxySubject.doSomething();}
}
自定義注解
- 注解的定義
- 使用自定義注解
- 通過反射獲取處理注解信息
泛型
- 泛型類的定義
public class Box<T> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}
- 泛型接口的定義
public interface Generator<T> {T generate();
}
- 泛型方法的定義
public class GenericMethodExample {public static <T> T getFirstElement(T[] array) {if (array.length > 0) {return array[0];}return null;}
}
Kotlin泛型
- 泛型類
class Box<T>(var element: T)
- 泛型函數(shù)
fun <T> swap(a: T, b: T): Pair<T, T> {return Pair(b, a)
}
- 泛型約束
fun <T : Comparable<T>> findMin(a: T, b: T): T {return if (a < b) a else b
}
- 協(xié)變與逆變
協(xié)變
interface Producer<out T> {fun produce(): T
}
逆變
interface Consumer<in T> {fun consume(item: T)
}
- 泛型的星投影
fun printListSize(list: List<*>){println("List size: ${list.size}")
}
精通多線程原理,對(duì) ThreadPoolExecutor 進(jìn)行過深度剖析,能夠精準(zhǔn)運(yùn)用多線程技術(shù)提升應(yīng)用性能與響應(yīng)速度。
多線程原理
- 概念
- 進(jìn)程事資源分配的基本單位,它擁有自己獨(dú)立的內(nèi)存空間和系統(tǒng)資源。一個(gè)進(jìn)程可以包含多個(gè)線程
- 線程是程序執(zhí)行流的最小單元,它是進(jìn)程中的一個(gè)實(shí)體,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位。
- 實(shí)現(xiàn)方式
- 繼承Thread類
- 實(shí)現(xiàn)Runnable接口
- 使用線程池ThreadExecutorService
- 線程調(diào)度模型
- 搶占式調(diào)度模型
- 線程的優(yōu)先級(jí)可以在一定程度上影響線程獲取CPU時(shí)間片的概率
- 多線程的內(nèi)存模型
- 內(nèi)存模型(JMM)規(guī)定了線程和內(nèi)存之間的抽象關(guān)系。每個(gè)線程有自己的工作內(nèi)存,工作內(nèi)存中國(guó)呢保存了該線程使用的變量的副本
- 這種內(nèi)存模型的存在是為了提高程序的并發(fā)性能,但也帶來了一些數(shù)據(jù)一致性的問題,如可見性、原子性和有序性問題
- 多線程的同步機(jī)制
- synchronized關(guān)鍵字:用于修飾方法或者代碼塊。
- Lock接口:ReentrantLock
- 進(jìn)程間通信
- 等待/通知機(jī)制(Object類的wait、notify和notifyAll方法)
- 阻塞隊(duì)列:提供了一種線程安全的隊(duì)列數(shù)據(jù)結(jié)構(gòu),用于在生產(chǎn)者和消費(fèi)者線程之間傳遞數(shù)據(jù)
AQS
- AQS的基本概念
AQS是一個(gè)抽象類,它是構(gòu)建鎖和同步器的基礎(chǔ)框架。
AQS維護(hù)了一個(gè)同步隊(duì)列(FIFO雙向隊(duì)列),用于管理等待獲取鎖的線程。 - AQS的內(nèi)部數(shù)據(jù)結(jié)構(gòu)-同步隊(duì)列
- 節(jié)點(diǎn)
- 頭節(jié)點(diǎn)和尾節(jié)點(diǎn)
- AQS的工作原理-獨(dú)占鎖模式
- 獲取鎖(acquire方法)acquire方法首先會(huì)嘗試通過tryAcquire方法獲取鎖。如果獲取失敗,說明鎖被其他線程占用。此時(shí),線程會(huì)被封裝一個(gè)Node節(jié)點(diǎn),通過addWaiter方法田間到同步隊(duì)列的尾部。
- 釋放鎖(release方法)release方法會(huì)調(diào)用tryRelease方法嘗試釋放鎖。
- AQS的共享鎖模式
- 初始化
- 等待操作
- 計(jì)數(shù)器遞減操作
- AQS的優(yōu)勢(shì)
- 可復(fù)用性
- 高性能
- 靈活性
ThreadPoolExecutor深度剖析
- 核心概念
ThreadPoolExecutor 是一個(gè)可擴(kuò)展的線程池實(shí)現(xiàn),允許開發(fā)者自定義線程池的核心參數(shù),如核心線程數(shù)、最大線程數(shù)、任務(wù)隊(duì)列、線程工廠、拒絕策略等。 - 核心參數(shù)
ThreadPoolExecutor 的構(gòu)造函數(shù)包含以下核心參數(shù):
- corePoolSize(核心線程數(shù))線程池中保持的最小線程數(shù),即使線程空閑也不會(huì)被銷毀(除非設(shè)置了 allowCoreThreadTimeOut)。
- maximumPoolSize(最大線程數(shù))線程池中允許的最大線程數(shù)。當(dāng)任務(wù)隊(duì)列滿時(shí),線程池會(huì)創(chuàng)建新線程,直到達(dá)到最大線程數(shù)。
- keepAliveTime(線程空閑時(shí)間)當(dāng)線程數(shù)超過核心線程數(shù)時(shí),空閑線程的存活時(shí)間。超過該時(shí)間后,多余的線程會(huì)被銷毀。
- unit(時(shí)間單位)keepAliveTime 的時(shí)間單位,如 TimeUnit.SECONDS。
- workQueue(任務(wù)隊(duì)列)用于存放待執(zhí)行任務(wù)的阻塞隊(duì)列。常見的隊(duì)列類型有:
- LinkedBlockingQueue:無界隊(duì)列(默認(rèn))。
- ArrayBlockingQueue:有界隊(duì)列。
- SynchronousQueue:不存儲(chǔ)任務(wù)的隊(duì)列,直接將任務(wù)交給線程。
- threadFactory(線程工廠)用于創(chuàng)建新線程的工廠,可以自定義線程的名稱、優(yōu)先級(jí)等。
- handler(拒絕策略)當(dāng)任務(wù)隊(duì)列滿且線程數(shù)達(dá)到最大線程數(shù)時(shí),新任務(wù)的拒絕策略。常見的策略有:
- AbortPolicy(默認(rèn)):拋出 RejectedExecutionException。
- CallerRunsPolicy:由提交任務(wù)的線程直接執(zhí)行任務(wù)。
- DiscardPolicy:直接丟棄任務(wù)。
- DiscardOldestPolicy:丟棄隊(duì)列中最舊的任務(wù),然后重新提交新任務(wù)。
- 線程池的工作流程
- 提交任務(wù)時(shí),首先檢查當(dāng)前線程數(shù)是否小于核心線程數(shù)(corePoolSize)。如果是,則創(chuàng)建新線程執(zhí)行任務(wù)。
- 如果線程數(shù)已達(dá)到核心線程數(shù),則將任務(wù)放入任務(wù)隊(duì)列(workQueue)。
- 如果任務(wù)隊(duì)列已滿,則檢查當(dāng)前線程數(shù)是否小于最大線程數(shù)(maximumPoolSize)。如果是,則創(chuàng)建新線程執(zhí)行任務(wù)。
- 如果線程數(shù)已達(dá)到最大線程數(shù)且任務(wù)隊(duì)列已滿,則觸發(fā)拒絕策略(handler)。
- 線程池的狀態(tài)
ThreadPoolExecutor 使用一個(gè) AtomicInteger 變量(ctl)來同時(shí)表示線程池的狀態(tài)和線程數(shù)。狀態(tài)包括:
- RUNNING:正常運(yùn)行狀態(tài),可以接受新任務(wù)并處理隊(duì)列中的任務(wù)。
- SHUTDOWN:關(guān)閉狀態(tài),不再接受新任務(wù),但會(huì)處理隊(duì)列中的任務(wù)。
- STOP:停止?fàn)顟B(tài),不再接受新任務(wù),也不處理隊(duì)列中的任務(wù),并中斷正在執(zhí)行的任務(wù)。
- TIDYING:整理狀態(tài),所有任務(wù)已終止,線程數(shù)為 0,準(zhǔn)備調(diào)用 terminated() 方法。
- TERMINATED:終止?fàn)顟B(tài),terminated() 方法已執(zhí)行完畢。
- 常用方法
submit(Runnable/Callable):提交任務(wù),返回 Future 對(duì)象。
execute(Runnable):提交任務(wù),無返回值。
shutdown():平滑關(guān)閉線程池,不再接受新任務(wù),但會(huì)處理隊(duì)列中的任務(wù)。
shutdownNow():立即關(guān)閉線程池,嘗試中斷所有線程,并返回未執(zhí)行的任務(wù)列表。
awaitTermination(long timeout, TimeUnit unit):等待線程池終止,直到超時(shí)或線程池終止。 - 線程池的優(yōu)化
- 合理設(shè)置核心線程數(shù)和最大線程數(shù)
根據(jù)任務(wù)類型(CPU 密集型或 IO 密集型)和硬件資源(CPU 核心數(shù))調(diào)整線程數(shù)。
CPU 密集型任務(wù):線程數(shù) ≈ CPU 核心數(shù)。
IO 密集型任務(wù):線程數(shù) ≈ CPU 核心數(shù) * (1 + 平均等待時(shí)間 / 平均計(jì)算時(shí)間)。 - 選擇合適的任務(wù)隊(duì)列
無界隊(duì)列(如 LinkedBlockingQueue)可能導(dǎo)致內(nèi)存溢出。
有界隊(duì)列(如 ArrayBlockingQueue)可以限制任務(wù)數(shù)量,但需要合理設(shè)置隊(duì)列大小。 - 自定義拒絕策略
根據(jù)業(yè)務(wù)需求實(shí)現(xiàn)自定義拒絕策略,例如記錄日志或?qū)⑷蝿?wù)持久化。
- 常見問題
- 線程池中的線程如何復(fù)用?
線程池中的線程在執(zhí)行完任務(wù)后不會(huì)立即銷毀,而是從任務(wù)隊(duì)列中獲取新任務(wù)繼續(xù)執(zhí)行。 - 如何避免線程池中的線程泄漏?
確保任務(wù)不會(huì)無限阻塞(如死鎖或長(zhǎng)時(shí)間等待),并合理設(shè)置 keepAliveTime。 - 如何監(jiān)控線程池的狀態(tài)?
可以通過 ThreadPoolExecutor 提供的方法(如 getPoolSize()、getActiveCount())監(jiān)控線程池的狀態(tài)。
- 示例代碼
import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 創(chuàng)建線程池ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // 核心線程數(shù)4, // 最大線程數(shù)60, // 空閑線程存活時(shí)間TimeUnit.SECONDS, // 時(shí)間單位new LinkedBlockingQueue<>(10), // 任務(wù)隊(duì)列Executors.defaultThreadFactory(), // 線程工廠new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略);// 提交任務(wù)for (int i = 0; i < 15; i++) {executor.execute(() -> {System.out.println("Task executed by " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}// 關(guān)閉線程池executor.shutdown();}
}
使用多線程技術(shù)提升應(yīng)用性能與響應(yīng)速度
- 多線程的優(yōu)勢(shì)
提高 CPU 利用率:通過并行執(zhí)行任務(wù),充分利用多核 CPU 的計(jì)算能力。
提升響應(yīng)速度:將耗時(shí)任務(wù)放到后臺(tái)線程執(zhí)行,避免阻塞主線程。
增強(qiáng)吞吐量:通過并發(fā)處理多個(gè)請(qǐng)求,提高系統(tǒng)的處理能力。 - 多線程的應(yīng)用場(chǎng)景
(1)CPU 密集型任務(wù)
例如:圖像處理、數(shù)據(jù)計(jì)算、加密解密等。
優(yōu)化方法:線程數(shù) ≈ CPU 核心數(shù)。
(2)IO 密集型任務(wù)
例如:文件讀寫、網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)庫操作等。
優(yōu)化方法:線程數(shù) ≈ CPU 核心數(shù) * (1 + 平均等待時(shí)間 / 平均計(jì)算時(shí)間)。
(3)異步任務(wù)
例如:發(fā)送郵件、日志記錄、消息推送等。
優(yōu)化方法:使用線程池或異步框架(如 CompletableFuture)。 - 提升性能的關(guān)鍵技術(shù)
(1)線程池優(yōu)化
使用 ThreadPoolExecutor 自定義線程池參數(shù),如核心線程數(shù)、最大線程數(shù)、任務(wù)隊(duì)列和拒絕策略
2)異步編程
使用 CompletableFuture 實(shí)現(xiàn)異步任務(wù)編排。
CompletableFuture.supplyAsync(() -> {// 異步任務(wù)return "Result";
}).thenAccept(result -> {System.out.println("Task result: " + result);
});
(3)并發(fā)工具類
使用 java.util.concurrent 包中的工具類,如 CountDownLatch、CyclicBarrier、Semaphore 等。
CountDownLatch latch = new CountDownLatch(3);
ExecutorService executor = Executors.newFixedThreadPool(3);for (int i = 0; i < 3; i++) {executor.execute(() -> {System.out.println("Task executed");latch.countDown();});
}latch.await(); // 等待所有任務(wù)完成
executor.shutdown();
4)鎖優(yōu)化
使用 ReentrantLock 替代 synchronized,提供更靈活的鎖機(jī)制。
使用 ReadWriteLock 實(shí)現(xiàn)讀寫分離,提高并發(fā)性能。
-
注意事項(xiàng)
線程安全:確保共享資源的線程安全性,使用同步機(jī)制(如 synchronized、Lock)或線程安全類(如 ConcurrentHashMap)。
避免死鎖:確保鎖的獲取順序一致,避免嵌套鎖。
資源管理:及時(shí)關(guān)閉線程池和釋放資源,避免內(nèi)存泄漏。
性能監(jiān)控:使用工具(如 JVisualVM、JProfiler)監(jiān)控線程狀態(tài)和性能瓶頸。 -
示例:使用線程池提升性能
import java.util.concurrent.*;public class ThreadPoolPerformanceExample {public static void main(String[] args) {// 創(chuàng)建線程池ExecutorService executor = Executors.newFixedThreadPool(4);// 提交任務(wù)long startTime = System.currentTimeMillis();for (int i = 0; i < 10; i++) {executor.execute(() -> {try {Thread.sleep(1000); // 模擬耗時(shí)任務(wù)System.out.println("Task executed by " + Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}});}// 關(guān)閉線程池executor.shutdown();try {executor.awaitTermination(1, TimeUnit.MINUTES); // 等待所有任務(wù)完成} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis();System.out.println("Total time: " + (endTime - startTime) + "ms");}
}
熟練掌握自定義 View 原理,憑借對(duì)事件分發(fā)原理的深刻理解,有效解決各類 UI 交互問題,確保用戶體驗(yàn)的流暢性與友好性。
自定義View原理
- 自定義View的基本步驟
- 繼承View或其子類
- 重寫關(guān)鍵方法 :onMeasure()測(cè)量view的寬高、onDraw繪制view的內(nèi)容、onLayout確定View的位置
- 處理自定義屬性
- 處理觸摸事件:重寫onTouchEvent方法
事件分發(fā)機(jī)制
-
事件分發(fā)流程
事件分發(fā)涉及三個(gè)核心方法:
dispatchTouchEvent():負(fù)責(zé)事件分發(fā)。
onInterceptTouchEvent():ViewGroup 特有,用于攔截事件。
onTouchEvent():處理事件。
事件分發(fā)流程:
事件從 Activity 傳遞到 ViewGroup,再傳遞到 View。
如果 ViewGroup 的 onInterceptTouchEvent() 返回 true,則攔截事件,不再向下傳遞。
如果 View 的 onTouchEvent() 返回 true,則消費(fèi)事件,不再向上傳遞。 -
事件沖突處理
外部攔截法:在父容器的 onInterceptTouchEvent() 中處理沖突。
內(nèi)部攔截法:在子 View 的 dispatchTouchEvent() 中調(diào)用 requestDisallowInterceptTouchEvent()。
View的設(shè)計(jì)模式
- 組合模式
- 責(zé)任鏈模式
- 觀察者模式
- 裝飾者模式
對(duì) Handler、Zygote、Binder、AMS 等機(jī)制有清晰認(rèn)知,長(zhǎng)期保持閱讀 Framework 層源碼的習(xí)慣,為應(yīng)用開發(fā)提供堅(jiān)實(shí)的技術(shù)支撐。
談?wù)剬?duì)Handler機(jī)制的理解
- Handler機(jī)制的核心組件
Handler:用于發(fā)送和處理消息。
Message:消息的載體,包含任務(wù)的相關(guān)信息。
MessageQueue:消息隊(duì)列,用于存儲(chǔ)待處理的消息。
Looper:消息循環(huán),不斷從 MessageQueue 中取出消息并分發(fā)給 Handler 處理。 - Handler機(jī)制的工作原理
(1)消息的發(fā)送
通過 Handler 發(fā)送消息(sendMessage())或任務(wù)(post())。
消息會(huì)被封裝成 Message 對(duì)象,并放入 MessageQueue 中。
(2)消息的存儲(chǔ)
MessageQueue 是一個(gè)基于單鏈表的消息隊(duì)列,按照時(shí)間順序存儲(chǔ)消息。
每條消息都有一個(gè)時(shí)間戳(when),用于確定消息的執(zhí)行順序。
(3)消息的循環(huán)
Looper 不斷從 MessageQueue 中取出消息(loop() 方法)。
如果 MessageQueue 為空,Looper 會(huì)進(jìn)入阻塞狀態(tài),直到有新消息加入。
(4)消息的處理
Looper 將取出的消息分發(fā)給對(duì)應(yīng)的 Handler。
Handler 調(diào)用 handleMessage() 方法處理消息。
3. Handler機(jī)制的代碼流程
(1)創(chuàng)建 Looper
new Thread(() -> {Looper.prepare(); // 初始化 LooperHandler handler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(Message msg) {// 處理消息}};Looper.loop(); // 啟動(dòng)消息循環(huán)
}).start();
(2)發(fā)送消息
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {// 在主線程執(zhí)行任務(wù)
});Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);
(3)處理消息
Handler handler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 1:// 處理消息break;}}
};
- Handler機(jī)制的關(guān)鍵點(diǎn)
(1)線程綁定
每個(gè) Handler 都會(huì)綁定一個(gè) Looper,而 Looper 是與線程綁定的。
主線程的 Looper 由系統(tǒng)自動(dòng)創(chuàng)建,子線程的 Looper 需要手動(dòng)創(chuàng)建。
(2)消息隊(duì)列
MessageQueue 是一個(gè)優(yōu)先級(jí)隊(duì)列,消息按照時(shí)間順序排列。
可以通過 postDelayed() 發(fā)送延遲消息。
(3)內(nèi)存泄漏
如果 Handler 持有 Activity 的引用,而 Handler 的消息隊(duì)列中仍有未處理的消息,會(huì)導(dǎo)致 Activity 無法被回收,從而引發(fā)內(nèi)存泄漏。
解決方法:使用靜態(tài)內(nèi)部類 + 弱引用。
private static class MyHandler extends Handler {private final WeakReference<Activity> mActivity;MyHandler(Activity activity) {mActivity = new WeakReference<>(activity);}@Overridepublic void handleMessage(Message msg) {Activity activity = mActivity.get();if (activity != null) {// 處理消息}}
}
- Handler機(jī)制的應(yīng)用場(chǎng)景
線程切換:將任務(wù)從子線程切換到主線程執(zhí)行。
定時(shí)任務(wù):通過 postDelayed() 實(shí)現(xiàn)定時(shí)任務(wù)。
消息傳遞:在不同組件之間傳遞消息。 - Handler機(jī)制的面試問題
(1)Handler 是如何實(shí)現(xiàn)線程切換的?
Handler 通過 Looper 和 MessageQueue 實(shí)現(xiàn)線程切換。發(fā)送消息時(shí),消息會(huì)被放入目標(biāo)線程的 MessageQueue 中,目標(biāo)線程的 Looper 會(huì)從 MessageQueue 中取出消息并分發(fā)給 Handler 處理。
(2)主線程的 Looper 和子線程的 Looper 有什么區(qū)別?
主線程的 Looper 由系統(tǒng)自動(dòng)創(chuàng)建,子線程的 Looper 需要手動(dòng)創(chuàng)建。
主線程的 Looper 不會(huì)退出,而子線程的 Looper 可以通過 quit() 或 quitSafely() 退出。
(3)Handler 的內(nèi)存泄漏是如何產(chǎn)生的?如何避免?
內(nèi)存泄漏產(chǎn)生的原因:Handler 持有 Activity 的引用,而 Handler 的消息隊(duì)列中仍有未處理的消息。
避免方法:使用靜態(tài)內(nèi)部類 + 弱引用。
(4)MessageQueue 是如何保證線程安全的?
MessageQueue 通過 synchronized 關(guān)鍵字和 native 方法(如 nativePollOnce())保證線程安全。
(5)Handler 的 post() 和 sendMessage() 有什么區(qū)別?
post() 用于發(fā)送 Runnable 任務(wù),sendMessage() 用于發(fā)送 Message 對(duì)象。
最終都會(huì)將任務(wù)封裝成 Message 并放入 MessageQueue 中。
談?wù)剬?duì)Zygote機(jī)制的理解
- Zygote的基本概念
- Zygote是Android系統(tǒng)中的一個(gè)關(guān)鍵進(jìn)程,它的名字來源于生物學(xué)中的“受精卵”。在Android系統(tǒng)啟動(dòng)時(shí),Zygote進(jìn)程就會(huì)被啟動(dòng)。它就像一個(gè)孵化器,用于孵化出其他的應(yīng)用程序進(jìn)程。
- 它是所有Android應(yīng)用程序進(jìn)程的父進(jìn)程。當(dāng)系統(tǒng)需要啟動(dòng)一個(gè)新的應(yīng)用程序時(shí),會(huì)通過Zygote進(jìn)程來進(jìn)行fork操作(復(fù)制進(jìn)程),快速創(chuàng)建出一個(gè)新的應(yīng)用程序進(jìn)程。這樣做的好處是可以共享Zygote進(jìn)程已經(jīng)加載的系統(tǒng)資源,如類庫、運(yùn)行時(shí)環(huán)境等,減少應(yīng)用程序啟動(dòng)時(shí)間。
- Zygote的啟動(dòng)過程
- 在Android系統(tǒng)初始化階段,init進(jìn)程會(huì)啟動(dòng)Zygote進(jìn)程。Zygote的啟動(dòng)腳本通常位于
/system/bin/app_process
(不同的Android版本可能會(huì)有差異)。這個(gè)腳本會(huì)加載Zygote的Java代碼,啟動(dòng)Zygote的Java虛擬機(jī)(Dalvik或者ART,在現(xiàn)代Android系統(tǒng)主要是ART)。 - 當(dāng)Zygote進(jìn)程啟動(dòng)后,它會(huì)預(yù)加載一些系統(tǒng)核心的Java類和資源。例如,常用的Android系統(tǒng)類(如
android.os.Bundle
、android.view.View
等)和一些常用的本地庫。預(yù)加載這些類和資源可以使得后續(xù)通過fork操作創(chuàng)建的應(yīng)用程序進(jìn)程能夠快速地使用這些已經(jīng)加載好的內(nèi)容。
- 在Android系統(tǒng)初始化階段,init進(jìn)程會(huì)啟動(dòng)Zygote進(jìn)程。Zygote的啟動(dòng)腳本通常位于
- Zygote與應(yīng)用程序進(jìn)程創(chuàng)建的關(guān)系
- 當(dāng)系統(tǒng)需要啟動(dòng)一個(gè)新的應(yīng)用程序時(shí),例如用戶點(diǎn)擊了一個(gè)應(yīng)用圖標(biāo),系統(tǒng)會(huì)向Zygote進(jìn)程發(fā)送一個(gè)請(qǐng)求。Zygote進(jìn)程收到請(qǐng)求后,會(huì)通過
fork()
系統(tǒng)調(diào)用創(chuàng)建一個(gè)新的子進(jìn)程。這個(gè)子進(jìn)程幾乎是Zygote進(jìn)程的一個(gè)副本,它繼承了Zygote進(jìn)程已經(jīng)加載的大部分資源。 - 新創(chuàng)建的子進(jìn)程會(huì)有自己獨(dú)立的進(jìn)程空間,然后它會(huì)通過一系列的初始化操作,如加載應(yīng)用程序自身的代碼和資源,來變成一個(gè)真正的應(yīng)用程序進(jìn)程。這個(gè)過程中,會(huì)對(duì)繼承自Zygote的資源進(jìn)行適當(dāng)?shù)恼{(diào)整,以滿足應(yīng)用程序自身的需求。
- 當(dāng)系統(tǒng)需要啟動(dòng)一個(gè)新的應(yīng)用程序時(shí),例如用戶點(diǎn)擊了一個(gè)應(yīng)用圖標(biāo),系統(tǒng)會(huì)向Zygote進(jìn)程發(fā)送一個(gè)請(qǐng)求。Zygote進(jìn)程收到請(qǐng)求后,會(huì)通過
- Zygote在系統(tǒng)資源共享方面的作用
- 內(nèi)存共享:由于應(yīng)用程序進(jìn)程是通過fork操作從Zygote進(jìn)程創(chuàng)建而來的,它們可以共享Zygote進(jìn)程已經(jīng)在內(nèi)存中加載的代碼段。例如,所有的Android應(yīng)用程序都需要使用
android.os
包下的類,這些類在Zygote進(jìn)程預(yù)加載后,通過fork創(chuàng)建的應(yīng)用程序進(jìn)程可以直接使用這些內(nèi)存中的代碼,而不需要重新加載,大大節(jié)省了內(nèi)存空間和加載時(shí)間。 - 運(yùn)行時(shí)環(huán)境共享:Zygote進(jìn)程初始化了Android運(yùn)行時(shí)環(huán)境(如ART虛擬機(jī)的一些全局?jǐn)?shù)據(jù)結(jié)構(gòu)),新創(chuàng)建的應(yīng)用程序進(jìn)程可以繼承這些運(yùn)行時(shí)環(huán)境設(shè)置。這使得應(yīng)用程序進(jìn)程能夠快速地融入到Android系統(tǒng)的運(yùn)行環(huán)境中,減少了每個(gè)應(yīng)用程序單獨(dú)初始化運(yùn)行時(shí)環(huán)境的開銷。
- 內(nèi)存共享:由于應(yīng)用程序進(jìn)程是通過fork操作從Zygote進(jìn)程創(chuàng)建而來的,它們可以共享Zygote進(jìn)程已經(jīng)在內(nèi)存中加載的代碼段。例如,所有的Android應(yīng)用程序都需要使用
- Zygote的安全性和穩(wěn)定性考慮
- Zygote進(jìn)程作為所有應(yīng)用程序進(jìn)程的父進(jìn)程,它的穩(wěn)定性至關(guān)重要。如果Zygote進(jìn)程出現(xiàn)異常崩潰,那么可能會(huì)導(dǎo)致整個(gè)系統(tǒng)無法正常啟動(dòng)新的應(yīng)用程序。為了保證其穩(wěn)定性,Zygote進(jìn)程在啟動(dòng)和運(yùn)行過程中會(huì)進(jìn)行一系列的錯(cuò)誤檢查和恢復(fù)機(jī)制。
- 在安全性方面,由于應(yīng)用程序進(jìn)程是從Zygote進(jìn)程派生而來的,Zygote進(jìn)程會(huì)設(shè)置一些安全機(jī)制,如為每個(gè)新創(chuàng)建的應(yīng)用程序進(jìn)程分配獨(dú)立的用戶ID(UID)和組ID(GID),這樣可以防止不同的應(yīng)用程序之間相互干擾,保護(hù)用戶數(shù)據(jù)和系統(tǒng)安全。
談?wù)剬?duì)Binder機(jī)制的理解
- Binder機(jī)制的基本概念
- Binder是Android系統(tǒng)中一種跨進(jìn)程通信(IPC)機(jī)制。在Android系統(tǒng)中,不同的應(yīng)用程序運(yùn)行在各自的進(jìn)程空間中,為了實(shí)現(xiàn)這些進(jìn)程之間的數(shù)據(jù)交換和通信,就需要一種高效、安全的IPC機(jī)制,這就是Binder機(jī)制發(fā)揮作用的地方。
- 它可以看作是一種特殊的“管道”,用于在不同的進(jìn)程之間傳遞消息。例如,當(dāng)一個(gè)應(yīng)用程序中的Activity需要調(diào)用另一個(gè)應(yīng)用程序中的Service來獲取某些數(shù)據(jù)或者執(zhí)行某些操作時(shí),就會(huì)通過Binder機(jī)制來實(shí)現(xiàn)通信。
- Binder機(jī)制的架構(gòu)組成
- Binder驅(qū)動(dòng):它是Binder機(jī)制的核心部分,位于內(nèi)核空間。它負(fù)責(zé)管理和調(diào)度Binder通信的各種事務(wù)。比如,當(dāng)一個(gè)進(jìn)程向另一個(gè)進(jìn)程發(fā)送數(shù)據(jù)時(shí),Binder驅(qū)動(dòng)會(huì)接收這個(gè)請(qǐng)求,進(jìn)行權(quán)限檢查等操作,然后將數(shù)據(jù)傳遞給目標(biāo)進(jìn)程。
- Service Manager:它是一個(gè)守護(hù)進(jìn)程,運(yùn)行在用戶空間。它的主要作用是管理系統(tǒng)中的各種服務(wù)。當(dāng)一個(gè)服務(wù)需要注冊(cè)自己,以便其他進(jìn)程可以訪問時(shí),會(huì)向Service Manager進(jìn)行注冊(cè)。其他進(jìn)程如果想要使用這個(gè)服務(wù),也需要先向Service Manager查詢?cè)摲?wù)的引用。
- Client端和Server端:在Binder通信中,發(fā)起請(qǐng)求的一方稱為Client端,提供服務(wù)的一方稱為Server端。例如,一個(gè)音樂播放應(yīng)用程序中的播放控制界面(Client端)想要獲取音樂播放服務(wù)(Server端)中的歌曲列表,就會(huì)通過Binder機(jī)制進(jìn)行通信。
- Binder機(jī)制的通信過程
- 注冊(cè)服務(wù)階段:Server端進(jìn)程首先要通過Binder驅(qū)動(dòng)向Service Manager注冊(cè)自己提供的服務(wù)。它會(huì)把服務(wù)的名稱和對(duì)應(yīng)的Binder對(duì)象(這個(gè)對(duì)象用于后續(xù)的通信)傳遞給Service Manager。Service Manager會(huì)將這些信息存儲(chǔ)在一個(gè)列表中,以便后續(xù)查詢。
- 獲取服務(wù)階段:Client端進(jìn)程如果需要使用某個(gè)服務(wù),它會(huì)向Service Manager發(fā)送請(qǐng)求,查詢想要的服務(wù)。Service Manager根據(jù)請(qǐng)求的服務(wù)名稱,在已注冊(cè)的服務(wù)列表中查找對(duì)應(yīng)的Binder對(duì)象,然后將這個(gè)對(duì)象的引用返回給Client端。
- 通信階段:Client端得到服務(wù)的Binder對(duì)象引用后,就可以通過這個(gè)引用向Server端發(fā)送請(qǐng)求。這個(gè)請(qǐng)求會(huì)通過Binder驅(qū)動(dòng)傳遞到Server端。Binder驅(qū)動(dòng)會(huì)進(jìn)行一些必要的操作,如檢查權(quán)限、將請(qǐng)求數(shù)據(jù)從Client端進(jìn)程空間復(fù)制到內(nèi)核空間,再從內(nèi)核空間復(fù)制到Server端進(jìn)程空間等。Server端收到請(qǐng)求后進(jìn)行處理,然后將結(jié)果通過類似的過程返回給Client端。
- Binder機(jī)制的優(yōu)勢(shì)
- 高效性:相比于傳統(tǒng)的IPC機(jī)制,如管道、共享內(nèi)存等,Binder機(jī)制在數(shù)據(jù)傳輸過程中的性能損耗較小。因?yàn)樗捎昧藘?nèi)存映射(mmap)技術(shù),將用戶空間的一塊內(nèi)存直接映射到內(nèi)核空間,減少了數(shù)據(jù)復(fù)制的次數(shù)。例如,當(dāng)傳遞較大的數(shù)據(jù)塊時(shí),這種優(yōu)勢(shì)更加明顯。
- 安全性:Binder機(jī)制在通信過程中會(huì)進(jìn)行嚴(yán)格的權(quán)限檢查。每個(gè)服務(wù)在注冊(cè)時(shí)都有對(duì)應(yīng)的權(quán)限設(shè)置,Client端在獲取和使用服務(wù)時(shí),會(huì)受到這些權(quán)限的限制。這樣可以有效防止惡意應(yīng)用程序非法訪問其他應(yīng)用程序的服務(wù),保護(hù)用戶數(shù)據(jù)和系統(tǒng)安全。
- Binder機(jī)制的應(yīng)用場(chǎng)景
- Activity與Service通信:在Android開發(fā)中,一個(gè)常見的場(chǎng)景是Activity(用戶界面組件)需要和Service(后臺(tái)服務(wù)組件)進(jìn)行通信。例如,一個(gè)下載管理應(yīng)用,Activity用于顯示下載進(jìn)度和控制下載,而Service負(fù)責(zé)在后臺(tái)實(shí)際執(zhí)行下載任務(wù)。它們之間就可以通過Binder機(jī)制來傳遞下載進(jìn)度信息、控制命令等。
- 跨應(yīng)用通信:不同的應(yīng)用程序之間也可以通過Binder機(jī)制進(jìn)行通信。比如,一個(gè)應(yīng)用程序提供了打印服務(wù),其他應(yīng)用程序可以通過Binder機(jī)制調(diào)用這個(gè)打印服務(wù)來打印文檔。這使得Android系統(tǒng)中的應(yīng)用程序可以相互協(xié)作,提供更豐富的功能。
談?wù)剬?duì)AMS機(jī)制的理解
-
AMS(Activity Manager Service)的基本概念
- AMS是Android系統(tǒng)中非常核心的一個(gè)服務(wù),它主要負(fù)責(zé)管理系統(tǒng)中的Activity(活動(dòng))。在Android系統(tǒng)中,Activity是用戶界面的基本組成單位,用戶與應(yīng)用程序的交互大多是通過Activity進(jìn)行的。AMS就像是一個(gè)大管家,對(duì)這些Activity進(jìn)行創(chuàng)建、啟動(dòng)、暫停、停止、銷毀等一系列操作的管理。
- 它運(yùn)行在系統(tǒng)進(jìn)程(system_process)中,擁有很高的系統(tǒng)權(quán)限。由于其關(guān)鍵作用,它和Android系統(tǒng)中的許多其他組件都有密切的交互,比如Window Manager Service(管理窗口)、Package Manager Service(管理應(yīng)用程序包)等。
-
AMS在Activity生命周期管理中的作用
- Activity的創(chuàng)建:當(dāng)用戶打開一個(gè)應(yīng)用程序或者通過應(yīng)用內(nèi)的跳轉(zhuǎn)啟動(dòng)一個(gè)新的Activity時(shí),AMS會(huì)協(xié)調(diào)一系列操作來創(chuàng)建這個(gè)Activity。它會(huì)首先檢查這個(gè)Activity是否存在,如果不存在,就會(huì)通過讀取應(yīng)用程序的APK文件中的配置信息(如AndroidManifest.xml)來確定Activity的布局、權(quán)限等要求,然后分配必要的系統(tǒng)資源來構(gòu)建這個(gè)Activity。
- Activity的啟動(dòng):在Activity創(chuàng)建完成后,AMS會(huì)負(fù)責(zé)啟動(dòng)它。這包括將Activity的視圖加載到屏幕上,以及協(xié)調(diào)與其他系統(tǒng)組件的關(guān)系,比如通知Window Manager Service為這個(gè)Activity創(chuàng)建一個(gè)窗口,以便能夠正確地顯示在屏幕上。同時(shí),它會(huì)處理Activity之間的切換動(dòng)畫等細(xì)節(jié)。
- Activity的暫停、停止和銷毀:當(dāng)系統(tǒng)資源緊張或者用戶操作導(dǎo)致Activity需要暫停、停止或者銷毀時(shí),AMS會(huì)根據(jù)預(yù)先設(shè)定的規(guī)則來執(zhí)行這些操作。例如,當(dāng)用戶按下手機(jī)的返回鍵時(shí),AMS會(huì)接收到這個(gè)事件,然后判斷當(dāng)前Activity是否可以被銷毀。如果可以,它會(huì)釋放該Activity占用的資源,包括內(nèi)存、CPU等資源。
-
AMS與其他系統(tǒng)組件的交互關(guān)系
- 與Package Manager Service(PMS)的交互:PMS主要負(fù)責(zé)管理應(yīng)用程序包,包括安裝、卸載、解析APK文件等操作。AMS和PMS密切合作,例如,當(dāng)啟動(dòng)一個(gè)新的Activity時(shí),AMS需要從PMS獲取關(guān)于這個(gè)應(yīng)用程序的信息,如應(yīng)用程序的權(quán)限是否滿足要求、該Activity是否是合法的組件等。
- 與Window Manager Service(WMS)的交互:WMS負(fù)責(zé)管理系統(tǒng)中的窗口,包括窗口的布局、顯示、隱藏等操作。AMS在啟動(dòng)或者切換Activity時(shí),會(huì)和WMS進(jìn)行通信,告訴WMS需要為新的Activity創(chuàng)建或者更新窗口。例如,當(dāng)一個(gè)Activity從后臺(tái)切換到前臺(tái)時(shí),AMS會(huì)通知WMS調(diào)整窗口的層次結(jié)構(gòu),將這個(gè)Activity對(duì)應(yīng)的窗口顯示在最上面。
- 與Content Provider的交互:Content Provider是一種用于在不同應(yīng)用程序之間共享數(shù)據(jù)的組件。AMS在某些情況下會(huì)協(xié)調(diào)Content Provider和Activity之間的關(guān)系。例如,當(dāng)一個(gè)Activity需要訪問另一個(gè)應(yīng)用程序中的數(shù)據(jù)(通過Content Provider)時(shí),AMS可能會(huì)參與權(quán)限檢查等操作,確保這個(gè)訪問是合法的。
-
AMS在任務(wù)棧管理中的角色
- 在Android系統(tǒng)中,Activity是按照任務(wù)棧(Task Stack)的形式進(jìn)行組織的。AMS負(fù)責(zé)管理這些任務(wù)棧。一個(gè)任務(wù)??梢岳斫鉃槭且唤M相關(guān)的Activity的集合,它們按照一定的順序被打開。例如,當(dāng)用戶在一個(gè)應(yīng)用程序中依次打開多個(gè)Activity時(shí),這些Activity就會(huì)被依次壓入同一個(gè)任務(wù)棧中。
- AMS會(huì)根據(jù)任務(wù)棧的規(guī)則來管理Activity的進(jìn)出棧。當(dāng)用戶按下返回鍵時(shí),通常是將當(dāng)前Activity從任務(wù)棧中彈出,然后顯示上一個(gè)Activity。AMS會(huì)確保這個(gè)過程的順利進(jìn)行,并且會(huì)處理一些特殊情況,比如當(dāng)任務(wù)棧為空時(shí),是否需要退出應(yīng)用程序等情況。
-
AMS的重要性和對(duì)系統(tǒng)性能的影響
- AMS的正常運(yùn)作對(duì)于整個(gè)Android系統(tǒng)的穩(wěn)定性和用戶體驗(yàn)至關(guān)重要。如果AMS出現(xiàn)故障,可能會(huì)導(dǎo)致Activity無法正常啟動(dòng)、切換或者銷毀,進(jìn)而影響用戶與應(yīng)用程序的交互。例如,用戶可能會(huì)遇到應(yīng)用程序無響應(yīng)、界面無法正常顯示等問題。
- 從系統(tǒng)性能的角度來看,AMS通過合理地管理Activity的生命周期和任務(wù)棧,可以有效地利用系統(tǒng)資源。例如,它可以及時(shí)地暫?;蛘咪N毀不需要的Activity,釋放內(nèi)存和CPU資源,以確保系統(tǒng)能夠流暢地運(yùn)行其他應(yīng)用程序或者系統(tǒng)服務(wù)。
談?wù)剬?duì)PMS機(jī)制的理解
-
PMS(Package Manager Service)的基本概念
- PMS是Android系統(tǒng)中負(fù)責(zé)管理應(yīng)用程序包的核心服務(wù)。它就像是一個(gè)應(yīng)用程序的“倉庫管理員”,對(duì)系統(tǒng)中所有安裝的應(yīng)用程序包(APK文件)進(jìn)行全面管理。從應(yīng)用程序的安裝、卸載、更新,到解析APK文件獲取應(yīng)用程序的各種信息(如組件信息、權(quán)限信息等),都是PMS的職責(zé)范圍。
-
PMS在應(yīng)用程序安裝過程中的作用
- APK文件的驗(yàn)證與解析:當(dāng)用戶通過各種渠道(如應(yīng)用商店、手動(dòng)安裝等)安裝一個(gè)APK文件時(shí),PMS首先會(huì)對(duì)APK文件進(jìn)行驗(yàn)證。它會(huì)檢查APK文件的簽名是否合法,以確保應(yīng)用程序來自可信的開發(fā)者,防止惡意軟件的安裝。然后,PMS會(huì)對(duì)APK文件進(jìn)行解析,讀取其中的AndroidManifest.xml文件等關(guān)鍵信息。通過解析,PMS可以獲取應(yīng)用程序包含的組件(如Activity、Service、Broadcast Receiver、Content Provider)的詳細(xì)信息,包括它們的名稱、權(quán)限要求、啟動(dòng)模式等。
- 資源分配與安裝操作:在驗(yàn)證和解析之后,PMS會(huì)為新安裝的應(yīng)用程序分配必要的系統(tǒng)資源。這包括為應(yīng)用程序在文件系統(tǒng)中分配存儲(chǔ)空間,用于存放應(yīng)用程序的代碼、數(shù)據(jù)、配置文件等。同時(shí),PMS還會(huì)將應(yīng)用程序的相關(guān)信息(如包名、版本號(hào)、組件信息等)存儲(chǔ)到系統(tǒng)的數(shù)據(jù)庫中,以便后續(xù)管理和查詢。例如,它會(huì)在系統(tǒng)的
packages.xml
文件和相關(guān)數(shù)據(jù)庫表中記錄這些信息,這些記錄對(duì)于后續(xù)的應(yīng)用程序更新、啟動(dòng)等操作都非常重要。
-
PMS在應(yīng)用程序更新過程中的作用
- 版本檢查與更新策略:PMS會(huì)定期檢查應(yīng)用程序的更新情況。它會(huì)比較已安裝應(yīng)用程序的版本號(hào)與應(yīng)用商店(或其他更新源)提供的新版本號(hào)。當(dāng)發(fā)現(xiàn)有更新版本時(shí),PMS會(huì)根據(jù)預(yù)先設(shè)定的更新策略進(jìn)行操作。這些策略可能包括自動(dòng)更新、提示用戶更新等。如果是自動(dòng)更新,PMS會(huì)下載新的APK文件,然后重復(fù)類似于安裝過程的步驟,包括驗(yàn)證、解析和資源分配。在更新過程中,PMS還需要處理數(shù)據(jù)遷移等問題,例如確保用戶的數(shù)據(jù)在更新前后不會(huì)丟失,并且能夠被新版本的應(yīng)用程序正確使用。
- 權(quán)限變更處理:在應(yīng)用程序更新過程中,可能會(huì)出現(xiàn)權(quán)限變更的情況。例如,新版本的應(yīng)用程序可能需要新增一些權(quán)限或者修改現(xiàn)有權(quán)限的范圍。PMS會(huì)對(duì)這些權(quán)限變更進(jìn)行仔細(xì)檢查。如果新增的權(quán)限涉及用戶隱私等重要信息,PMS可能會(huì)提示用戶進(jìn)行確認(rèn)。同時(shí),PMS會(huì)更新系統(tǒng)數(shù)據(jù)庫中關(guān)于該應(yīng)用程序的權(quán)限記錄,以確保后續(xù)的管理和權(quán)限檢查能夠準(zhǔn)確反映應(yīng)用程序的實(shí)際權(quán)限需求。
-
PMS在應(yīng)用程序卸載過程中的作用
- 資源回收與信息清除:當(dāng)用戶卸載一個(gè)應(yīng)用程序時(shí),PMS會(huì)負(fù)責(zé)回收該應(yīng)用程序占用的所有系統(tǒng)資源。這包括刪除應(yīng)用程序在文件系統(tǒng)中的代碼、數(shù)據(jù)和配置文件等存儲(chǔ)內(nèi)容。同時(shí),PMS會(huì)從系統(tǒng)數(shù)據(jù)庫中清除與該應(yīng)用程序相關(guān)的所有記錄,如包名、組件信息、權(quán)限信息等。這樣可以確保系統(tǒng)的數(shù)據(jù)庫和存儲(chǔ)空間能夠得到有效利用,并且不會(huì)因?yàn)闅埩舻膽?yīng)用程序信息而導(dǎo)致系統(tǒng)出現(xiàn)混亂。
- 關(guān)聯(lián)組件處理:在卸載過程中,PMS還需要考慮與被卸載應(yīng)用程序相關(guān)的其他組件。例如,如果被卸載的應(yīng)用程序提供了一個(gè)Content Provider,并且其他應(yīng)用程序正在使用這個(gè)Content Provider,PMS需要妥善處理這種情況。它可能會(huì)通知相關(guān)的應(yīng)用程序這個(gè)Content Provider即將消失,或者采取其他措施來避免因?yàn)镃ontent Provider的缺失而導(dǎo)致其他應(yīng)用程序出現(xiàn)異常。
-
PMS與其他系統(tǒng)組件的交互關(guān)系
- 與AMS(Activity Manager Service)的交互:AMS負(fù)責(zé)管理Activity的生命周期等操作,而PMS為AMS提供關(guān)于應(yīng)用程序的基本信息。例如,當(dāng)AMS需要啟動(dòng)一個(gè)Activity時(shí),它會(huì)向PMS查詢這個(gè)Activity所屬應(yīng)用程序的信息,包括該應(yīng)用程序是否合法安裝、其權(quán)限是否滿足啟動(dòng)要求等。PMS提供的這些信息對(duì)于AMS正確地啟動(dòng)和管理Activity至關(guān)重要。
- 與Broadcast Receiver的交互:Broadcast Receiver用于接收系統(tǒng)或應(yīng)用程序發(fā)出的廣播消息。PMS管理著應(yīng)用程序中Broadcast Receiver的注冊(cè)信息。當(dāng)一個(gè)廣播消息發(fā)出時(shí),PMS可以根據(jù)自己存儲(chǔ)的注冊(cè)信息,通知符合條件的Broadcast Receiver接收廣播。同時(shí),在應(yīng)用程序安裝或卸載過程中,PMS會(huì)更新Broadcast Receiver的注冊(cè)狀態(tài),確保廣播系統(tǒng)的正常運(yùn)行。
- 與Content Provider的交互:Content Provider用于在不同應(yīng)用程序之間共享數(shù)據(jù)。PMS負(fù)責(zé)管理Content Provider的安裝、注冊(cè)和權(quán)限信息。當(dāng)一個(gè)應(yīng)用程序需要訪問另一個(gè)應(yīng)用程序的Content Provider時(shí),PMS會(huì)參與其中的權(quán)限檢查等操作,確保訪問是合法的。并且,在應(yīng)用程序更新或卸載時(shí),PMS會(huì)對(duì)Content Provider的狀態(tài)進(jìn)行相應(yīng)的調(diào)整。
談?wù)勍ㄟ^閱讀Framework層源碼解決的實(shí)際問題
- 解決Activity啟動(dòng)流程異常問題
- 問題描述:在開發(fā)一個(gè)復(fù)雜的Android應(yīng)用時(shí),遇到了Activity啟動(dòng)緩慢且偶爾無法啟動(dòng)的情況。通過查看Logcat日志,只能發(fā)現(xiàn)一些模糊的線索,如“Activity啟動(dòng)超時(shí)”等信息,但很難確定具體的原因。
- 源碼分析過程:深入研究Framework層中Activity啟動(dòng)相關(guān)的源碼,主要涉及到ActivityManagerService(AMS)相關(guān)部分。在AMS的源碼中,發(fā)現(xiàn)Activity啟動(dòng)過程涉及多個(gè)步驟,包括權(quán)限檢查、任務(wù)棧管理、資源分配等。通過逐步跟蹤源碼,發(fā)現(xiàn)問題出在權(quán)限檢查部分。在應(yīng)用中添加了新的權(quán)限要求,但在某些特殊設(shè)備或系統(tǒng)版本下,權(quán)限檢查機(jī)制與預(yù)期不符,導(dǎo)致Activity啟動(dòng)流程被阻塞。
- 解決方案及效果:根據(jù)源碼分析的結(jié)果,對(duì)權(quán)限檢查部分進(jìn)行了針對(duì)性的優(yōu)化。確保權(quán)限檢查的邏輯在不同設(shè)備和系統(tǒng)版本下都能夠正確執(zhí)行,避免了不必要的阻塞。經(jīng)過測(cè)試,Activity啟動(dòng)緩慢和無法啟動(dòng)的問題得到了解決,應(yīng)用的啟動(dòng)性能得到了顯著提升。
- 優(yōu)化應(yīng)用內(nèi)存管理問題
- 問題描述:應(yīng)用在長(zhǎng)時(shí)間運(yùn)行后,會(huì)出現(xiàn)內(nèi)存占用過高,甚至頻繁出現(xiàn)內(nèi)存溢出(OOM)的情況。使用常規(guī)的內(nèi)存分析工具,如Android Profiler,能夠發(fā)現(xiàn)內(nèi)存占用高的大致組件,但很難深入了解內(nèi)存泄漏的根源。
- 源碼分析過程:從Framework層的角度,研究了Android系統(tǒng)的內(nèi)存管理機(jī)制,特別是涉及到應(yīng)用組件(如Activity、Service等)生命周期管理與內(nèi)存回收的部分。重點(diǎn)關(guān)注了垃圾回收(GC)相關(guān)的源碼以及系統(tǒng)如何管理應(yīng)用組件的生命周期。通過分析發(fā)現(xiàn),在應(yīng)用中有一些自定義的廣播接收器(Broadcast Receiver)沒有正確地注銷,導(dǎo)致這些組件在不需要接收廣播后仍然被系統(tǒng)保留,占用內(nèi)存。而且,在某些復(fù)雜的界面跳轉(zhuǎn)場(chǎng)景下,Activity的生命周期管理出現(xiàn)混亂,舊的Activity沒有及時(shí)被回收。
- 解決方案及效果:根據(jù)源碼分析結(jié)果,在代碼中添加了正確注銷廣播接收器的邏輯,并且優(yōu)化了Activity的生命周期管理。例如,在Activity的
onDestroy
方法中,確保所有與該Activity相關(guān)的資源都被正確釋放。經(jīng)過這些優(yōu)化后,應(yīng)用長(zhǎng)時(shí)間運(yùn)行后的內(nèi)存占用明顯降低,不再出現(xiàn)OOM問題,系統(tǒng)的穩(wěn)定性得到了極大的提高。
- 解決Service與Activity通信故障問題
- 問題描述:應(yīng)用中有一個(gè)后臺(tái)運(yùn)行的Service,需要與前臺(tái)的Activity進(jìn)行頻繁通信,傳遞一些數(shù)據(jù)和狀態(tài)信息。但是在實(shí)際運(yùn)行中,出現(xiàn)了通信中斷、數(shù)據(jù)丟失的情況。
- 源碼分析過程:研究Framework層中Service與Activity通信的機(jī)制,主要涉及Binder機(jī)制。分析發(fā)現(xiàn),在Service和Activity之間通過Binder進(jìn)行通信時(shí),由于網(wǎng)絡(luò)狀態(tài)變化或者系統(tǒng)資源緊張等因素,導(dǎo)致Binder連接出現(xiàn)不穩(wěn)定的情況。在Binder機(jī)制的源碼中,看到了連接管理和數(shù)據(jù)傳輸?shù)募?xì)節(jié),包括數(shù)據(jù)的序列化和反序列化過程、連接異常處理等。
- 解決方案及效果:根據(jù)源碼的啟示,在應(yīng)用代碼中添加了連接狀態(tài)監(jiān)測(cè)和異常處理機(jī)制。當(dāng)發(fā)現(xiàn)Binder連接出現(xiàn)異常時(shí),及時(shí)嘗試重新建立連接,并且優(yōu)化了數(shù)據(jù)傳輸?shù)念l率和方式,避免一次性傳輸過多數(shù)據(jù)導(dǎo)致連接阻塞。經(jīng)過這些改進(jìn),Service與Activity之間的通信變得更加穩(wěn)定,數(shù)據(jù)丟失的問題得到了解決。
Android冷啟動(dòng)App
-
冷啟動(dòng)的概念
- 冷啟動(dòng)是指當(dāng)用戶首次啟動(dòng)一個(gè)應(yīng)用或者系統(tǒng)由于某種原因(如內(nèi)存回收)完全銷毀應(yīng)用進(jìn)程后再次啟動(dòng)應(yīng)用的過程。在冷啟動(dòng)時(shí),系統(tǒng)和應(yīng)用都需要執(zhí)行一系列完整的初始化操作。
- 從系統(tǒng)層面看,系統(tǒng)需要為應(yīng)用分配新的進(jìn)程空間,加載必要的運(yùn)行時(shí)環(huán)境(如ART虛擬機(jī)),然后開始啟動(dòng)應(yīng)用。從應(yīng)用層面看,要加載應(yīng)用的代碼、資源,初始化全局變量,創(chuàng)建和啟動(dòng)第一個(gè)Activity等。
-
冷啟動(dòng)的流程
- 進(jìn)程創(chuàng)建階段:
- 當(dāng)用戶點(diǎn)擊應(yīng)用圖標(biāo)時(shí),系統(tǒng)的Launcher(桌面啟動(dòng)器)會(huì)向系統(tǒng)的Activity Manager Service(AMS)發(fā)送啟動(dòng)該應(yīng)用的請(qǐng)求。AMS接收到請(qǐng)求后,會(huì)通過Zygote進(jìn)程來fork一個(gè)新的應(yīng)用進(jìn)程。這個(gè)新進(jìn)程是基于Zygote進(jìn)程已有的資源和環(huán)境創(chuàng)建的,會(huì)繼承Zygote進(jìn)程中預(yù)加載的一些系統(tǒng)類和運(yùn)行時(shí)環(huán)境。
- 新的應(yīng)用進(jìn)程創(chuàng)建后,會(huì)開始加載一些基本的運(yùn)行時(shí)環(huán)境,如加載Android運(yùn)行時(shí)庫(ART),并對(duì)其進(jìn)行初始化。這個(gè)過程包括設(shè)置一些默認(rèn)的參數(shù)和配置,為后續(xù)的應(yīng)用代碼執(zhí)行做好準(zhǔn)備。
- 應(yīng)用初始化階段:
- 首先會(huì)加載應(yīng)用的
Application
類。Application
類是應(yīng)用全局的上下文環(huán)境,在這里可以進(jìn)行一些全局的初始化操作,如初始化第三方庫、配置全局變量等。例如,如果應(yīng)用使用了數(shù)據(jù)庫,可能會(huì)在Application
類的onCreate
方法中初始化數(shù)據(jù)庫連接。 - 接著會(huì)加載和解析應(yīng)用的資源文件,包括布局文件、圖片資源、字符串資源等。這些資源是構(gòu)建應(yīng)用界面和實(shí)現(xiàn)功能的基礎(chǔ)。例如,當(dāng)啟動(dòng)一個(gè)Activity時(shí),需要從資源文件中獲取布局信息來構(gòu)建界面。
- 首先會(huì)加載應(yīng)用的
- Activity創(chuàng)建和顯示階段:
- AMS會(huì)根據(jù)應(yīng)用的AndroidManifest.xml文件中的配置信息,確定啟動(dòng)哪個(gè)Activity作為應(yīng)用的主界面。然后會(huì)創(chuàng)建這個(gè)Activity的實(shí)例,調(diào)用其
onCreate
方法。在onCreate
方法中,會(huì)設(shè)置Activity的布局,通常是通過setContentView
方法來加載布局資源。 - 之后會(huì)依次執(zhí)行Activity的生命周期方法,如
onStart
和onResume
,使Activity逐步進(jìn)入可見和可交互的狀態(tài)。這個(gè)過程還涉及到與系統(tǒng)的Window Manager Service(WMS)的交互,WMS會(huì)為Activity創(chuàng)建窗口并進(jìn)行顯示相關(guān)的操作,如處理窗口動(dòng)畫、將Activity的視圖添加到屏幕顯示隊(duì)列等。
- AMS會(huì)根據(jù)應(yīng)用的AndroidManifest.xml文件中的配置信息,確定啟動(dòng)哪個(gè)Activity作為應(yīng)用的主界面。然后會(huì)創(chuàng)建這個(gè)Activity的實(shí)例,調(diào)用其
- 進(jìn)程創(chuàng)建階段:
-
影響冷啟動(dòng)速度的因素
- 應(yīng)用代碼和資源大小:如果應(yīng)用的代碼量龐大,包含大量的類和方法,那么在冷啟動(dòng)時(shí)加載這些代碼的時(shí)間就會(huì)變長(zhǎng)。同樣,豐富的資源(如高分辨率的圖片、復(fù)雜的布局文件)也會(huì)增加加載時(shí)間。例如,一個(gè)游戲應(yīng)用有大量的紋理圖片資源用于渲染游戲場(chǎng)景,這些資源的加載會(huì)顯著影響冷啟動(dòng)速度。
- 初始化操作的復(fù)雜程度:在
Application
類和Activity的onCreate
方法中進(jìn)行過多復(fù)雜的初始化操作會(huì)延遲應(yīng)用的啟動(dòng)。比如,在Application
類中初始化多個(gè)大型第三方庫,每個(gè)庫都需要進(jìn)行網(wǎng)絡(luò)請(qǐng)求或者文件讀取等耗時(shí)操作,這會(huì)使冷啟動(dòng)時(shí)間大大增加。 - 系統(tǒng)資源狀況:當(dāng)系統(tǒng)內(nèi)存緊張或者CPU負(fù)載過高時(shí),應(yīng)用冷啟動(dòng)可能會(huì)受到影響。因?yàn)橄到y(tǒng)需要分配資源給新的應(yīng)用進(jìn)程,而有限的資源會(huì)導(dǎo)致分配過程變慢。例如,在同時(shí)啟動(dòng)多個(gè)大型應(yīng)用的情況下,系統(tǒng)可能會(huì)優(yōu)先分配資源給前臺(tái)應(yīng)用,使得后臺(tái)應(yīng)用的冷啟動(dòng)時(shí)間延長(zhǎng)。
-
優(yōu)化冷啟動(dòng)速度的方法
- 代碼和資源優(yōu)化:
- 對(duì)代碼進(jìn)行精簡(jiǎn),去除不必要的類和方法??梢允褂么a混淆工具,不僅能保護(hù)代碼,還能減少代碼體積。例如,ProGuard工具可以在構(gòu)建應(yīng)用時(shí)刪除未使用的代碼。
- 對(duì)于資源,采用合適的壓縮格式和分辨率。例如,對(duì)于非高清設(shè)備,使用較低分辨率的圖片資源。并且可以使用資源懶加載策略,即只在需要時(shí)才加載資源,而不是一次性全部加載。
- 延遲初始化操作:
- 在
Application
類中,避免一次性完成所有的初始化操作??梢詫⒁恍┓顷P(guān)鍵的初始化操作推遲到應(yīng)用真正需要時(shí)進(jìn)行。例如,對(duì)于一個(gè)有拍照功能的應(yīng)用,初始化相機(jī)相關(guān)的庫可以推遲到用戶打開相機(jī)功能時(shí)。 - 在Activity的
onCreate
方法中,也可以采用類似的策略。將一些不影響界面顯示的初始化(如加載某些非關(guān)鍵的數(shù)據(jù))放在onResume
或者更后的生命周期方法中進(jìn)行。
- 在
- 利用系統(tǒng)機(jī)制優(yōu)化:
- 利用Android的多進(jìn)程機(jī)制,將一些獨(dú)立的功能模塊(如推送服務(wù))放在單獨(dú)的進(jìn)程中。這樣在冷啟動(dòng)主應(yīng)用進(jìn)程時(shí),這些獨(dú)立進(jìn)程不會(huì)影響啟動(dòng)速度,并且可以提前進(jìn)行一些準(zhǔn)備工作。
- 還可以通過預(yù)加載機(jī)制來提高冷啟動(dòng)速度。例如,使用Android的JobScheduler在系統(tǒng)空閑時(shí)提前加載部分應(yīng)用資源或者初始化部分代碼,為后續(xù)的冷啟動(dòng)做好準(zhǔn)備。
- 代碼和資源優(yōu)化:
Android熱啟動(dòng)App
-
熱啟動(dòng)的概念
- 熱啟動(dòng)是指當(dāng)應(yīng)用已經(jīng)被啟動(dòng)過,并且其進(jìn)程仍然存在于系統(tǒng)內(nèi)存中,用戶再次打開該應(yīng)用(例如從后臺(tái)切換到前臺(tái))的啟動(dòng)方式。與冷啟動(dòng)相比,熱啟動(dòng)不需要重新創(chuàng)建應(yīng)用進(jìn)程和加載所有的代碼與資源,因?yàn)檫@些已經(jīng)在內(nèi)存中準(zhǔn)備好了,所以熱啟動(dòng)通常比冷啟動(dòng)快很多。
-
熱啟動(dòng)的流程
- Activity恢復(fù)階段:
- 當(dāng)用戶將應(yīng)用從后臺(tái)切換到前臺(tái)時(shí),系統(tǒng)會(huì)調(diào)用處于棧頂?shù)腁ctivity(如果有多個(gè)Activity在任務(wù)棧中)的
onRestart
方法。這個(gè)方法標(biāo)志著Activity開始從后臺(tái)狀態(tài)恢復(fù)到前臺(tái)狀態(tài)。在onRestart
方法中,Activity可以執(zhí)行一些必要的操作來重新獲取焦點(diǎn),例如重新注冊(cè)一些在onPause
或onStop
階段被注銷的資源或監(jiān)聽器。 - 接著會(huì)依次執(zhí)行
onStart
和onResume
方法。onStart
方法會(huì)使Activity在屏幕上變?yōu)榭梢姞顟B(tài),onResume
方法則讓Activity完全恢復(fù)到可交互狀態(tài)。在這兩個(gè)方法中,Activity可以重新連接一些服務(wù)(如后臺(tái)的數(shù)據(jù)加載服務(wù)),更新界面顯示(例如刷新數(shù)據(jù)顯示)等操作。
- 當(dāng)用戶將應(yīng)用從后臺(tái)切換到前臺(tái)時(shí),系統(tǒng)會(huì)調(diào)用處于棧頂?shù)腁ctivity(如果有多個(gè)Activity在任務(wù)棧中)的
- 資源恢復(fù)與更新階段:
- 雖然應(yīng)用進(jìn)程在內(nèi)存中,大部分資源已經(jīng)加載,但有些資源可能需要重新獲取或更新。例如,如果應(yīng)用在后臺(tái)時(shí)網(wǎng)絡(luò)連接發(fā)生了變化,或者有新的數(shù)據(jù)推送,那么在熱啟動(dòng)過程中可能需要重新獲取網(wǎng)絡(luò)數(shù)據(jù)并更新界面。對(duì)于一些需要實(shí)時(shí)更新的資源,如傳感器數(shù)據(jù)(加速度計(jì)、陀螺儀等),也需要在熱啟動(dòng)過程中重新建立連接并獲取最新數(shù)據(jù)。
- 另外,系統(tǒng)的一些配置參數(shù)可能在應(yīng)用處于后臺(tái)時(shí)發(fā)生了變化,如屏幕方向、語言環(huán)境等。在熱啟動(dòng)時(shí),應(yīng)用需要檢查這些配置變化并相應(yīng)地更新界面布局和資源。例如,如果屏幕方向發(fā)生了變化,應(yīng)用可能需要重新加載和調(diào)整布局資源,以適應(yīng)新的屏幕方向。
- Activity恢復(fù)階段:
-
影響熱啟動(dòng)速度的因素
- 后臺(tái)任務(wù)的復(fù)雜程度:如果應(yīng)用在后臺(tái)執(zhí)行了大量復(fù)雜的任務(wù),例如持續(xù)進(jìn)行大數(shù)據(jù)量的網(wǎng)絡(luò)下載、復(fù)雜的計(jì)算任務(wù)等,那么在熱啟動(dòng)時(shí),這些后臺(tái)任務(wù)可能會(huì)影響系統(tǒng)資源的分配,導(dǎo)致熱啟動(dòng)速度變慢。例如,一個(gè)文件下載應(yīng)用在后臺(tái)一直在下載大型文件,當(dāng)熱啟動(dòng)時(shí),系統(tǒng)可能需要花費(fèi)時(shí)間來暫停或調(diào)整這些下載任務(wù),從而影響熱啟動(dòng)的速度。
- 資源更新的數(shù)量和難度:當(dāng)需要更新的資源數(shù)量較多或者更新過程比較復(fù)雜時(shí),熱啟動(dòng)速度會(huì)受到影響。例如,一個(gè)新聞閱讀應(yīng)用在后臺(tái)收到了大量新的新聞推送,在熱啟動(dòng)時(shí)需要更新界面來顯示這些新聞,包括解析新聞內(nèi)容、加載圖片等操作,這會(huì)增加熱啟動(dòng)的時(shí)間。
- 系統(tǒng)資源競(jìng)爭(zhēng):當(dāng)系統(tǒng)內(nèi)存緊張或者其他應(yīng)用在前臺(tái)占用大量資源(如CPU、網(wǎng)絡(luò)帶寬等)時(shí),熱啟動(dòng)的應(yīng)用可能會(huì)受到資源限制。例如,在一個(gè)多任務(wù)處理的場(chǎng)景下,同時(shí)運(yùn)行多個(gè)大型游戲和其他應(yīng)用,當(dāng)切換到一個(gè)后臺(tái)的應(yīng)用進(jìn)行熱啟動(dòng)時(shí),由于系統(tǒng)資源被其他應(yīng)用占用,熱啟動(dòng)的速度可能會(huì)變慢。
-
優(yōu)化熱啟動(dòng)速度的方法
- 優(yōu)化后臺(tái)任務(wù)管理:
- 合理控制后臺(tái)任務(wù)的執(zhí)行,避免在后臺(tái)進(jìn)行非必要的復(fù)雜任務(wù)。例如,可以通過使用
JobScheduler
或WorkManager
來調(diào)度后臺(tái)任務(wù),在系統(tǒng)資源允許的情況下進(jìn)行任務(wù)執(zhí)行。對(duì)于一些不重要的后臺(tái)任務(wù),如定期的數(shù)據(jù)更新,可以適當(dāng)延遲或暫停,以確保在熱啟動(dòng)時(shí)不會(huì)占用過多資源。 - 當(dāng)應(yīng)用切換到后臺(tái)時(shí),及時(shí)清理和釋放一些不必要的資源。例如,關(guān)閉一些不再需要的數(shù)據(jù)庫連接、釋放內(nèi)存緩存等,這樣可以減少在熱啟動(dòng)時(shí)需要恢復(fù)和處理的資源量。
- 合理控制后臺(tái)任務(wù)的執(zhí)行,避免在后臺(tái)進(jìn)行非必要的復(fù)雜任務(wù)。例如,可以通過使用
- 高效的資源更新策略:
- 采用增量式更新資源的方法,而不是一次性更新所有資源。例如,對(duì)于一個(gè)社交應(yīng)用,在熱啟動(dòng)時(shí)只更新用戶頭像、最新消息等關(guān)鍵信息,而不是重新加載所有用戶信息和聊天記錄。
- 利用緩存機(jī)制來加速資源更新。如果之前已經(jīng)獲取過某些資源(如圖片、新聞內(nèi)容等),并且這些資源沒有發(fā)生變化,可以直接從緩存中獲取,而不是重新請(qǐng)求。例如,可以使用內(nèi)存緩存庫(如LruCache)來存儲(chǔ)和快速獲取常用的資源。
- 減少系統(tǒng)資源競(jìng)爭(zhēng):
- 優(yōu)化應(yīng)用的資源占用,使其在熱啟動(dòng)時(shí)不會(huì)過度依賴系統(tǒng)資源。例如,減少不必要的動(dòng)畫效果、降低網(wǎng)絡(luò)請(qǐng)求頻率等。并且可以通過設(shè)置應(yīng)用的優(yōu)先級(jí)(如在
AndroidManifest.xml
中調(diào)整android:process
屬性)來合理分配系統(tǒng)資源,確保在熱啟動(dòng)時(shí)能夠更快地獲取所需資源。
- 優(yōu)化應(yīng)用的資源占用,使其在熱啟動(dòng)時(shí)不會(huì)過度依賴系統(tǒng)資源。例如,減少不必要的動(dòng)畫效果、降低網(wǎng)絡(luò)請(qǐng)求頻率等。并且可以通過設(shè)置應(yīng)用的優(yōu)先級(jí)(如在
- 優(yōu)化后臺(tái)任務(wù)管理:
啟動(dòng)一個(gè)Activity
-
啟動(dòng)請(qǐng)求階段
- 當(dāng)用戶點(diǎn)擊一個(gè)應(yīng)用圖標(biāo)或者在應(yīng)用內(nèi)部通過Intent(意圖)觸發(fā)一個(gè)Activity的啟動(dòng)(如從一個(gè)Activity跳轉(zhuǎn)到另一個(gè)Activity)時(shí),這個(gè)請(qǐng)求首先會(huì)被發(fā)送到系統(tǒng)的Launcher(桌面啟動(dòng)器)或者當(dāng)前Activity所在的應(yīng)用進(jìn)程。
- 以應(yīng)用內(nèi)部啟動(dòng)為例,發(fā)起方(通常是一個(gè)Activity)會(huì)創(chuàng)建一個(gè)Intent對(duì)象,這個(gè)Intent對(duì)象包含了要啟動(dòng)的Activity的信息,如組件名稱(通過包名和類名指定)或者動(dòng)作(
action
)與類別(category
)的組合。例如,Intent intent = new Intent(this, TargetActivity.class);
,這里this
是當(dāng)前Activity的上下文,TargetActivity.class
是要啟動(dòng)的Activity的類。
-
跨進(jìn)程通信(IPC)階段(如果需要)
- 如果要啟動(dòng)的Activity屬于另一個(gè)應(yīng)用程序,那么就涉及到跨進(jìn)程通信。系統(tǒng)會(huì)通過Binder機(jī)制將啟動(dòng)請(qǐng)求發(fā)送給Activity Manager Service(AMS)。
- AMS運(yùn)行在系統(tǒng)進(jìn)程中,它負(fù)責(zé)管理系統(tǒng)中的所有Activity。發(fā)起方的應(yīng)用進(jìn)程會(huì)把Intent和相關(guān)的請(qǐng)求信息打包發(fā)送給AMS,這個(gè)過程中,Binder驅(qū)動(dòng)會(huì)起到關(guān)鍵的中介作用,確保數(shù)據(jù)在不同進(jìn)程間安全、高效地傳遞。
-
權(quán)限檢查與驗(yàn)證階段
- AMS收到啟動(dòng)請(qǐng)求后,首先會(huì)進(jìn)行權(quán)限檢查。它會(huì)查看要啟動(dòng)的Activity所需的權(quán)限是否已經(jīng)被授予。這些權(quán)限信息可以從應(yīng)用的AndroidManifest.xml文件中獲取。
- 例如,如果要啟動(dòng)的Activity需要訪問用戶的位置信息,而發(fā)起方應(yīng)用沒有獲取該權(quán)限,那么AMS可能會(huì)拒絕這個(gè)啟動(dòng)請(qǐng)求,或者根據(jù)系統(tǒng)設(shè)置提示用戶授予權(quán)限。同時(shí),AMS還會(huì)檢查Activity的合法性,比如該Activity是否是一個(gè)有效的組件,是否在應(yīng)用的注冊(cè)組件范圍內(nèi)等。
-
目標(biāo)Activity創(chuàng)建階段
- 在權(quán)限檢查通過后,AMS會(huì)根據(jù)Intent中的信息確定要啟動(dòng)的Activity。如果目標(biāo)Activity所屬的應(yīng)用進(jìn)程尚未啟動(dòng),AMS會(huì)通過Zygote進(jìn)程來fork一個(gè)新的應(yīng)用進(jìn)程用于該Activity所屬的應(yīng)用。
- 新的應(yīng)用進(jìn)程創(chuàng)建后,會(huì)加載應(yīng)用的
Application
類(如果還沒有加載),然后開始創(chuàng)建目標(biāo)Activity。在這個(gè)過程中,會(huì)調(diào)用Activity的構(gòu)造函數(shù),接著調(diào)用onCreate
方法。在onCreate
方法中,通常會(huì)通過setContentView
來設(shè)置Activity的布局,加載各種資源,初始化視圖組件等。
-
Activity生命周期推進(jìn)階段
- 目標(biāo)Activity創(chuàng)建完成后,會(huì)按照Activity的生命周期方法依次執(zhí)行。首先是
onStart
方法,此時(shí)Activity在屏幕上變?yōu)榭梢姞顟B(tài),但還不能與用戶進(jìn)行交互。 - 接著會(huì)執(zhí)行
onResume
方法,在這個(gè)方法執(zhí)行后,Activity就完全進(jìn)入前臺(tái)可交互狀態(tài)。在onResume
過程中,可能會(huì)涉及到一些資源的獲取和恢復(fù)操作,如注冊(cè)傳感器監(jiān)聽器、重新建立網(wǎng)絡(luò)連接等,以確保Activity能夠正常地與用戶進(jìn)行交互。
- 目標(biāo)Activity創(chuàng)建完成后,會(huì)按照Activity的生命周期方法依次執(zhí)行。首先是
-
視圖顯示階段
- 在Activity的生命周期推進(jìn)過程中,系統(tǒng)的Window Manager Service(WMS)會(huì)參與其中。WMS負(fù)責(zé)管理系統(tǒng)中的窗口,包括Activity的窗口。
- 當(dāng)Activity進(jìn)入
onResume
狀態(tài)后,WMS會(huì)將Activity的視圖添加到窗口顯示隊(duì)列中,處理窗口動(dòng)畫等顯示相關(guān)的操作,使得Activity的視圖能夠正確地顯示在屏幕上,最終完成Activity的啟動(dòng)過程。
熟練使用 systrace、traceview、AS profile 等多種性能監(jiān)控與優(yōu)化工具,在性能優(yōu)化、內(nèi)存泄漏上報(bào)(KOOM)以及用戶體驗(yàn)優(yōu)化方面積累了豐富的實(shí)際調(diào)優(yōu)經(jīng)驗(yàn)。
systrace的使用
-
systrace的基本概念
- Systrace是Android平臺(tái)提供的一個(gè)性能分析工具,用于收集和分析系統(tǒng)級(jí)別的事件信息。它可以幫助開發(fā)者深入了解應(yīng)用在運(yùn)行過程中的系統(tǒng)行為,包括CPU使用情況、進(jìn)程調(diào)度、磁盤I/O、網(wǎng)絡(luò)活動(dòng)等多個(gè)方面。通過這些信息,開發(fā)者可以發(fā)現(xiàn)性能瓶頸,優(yōu)化應(yīng)用性能。
-
systrace的安裝和配置
- 環(huán)境搭建:
- 要使用systrace,首先需要安裝Python環(huán)境。因?yàn)閟ystrace是通過Python腳本運(yùn)行的。在Android SDK中已經(jīng)包含了systrace工具,它位于
$ANDROID_HOME/platform - tools/systrace
目錄下。確保你的系統(tǒng)已經(jīng)安裝了Android SDK,并且將SDK的platform - tools
目錄添加到環(huán)境變量中。
- 要使用systrace,首先需要安裝Python環(huán)境。因?yàn)閟ystrace是通過Python腳本運(yùn)行的。在Android SDK中已經(jīng)包含了systrace工具,它位于
- 設(shè)備連接和配置:
- 使用USB數(shù)據(jù)線將需要進(jìn)行性能分析的Android設(shè)備連接到開發(fā)電腦。確保設(shè)備已經(jīng)開啟了開發(fā)者選項(xiàng),并且允許通過USB進(jìn)行調(diào)試。在設(shè)備上,可能還需要安裝一些額外的配置文件,具體取決于你要分析的內(nèi)容。例如,如果你要分析圖形性能,可能需要安裝GPU調(diào)試符號(hào)。
- 環(huán)境搭建:
-
systrace的使用步驟
- 啟動(dòng)數(shù)據(jù)收集:
- 打開命令行終端,進(jìn)入到systrace工具所在的目錄(如
$ANDROID_HOME/platform - tools/systrace
)。然后使用命令來啟動(dòng)數(shù)據(jù)收集,例如systrace.py -o my_trace.html sched gfx view
。這個(gè)命令中的-o my_trace.html
指定了輸出文件的名稱為my_trace.html
,sched gfx view
是要跟蹤的標(biāo)簽,在這里分別表示調(diào)度(sched)、圖形(gfx)和視圖(view)相關(guān)的事件。你可以根據(jù)具體的分析需求選擇不同的標(biāo)簽,如添加binder
標(biāo)簽來分析跨進(jìn)程通信。
- 打開命令行終端,進(jìn)入到systrace工具所在的目錄(如
- 運(yùn)行應(yīng)用并操作:
- 在systrace開始收集數(shù)據(jù)后,在設(shè)備上運(yùn)行你想要分析性能的應(yīng)用。然后按照你期望分析的場(chǎng)景進(jìn)行操作,例如,如果是一個(gè)游戲應(yīng)用,就開始玩游戲,執(zhí)行游戲中的各種操作,如角色移動(dòng)、戰(zhàn)斗等;如果是一個(gè)社交應(yīng)用,就進(jìn)行瀏覽消息、發(fā)送消息等操作。這樣可以讓systrace收集到應(yīng)用在實(shí)際運(yùn)行過程中的相關(guān)性能數(shù)據(jù)。
- 停止數(shù)據(jù)收集并分析:
- 當(dāng)完成應(yīng)用操作后,在命令行終端中按Ctrl + C來停止systrace的數(shù)據(jù)收集。此時(shí),systrace會(huì)生成一個(gè)HTML文件(如前面指定的
my_trace.html
)。用瀏覽器打開這個(gè)HTML文件,就可以看到一個(gè)可視化的性能分析圖表。圖表的橫軸表示時(shí)間,縱軸表示不同的系統(tǒng)組件或標(biāo)簽。通過滾動(dòng)、縮放圖表,以及查看不同標(biāo)簽下的事件信息,可以發(fā)現(xiàn)性能問題。例如,如果你發(fā)現(xiàn)CPU使用率長(zhǎng)時(shí)間處于高位,或者圖形渲染出現(xiàn)延遲,就可以深入分析對(duì)應(yīng)的事件來找出原因。
- 當(dāng)完成應(yīng)用操作后,在命令行終端中按Ctrl + C來停止systrace的數(shù)據(jù)收集。此時(shí),systrace會(huì)生成一個(gè)HTML文件(如前面指定的
- 啟動(dòng)數(shù)據(jù)收集:
-
systrace圖表的解讀
- 時(shí)間軸分析:
- 在systrace圖表中,時(shí)間軸是一個(gè)關(guān)鍵元素??梢圆榭锤鱾€(gè)事件在時(shí)間上的分布,了解應(yīng)用的操作流程以及系統(tǒng)響應(yīng)的時(shí)間順序。例如,當(dāng)一個(gè)Activity啟動(dòng)時(shí),可以看到在時(shí)間軸上的一系列相關(guān)事件,包括進(jìn)程創(chuàng)建、視圖加載、資源分配等,以及這些事件所花費(fèi)的時(shí)間。如果某個(gè)事件花費(fèi)的時(shí)間過長(zhǎng),就可能是一個(gè)性能瓶頸。
- 標(biāo)簽信息解讀:
- 不同的標(biāo)簽代表不同的系統(tǒng)組件或功能。例如,
sched
標(biāo)簽可以顯示CPU調(diào)度信息,包括各個(gè)進(jìn)程和線程的運(yùn)行時(shí)間、等待時(shí)間等。gfx
標(biāo)簽用于分析圖形性能,如GPU的使用率、幀渲染時(shí)間等。binder
標(biāo)簽則可以查看跨進(jìn)程通信的情況,包括通信的頻率、耗時(shí)等。通過查看這些標(biāo)簽下的詳細(xì)信息,可以深入了解每個(gè)系統(tǒng)組件對(duì)應(yīng)用性能的影響。
- 不同的標(biāo)簽代表不同的系統(tǒng)組件或功能。例如,
- 事件關(guān)聯(lián)分析:
- Systrace圖表還可以幫助分析不同事件之間的關(guān)聯(lián)。例如,一個(gè)網(wǎng)絡(luò)請(qǐng)求事件可能會(huì)影響后續(xù)的視圖更新事件,通過查看圖表中的事件順序和時(shí)間間隔,可以了解這種關(guān)聯(lián)是否正常。如果發(fā)現(xiàn)網(wǎng)絡(luò)請(qǐng)求完成后,視圖更新出現(xiàn)延遲,就可以進(jìn)一步分析是網(wǎng)絡(luò)數(shù)據(jù)處理問題還是視圖更新機(jī)制的問題。
- 時(shí)間軸分析:
traceView的使用
-
TraceView的基本概念
- TraceView是Android SDK提供的一種性能分析工具,主要用于分析Android應(yīng)用程序中方法的執(zhí)行時(shí)間和調(diào)用關(guān)系。它可以幫助開發(fā)者找出應(yīng)用中執(zhí)行時(shí)間過長(zhǎng)的方法、頻繁調(diào)用的方法,從而發(fā)現(xiàn)性能瓶頸,優(yōu)化代碼。
-
TraceView的啟動(dòng)方式
- 代碼方式啟動(dòng):
- 在應(yīng)用代碼中,可以使用
Debug
類來啟動(dòng)和停止TraceView的跟蹤。例如,在要分析的代碼段開始處,添加Debug.startMethodTracing("trace_file_name");
,這里"trace_file_name"
是跟蹤數(shù)據(jù)保存的文件名。在要分析的代碼段結(jié)束后,添加Debug.stopMethodTracing();
。當(dāng)應(yīng)用運(yùn)行到startMethodTracing
語句時(shí),會(huì)開始記錄方法調(diào)用的相關(guān)信息,直到遇到stopMethodTracing
語句停止記錄。這些信息會(huì)保存在設(shè)備的內(nèi)部存儲(chǔ)中,文件路徑通常是/data/data/your_package_name/files/trace_file_name.trace
。
- 在應(yīng)用代碼中,可以使用
- 通過DDMS啟動(dòng):
- 首先將Android設(shè)備連接到開發(fā)電腦,并打開DDMS(Dalvik Debug Monitor Server)工具。在DDMS中,選擇要分析的應(yīng)用進(jìn)程。然后在DDMS的菜單中找到“Start Method Profiling”選項(xiàng)并點(diǎn)擊,此時(shí)就開始了對(duì)該應(yīng)用進(jìn)程的方法跟蹤。當(dāng)完成需要分析的操作后,再次點(diǎn)擊“Stop Method Profiling”選項(xiàng),TraceView會(huì)自動(dòng)生成跟蹤數(shù)據(jù)文件,并且可以在DDMS中直接查看分析結(jié)果。
- 代碼方式啟動(dòng):
-
TraceView分析界面介紹
- 時(shí)間軸視圖(Timeline View):
- 在TraceView的時(shí)間軸視圖中,橫軸表示時(shí)間,縱軸表示線程。每個(gè)線程中的方法調(diào)用會(huì)以彩色的矩形條表示,矩形條的長(zhǎng)度代表方法的執(zhí)行時(shí)間。通過時(shí)間軸視圖,可以直觀地看到不同線程中方法的執(zhí)行順序和時(shí)間跨度。例如,可以發(fā)現(xiàn)某個(gè)線程在一段時(shí)間內(nèi)一直被某個(gè)方法占用,這可能是一個(gè)性能問題。
- 調(diào)用樹視圖(Call Tree View):
- 調(diào)用樹視圖展示了方法之間的調(diào)用關(guān)系。它以樹形結(jié)構(gòu)呈現(xiàn),根節(jié)點(diǎn)是應(yīng)用的入口方法(如
main
方法或者Application
類的onCreate
方法)。展開樹節(jié)點(diǎn),可以看到每個(gè)方法調(diào)用的子方法,以及每個(gè)方法的執(zhí)行時(shí)間、調(diào)用次數(shù)等信息。在這里,可以分析出方法的嵌套調(diào)用情況,以及每個(gè)方法在整個(gè)調(diào)用鏈中的時(shí)間占比。例如,如果一個(gè)方法的子方法執(zhí)行時(shí)間過長(zhǎng),就可以深入研究這個(gè)子方法是否有優(yōu)化的空間。
- 調(diào)用樹視圖展示了方法之間的調(diào)用關(guān)系。它以樹形結(jié)構(gòu)呈現(xiàn),根節(jié)點(diǎn)是應(yīng)用的入口方法(如
- 詳細(xì)信息面板(Detail Panel):
- 當(dāng)在時(shí)間軸視圖或者調(diào)用樹視圖中選擇一個(gè)方法時(shí),詳細(xì)信息面板會(huì)顯示該方法的詳細(xì)信息。包括該方法的名稱、所屬類、執(zhí)行時(shí)間(包括自身執(zhí)行時(shí)間和包含子方法的總執(zhí)行時(shí)間)、調(diào)用次數(shù)、平均執(zhí)行時(shí)間等。這些詳細(xì)信息有助于更精確地評(píng)估方法的性能影響,例如,通過比較執(zhí)行時(shí)間和調(diào)用次數(shù),可以判斷一個(gè)方法是因?yàn)閱未螆?zhí)行時(shí)間長(zhǎng)還是因?yàn)轭l繁調(diào)用而導(dǎo)致性能問題。
- 時(shí)間軸視圖(Timeline View):
-
利用TraceView進(jìn)行性能優(yōu)化
- 找出耗時(shí)方法:
- 在時(shí)間軸視圖或者調(diào)用樹視圖中,很容易找到那些執(zhí)行時(shí)間較長(zhǎng)的方法。這些方法可能是復(fù)雜的計(jì)算邏輯、頻繁的I/O操作或者大量的數(shù)據(jù)庫查詢等導(dǎo)致的。對(duì)于這些方法,可以考慮優(yōu)化算法、減少I/O操作次數(shù)或者優(yōu)化數(shù)據(jù)庫查詢語句等方式來縮短執(zhí)行時(shí)間。
- 分析方法調(diào)用頻率:
- 通過查看調(diào)用樹視圖和方法的調(diào)用次數(shù)信息,能夠發(fā)現(xiàn)一些被頻繁調(diào)用的方法。如果這些方法本身執(zhí)行時(shí)間不長(zhǎng),但由于頻繁調(diào)用導(dǎo)致總體性能下降,可以考慮緩存結(jié)果、合并調(diào)用或者優(yōu)化調(diào)用邏輯等方式來減少調(diào)用次數(shù)。
- 優(yōu)化調(diào)用鏈:
- 在調(diào)用樹視圖中分析方法的調(diào)用鏈,可以發(fā)現(xiàn)一些不必要的嵌套調(diào)用或者可以并行執(zhí)行的方法。對(duì)于不必要的嵌套調(diào)用,可以嘗試簡(jiǎn)化調(diào)用邏輯;對(duì)于可以并行執(zhí)行的方法,可以通過多線程等方式來提高執(zhí)行效率。
- 找出耗時(shí)方法:
Android sutio Profile的使用
-
Android Studio Profile基本概念
- Android Studio Profile是Android Studio集成的一個(gè)強(qiáng)大的性能分析工具。它可以幫助開發(fā)者全面地分析Android應(yīng)用的性能,包括CPU、內(nèi)存、網(wǎng)絡(luò)和電量等多個(gè)方面。通過收集應(yīng)用在運(yùn)行過程中的各種性能數(shù)據(jù),并以直觀的圖表和報(bào)告形式呈現(xiàn),開發(fā)者可以深入了解應(yīng)用的性能瓶頸并進(jìn)行針對(duì)性的優(yōu)化。
-
啟動(dòng)Profile工具并配置分析類型
- 啟動(dòng)方式:在Android Studio中,通過點(diǎn)擊“Run”菜單,然后選擇“Profiler”選項(xiàng)來啟動(dòng)Profile工具。另外,也可以在工具欄中找到“Profiler”圖標(biāo)并點(diǎn)擊啟動(dòng)。當(dāng)應(yīng)用運(yùn)行在設(shè)備或模擬器上時(shí),Profile工具會(huì)自動(dòng)連接并開始收集數(shù)據(jù)。
- 分析類型選擇:Profile工具提供了多種性能分析類型,如CPU Profiler、Memory Profiler、Network Profiler和Energy Profiler。
- CPU Profiler:用于分析應(yīng)用程序的CPU使用情況。它可以記錄應(yīng)用中方法的執(zhí)行時(shí)間和調(diào)用頻率,幫助找到CPU密集型的代碼部分??梢赃x擇不同的采樣方式,如Java方法采樣、Native方法采樣或者兩者同時(shí)采樣。
- Memory Profiler:主要關(guān)注應(yīng)用的內(nèi)存使用。它能夠?qū)崟r(shí)顯示應(yīng)用的內(nèi)存分配情況,包括堆內(nèi)存和原生內(nèi)存??梢詭椭l(fā)現(xiàn)內(nèi)存泄漏、內(nèi)存抖動(dòng)等問題,并且可以查看對(duì)象的分配和釋放情況。
- Network Profiler:用于跟蹤應(yīng)用的網(wǎng)絡(luò)活動(dòng)。可以看到網(wǎng)絡(luò)請(qǐng)求的時(shí)間、數(shù)據(jù)量、請(qǐng)求類型(如HTTP/HTTPS)等信息。這對(duì)于優(yōu)化網(wǎng)絡(luò)請(qǐng)求、減少數(shù)據(jù)傳輸量等網(wǎng)絡(luò)性能優(yōu)化非常有用。
- Energy Profiler:關(guān)注應(yīng)用的電量消耗情況。它可以提供應(yīng)用在不同設(shè)備狀態(tài)(如屏幕亮/暗、CPU頻率等)下的電量消耗估計(jì),幫助開發(fā)者優(yōu)化應(yīng)用以減少不必要的電量消耗。
-
CPU Profiler的使用方法和數(shù)據(jù)解讀
- 記錄數(shù)據(jù):在CPU Profiler中,點(diǎn)擊“Record”按鈕開始記錄CPU相關(guān)的數(shù)據(jù)。在應(yīng)用中執(zhí)行要分析的操作,如啟動(dòng)一個(gè)Activity、進(jìn)行復(fù)雜的計(jì)算等。操作完成后,點(diǎn)擊“Stop”按鈕停止記錄。
- 火焰圖(Flame Chart)解讀:火焰圖是CPU Profiler中的一種重要的可視化方式。它以圖形化的方式展示了方法的調(diào)用棧和執(zhí)行時(shí)間。在火焰圖中,橫軸表示時(shí)間,縱軸表示方法調(diào)用棧。每個(gè)方法用一個(gè)矩形表示,矩形的寬度代表該方法的執(zhí)行時(shí)間。從下往上看,下層方法是上層方法的調(diào)用者。通過火焰圖,可以快速找到執(zhí)行時(shí)間長(zhǎng)的方法和調(diào)用路徑。
- 調(diào)用樹(Call Tree)分析:調(diào)用樹視圖展示了方法之間的詳細(xì)調(diào)用關(guān)系??梢圆榭疵總€(gè)方法的執(zhí)行時(shí)間、調(diào)用次數(shù)、自身執(zhí)行時(shí)間等信息。通過分析調(diào)用樹,可以發(fā)現(xiàn)哪些方法被頻繁調(diào)用,以及它們對(duì)CPU資源的占用情況。
-
Memory Profiler的使用方法和數(shù)據(jù)解讀
- 內(nèi)存數(shù)據(jù)查看:Memory Profiler會(huì)實(shí)時(shí)顯示應(yīng)用的內(nèi)存使用情況??梢圆榭炊褍?nèi)存的使用量、已分配對(duì)象的數(shù)量等基本信息。通過點(diǎn)擊“Dump Java Heap”按鈕,可以獲取一個(gè)內(nèi)存快照,用于分析當(dāng)前內(nèi)存中的對(duì)象。
- 內(nèi)存泄漏分析:在內(nèi)存快照中,查找那些應(yīng)該被回收但仍然存在的對(duì)象。如果發(fā)現(xiàn)某個(gè)對(duì)象的引用計(jì)數(shù)在一段時(shí)間內(nèi)沒有下降,或者對(duì)象數(shù)量持續(xù)增加,可能存在內(nèi)存泄漏??梢酝ㄟ^分析對(duì)象的引用鏈來確定泄漏的原因。
- 內(nèi)存抖動(dòng)觀察:內(nèi)存抖動(dòng)是指內(nèi)存頻繁地分配和釋放,導(dǎo)致性能下降。在Memory Profiler中,可以觀察到內(nèi)存使用量的波動(dòng)情況。如果發(fā)現(xiàn)內(nèi)存使用量頻繁地大幅度上升和下降,可能存在內(nèi)存抖動(dòng)問題,需要檢查代碼中是否存在頻繁創(chuàng)建和銷毀對(duì)象的情況。
-
Network Profiler和Energy Profiler的使用要點(diǎn)
- Network Profiler:
- 查看網(wǎng)絡(luò)請(qǐng)求的詳細(xì)信息,包括請(qǐng)求的URL、響應(yīng)時(shí)間、請(qǐng)求方法(如GET、POST)和傳輸?shù)臄?shù)據(jù)量??梢酝ㄟ^分析這些信息來優(yōu)化網(wǎng)絡(luò)請(qǐng)求,例如合并多個(gè)小的請(qǐng)求為一個(gè)大的請(qǐng)求,或者優(yōu)化請(qǐng)求的順序。
- 識(shí)別網(wǎng)絡(luò)性能瓶頸,如長(zhǎng)時(shí)間的等待響應(yīng)或者高數(shù)據(jù)傳輸延遲。這可能是由于網(wǎng)絡(luò)環(huán)境差或者服務(wù)器端的問題導(dǎo)致的,也可能是應(yīng)用自身的網(wǎng)絡(luò)請(qǐng)求邏輯需要優(yōu)化。
- Energy Profiler:
- 了解應(yīng)用在不同操作下的電量消耗情況。例如,比較不同功能模塊(如屏幕顯示、后臺(tái)任務(wù)、網(wǎng)絡(luò)連接等)的電量消耗占比,從而確定哪些功能對(duì)電量消耗影響較大。
- 根據(jù)電量消耗情況,優(yōu)化應(yīng)用的行為。例如,減少不必要的后臺(tái)任務(wù)、優(yōu)化屏幕刷新率或者降低傳感器的使用頻率,以降低應(yīng)用的整體電量消耗。
- Network Profiler:
KOOM
-
KOOM(Kwai Open-source OOM)的基本概念
- KOOM是快手開源的一個(gè)用于檢測(cè)Android應(yīng)用內(nèi)存泄漏和內(nèi)存溢出(OOM)的工具。它的主要目的是幫助開發(fā)者更方便、更高效地發(fā)現(xiàn)和定位內(nèi)存相關(guān)的問題,從而提高應(yīng)用的穩(wěn)定性和性能。
- 在Android開發(fā)中,內(nèi)存泄漏是一個(gè)比較常見且棘手的問題。內(nèi)存泄漏指的是程序中已經(jīng)不再使用的對(duì)象卻沒有被垃圾回收機(jī)制回收,導(dǎo)致內(nèi)存占用不斷增加。隨著時(shí)間的推移,可能會(huì)導(dǎo)致應(yīng)用出現(xiàn)OOM,影響用戶體驗(yàn)。KOOM就是為了解決這類問題而誕生的。
-
KOOM的工作原理
- 內(nèi)存快照對(duì)比:KOOM會(huì)定期(例如每隔一段時(shí)間)獲取應(yīng)用的內(nèi)存快照。內(nèi)存快照是當(dāng)前應(yīng)用內(nèi)存中所有對(duì)象的狀態(tài)記錄,包括對(duì)象的類型、引用關(guān)系等信息。通過對(duì)比不同時(shí)間點(diǎn)的內(nèi)存快照,KOOM可以找出那些在一段時(shí)間內(nèi)一直存在且沒有被釋放的對(duì)象,這些對(duì)象很可能是內(nèi)存泄漏的嫌疑對(duì)象。
- 引用鏈分析:對(duì)于疑似內(nèi)存泄漏的對(duì)象,KOOM會(huì)深入分析它們的引用鏈。引用鏈?zhǔn)侵笍母鶎?duì)象(如Activity、Service等系統(tǒng)組件)到疑似泄漏對(duì)象的引用路徑。通過分析引用鏈,KOOM可以確定對(duì)象無法被回收的原因,例如是否存在某個(gè)靜態(tài)變量一直引用著這個(gè)對(duì)象,或者是否在不恰當(dāng)?shù)牡胤匠钟辛藢?duì)象的引用。
- 結(jié)合系統(tǒng)信息分析:KOOM還會(huì)結(jié)合系統(tǒng)的其他信息來輔助分析內(nèi)存問題。比如,它會(huì)考慮應(yīng)用的生命周期狀態(tài)(如Activity的生命周期階段)、系統(tǒng)資源的使用情況(如內(nèi)存壓力、CPU負(fù)載等)。這些信息有助于更準(zhǔn)確地判斷內(nèi)存泄漏是否是由于不合理的代碼邏輯或者系統(tǒng)環(huán)境因素導(dǎo)致的。
-
KOOM的優(yōu)勢(shì)
- 準(zhǔn)確性高:通過詳細(xì)的內(nèi)存快照對(duì)比和引用鏈分析,KOOM能夠比較精準(zhǔn)地定位內(nèi)存泄漏的位置。相比一些傳統(tǒng)的內(nèi)存檢測(cè)工具,它能夠提供更深入、更準(zhǔn)確的分析結(jié)果,幫助開發(fā)者快速找到問題根源。
- 易于集成和使用:KOOM作為一個(gè)開源工具,它的集成方式相對(duì)簡(jiǎn)單。開發(fā)者可以很容易地將KOOM集成到自己的Android項(xiàng)目中,并且它提供了比較友好的接口和文檔。在使用過程中,不需要復(fù)雜的配置和操作,就可以開始檢測(cè)內(nèi)存問題。
- 高效性能:KOOM在檢測(cè)內(nèi)存問題的過程中,對(duì)應(yīng)用性能的影響較小。它采用了一些優(yōu)化策略,如合理的快照獲取頻率、高效的分析算法等,使得在進(jìn)行內(nèi)存檢測(cè)的同時(shí),不會(huì)因?yàn)榇罅康馁Y源占用而導(dǎo)致應(yīng)用卡頓或者性能下降。
-
KOOM的應(yīng)用場(chǎng)景
- 日常開發(fā)中的內(nèi)存問題檢測(cè):在開發(fā)過程中,開發(fā)者可以使用KOOM來實(shí)時(shí)監(jiān)測(cè)應(yīng)用的內(nèi)存情況。例如,當(dāng)開發(fā)一個(gè)新的功能模塊,懷疑可能會(huì)導(dǎo)致內(nèi)存泄漏時(shí),可以開啟KOOM進(jìn)行檢測(cè)。通過KOOM的分析報(bào)告,及時(shí)發(fā)現(xiàn)和解決潛在的內(nèi)存問題,避免將問題遺留到測(cè)試或者上線階段。
- 問題定位與修復(fù):當(dāng)應(yīng)用在測(cè)試或者上線后出現(xiàn)了內(nèi)存相關(guān)的問題(如頻繁的OOM崩潰),KOOM可以作為一個(gè)重要的工具來幫助定位問題。開發(fā)者可以根據(jù)KOOM提供的內(nèi)存泄漏對(duì)象的信息、引用鏈以及相關(guān)的系統(tǒng)環(huán)境分析,快速找到導(dǎo)致內(nèi)存問題的代碼位置,從而進(jìn)行針對(duì)性的修復(fù)。
熟練掌握 OKHttp/Retrofit 等第三方架構(gòu),精通 TCP/IP、HTTP 協(xié)議,在進(jìn)程保活技術(shù)方面具備扎實(shí)的實(shí)踐經(jīng)驗(yàn),有效提升應(yīng)用的穩(wěn)定性與可靠性。
安卓面試 Okhttp源碼解析
- Okhttp的整體架構(gòu)
- 責(zé)任鏈模式的應(yīng)用:Okhttp采用了責(zé)任鏈模式來處理網(wǎng)絡(luò)請(qǐng)求。一個(gè)請(qǐng)求從客戶端發(fā)出后,會(huì)依次經(jīng)過多個(gè)攔截器(Interceptor),每個(gè)攔截器都有自己特定的職責(zé),對(duì)請(qǐng)求進(jìn)行處理或者對(duì)響應(yīng)進(jìn)行加工。例如,在請(qǐng)求發(fā)送前,可能會(huì)經(jīng)過添加請(qǐng)求頭的攔截器,在收到響應(yīng)后,可能會(huì)經(jīng)過解析響應(yīng)數(shù)據(jù)的攔截器。
- 核心組件:主要包括
OkHttpClient
、Request
、Response
、Interceptor
和Call
。OkHttpClient
是整個(gè)網(wǎng)絡(luò)請(qǐng)求的客戶端,用于配置各種網(wǎng)絡(luò)參數(shù),如連接超時(shí)時(shí)間、讀取超時(shí)時(shí)間等。Request
用于構(gòu)建請(qǐng)求對(duì)象,包含請(qǐng)求的方法(如GET、POST)、URL、請(qǐng)求頭和請(qǐng)求體等信息。Response
則是服務(wù)器返回的響應(yīng),包含響應(yīng)狀態(tài)碼、響應(yīng)頭和響應(yīng)體等。Interceptor
是攔截器,負(fù)責(zé)在請(qǐng)求和響應(yīng)過程中進(jìn)行處理。Call
用于執(zhí)行網(wǎng)絡(luò)請(qǐng)求,可以理解為是一個(gè)請(qǐng)求任務(wù)。
- 請(qǐng)求構(gòu)建階段(Request)
- 請(qǐng)求對(duì)象的創(chuàng)建:通過
Request.Builder
來構(gòu)建一個(gè)請(qǐng)求對(duì)象。例如,Request request = new Request.Builder().url("http://example.com").build();
。在構(gòu)建過程中,可以設(shè)置請(qǐng)求的方法、URL、請(qǐng)求頭(如addHeader
方法)和請(qǐng)求體(如果是POST等有請(qǐng)求體的請(qǐng)求,通過post
或put
等方法設(shè)置請(qǐng)求體內(nèi)容)。 - 請(qǐng)求體的處理(如果有):對(duì)于有請(qǐng)求體的請(qǐng)求,Okhttp提供了多種方式來設(shè)置請(qǐng)求體。例如,對(duì)于簡(jiǎn)單的文本內(nèi)容,可以使用
RequestBody.create(MediaType.parse("text/plain"), "請(qǐng)求體內(nèi)容");
來創(chuàng)建請(qǐng)求體。如果是上傳文件,可以使用RequestBody.create(MediaType.parse("application/octet - stream"), file);
,其中file
是要上傳的文件對(duì)象。這些請(qǐng)求體在后續(xù)的請(qǐng)求發(fā)送過程中會(huì)被正確地處理。
- 請(qǐng)求對(duì)象的創(chuàng)建:通過
- 客戶端配置階段(OkHttpClient)
- 基本參數(shù)配置:
OkHttpClient
的創(chuàng)建可以通過OkHttpClient.Builder
來完成??梢栽O(shè)置各種網(wǎng)絡(luò)參數(shù),如connectTimeout
用于設(shè)置連接超時(shí)時(shí)間,readTimeout
用于設(shè)置讀取超時(shí)時(shí)間。例如,OkHttpClient client = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).build();
。 - 攔截器添加:可以向
OkHttpClient
添加攔截器,攔截器會(huì)按照添加的順序組成一個(gè)攔截鏈。例如,client.interceptors().add(new LoggingInterceptor());
,這里LoggingInterceptor
是自定義的一個(gè)攔截器,用于記錄請(qǐng)求和響應(yīng)的日志。攔截器可以用于添加公共的請(qǐng)求頭、進(jìn)行權(quán)限驗(yàn)證、緩存控制等多種用途。
- 基本參數(shù)配置:
- 請(qǐng)求執(zhí)行階段(Call)
- 同步請(qǐng)求執(zhí)行:通過
Call
對(duì)象來執(zhí)行請(qǐng)求。對(duì)于同步請(qǐng)求,可以使用Response response = call.execute();
。在執(zhí)行過程中,請(qǐng)求會(huì)按照攔截鏈的順序依次經(jīng)過各個(gè)攔截器。首先是自定義的攔截器,然后是Okhttp內(nèi)置的攔截器,如重試攔截器(如果配置了重試)、橋接攔截器(用于添加或處理一些必要的請(qǐng)求頭,如Content - Length
)等。 - 異步請(qǐng)求執(zhí)行:對(duì)于異步請(qǐng)求,使用
call.enqueue(new Callback() { // 處理響應(yīng)的回調(diào) });
。異步請(qǐng)求會(huì)在一個(gè)單獨(dú)的線程(通常是線程池中的線程)中執(zhí)行,當(dāng)請(qǐng)求完成后,會(huì)通過回調(diào)函數(shù)來通知結(jié)果。在異步請(qǐng)求執(zhí)行過程中,同樣會(huì)經(jīng)過攔截鏈,并且在回調(diào)函數(shù)中,可以在主線程中處理響應(yīng),以更新UI等操作。
- 同步請(qǐng)求執(zhí)行:通過
- 攔截器工作機(jī)制
- 攔截器鏈的順序和職責(zé):攔截器鏈的順序很重要。在請(qǐng)求階段,攔截器按照添加到
OkHttpClient
的順序依次處理請(qǐng)求。例如,最先添加的攔截器會(huì)第一個(gè)接收到請(qǐng)求,它可以對(duì)請(qǐng)求進(jìn)行修改或者添加信息,然后將請(qǐng)求傳遞給下一個(gè)攔截器。在響應(yīng)階段,攔截器鏈的順序反過來,最后添加的攔截器會(huì)第一個(gè)接收到響應(yīng),然后依次向上傳遞,每個(gè)攔截器可以對(duì)響應(yīng)進(jìn)行處理,如解析數(shù)據(jù)、添加緩存等。 - 內(nèi)置攔截器的功能:Okhttp有一些重要的內(nèi)置攔截器。
- 重試攔截器:如果在請(qǐng)求過程中出現(xiàn)網(wǎng)絡(luò)故障或者可重試的錯(cuò)誤(如服務(wù)器返回503服務(wù)不可用),并且配置了重試,重試攔截器會(huì)嘗試重新發(fā)起請(qǐng)求。
- 橋接攔截器:主要用于在應(yīng)用層的請(qǐng)求和底層的網(wǎng)絡(luò)請(qǐng)求之間進(jìn)行轉(zhuǎn)換。例如,它會(huì)自動(dòng)添加一些必要的請(qǐng)求頭,如
User - Agent
,并且會(huì)處理一些請(qǐng)求體的轉(zhuǎn)換,如將應(yīng)用層的請(qǐng)求體格式轉(zhuǎn)換為適合網(wǎng)絡(luò)傳輸?shù)母袷健?/li> - 緩存攔截器:用于控制緩存。如果配置了緩存,緩存攔截器會(huì)根據(jù)緩存策略(如
Cache - Control
請(qǐng)求頭)來判斷是否使用緩存,以及是否更新緩存。
- 攔截器鏈的順序和職責(zé):攔截器鏈的順序很重要。在請(qǐng)求階段,攔截器按照添加到
Retrofit源碼解析
-
Retrofit的基本架構(gòu)和原理
- 基于接口的設(shè)計(jì)模式:Retrofit是一個(gè)基于Java接口的RESTful API客戶端框架。它的核心設(shè)計(jì)理念是通過定義接口來描述網(wǎng)絡(luò)請(qǐng)求,接口中的方法對(duì)應(yīng)具體的API端點(diǎn)。這種設(shè)計(jì)使得網(wǎng)絡(luò)請(qǐng)求的定義和使用更加清晰、簡(jiǎn)潔,符合面向?qū)ο蟮木幊淘瓌t。
- 動(dòng)態(tài)代理機(jī)制:Retrofit利用動(dòng)態(tài)代理來實(shí)現(xiàn)接口方法與實(shí)際網(wǎng)絡(luò)請(qǐng)求的關(guān)聯(lián)。當(dāng)調(diào)用接口中的方法時(shí),實(shí)際上是通過動(dòng)態(tài)代理攔截這些調(diào)用,并將其轉(zhuǎn)換為網(wǎng)絡(luò)請(qǐng)求。具體來說,Retrofit會(huì)為定義的接口創(chuàng)建一個(gè)代理對(duì)象,這個(gè)代理對(duì)象負(fù)責(zé)處理接口方法的調(diào)用,并根據(jù)方法的定義(如方法名、參數(shù)等)構(gòu)建Okhttp請(qǐng)求。
- 與Okhttp的關(guān)系:Retrofit底層依賴Okhttp來執(zhí)行實(shí)際的網(wǎng)絡(luò)請(qǐng)求。它將接口方法中定義的請(qǐng)求信息(如請(qǐng)求方法、URL、參數(shù)等)轉(zhuǎn)換為Okhttp的
Request
對(duì)象,然后通過Okhttp的Call
機(jī)制來發(fā)送請(qǐng)求并獲取響應(yīng)??梢园裄etrofit看作是對(duì)Okhttp的一個(gè)高級(jí)封裝,使得網(wǎng)絡(luò)請(qǐng)求在更高層次上更易于使用。
-
接口定義與注解解析階段
- 接口方法的定義:開發(fā)者通過定義接口來描述網(wǎng)絡(luò)請(qǐng)求。例如,定義一個(gè)獲取用戶信息的接口方法:
@GET("users/{id}") User getUser(@Path("id") int id);
。在這個(gè)接口方法中,@GET
是一個(gè)Retrofit注解,用于指定請(qǐng)求方法為GET,"users/{id}"
是請(qǐng)求的相對(duì)URL,其中{id}
是一個(gè)路徑參數(shù)。User
是返回值類型,代表期望從服務(wù)器獲取的用戶信息的數(shù)據(jù)結(jié)構(gòu),@Path("id") int id
用于將方法參數(shù)id
綁定到URL中的路徑參數(shù){id}
。 - 注解解析過程:Retrofit會(huì)在初始化階段解析這些接口方法上的注解。它有一套注解處理器,能夠識(shí)別
@GET
、@POST
、@PUT
等請(qǐng)求方法注解,以及@Path
、@Query
、@Body
等參數(shù)相關(guān)的注解。通過解析這些注解,Retrofit可以確定請(qǐng)求的具體細(xì)節(jié),如請(qǐng)求方法、URL模板、參數(shù)如何填充到請(qǐng)求中等信息。例如,對(duì)于@Path
注解,Retrofit會(huì)根據(jù)方法參數(shù)的值替換URL模板中的路徑參數(shù)。
- 接口方法的定義:開發(fā)者通過定義接口來描述網(wǎng)絡(luò)請(qǐng)求。例如,定義一個(gè)獲取用戶信息的接口方法:
-
請(qǐng)求構(gòu)建與轉(zhuǎn)換階段(與Okhttp的協(xié)作)
- 將接口方法轉(zhuǎn)換為Okhttp請(qǐng)求:在解析完接口方法的注解后,Retrofit會(huì)將這些信息轉(zhuǎn)換為Okhttp的
Request
對(duì)象。它會(huì)根據(jù)注解中指定的請(qǐng)求方法(如GET、POST)設(shè)置Request
的方法屬性,根據(jù)解析出的URL模板和參數(shù)填充實(shí)際的請(qǐng)求URL。對(duì)于請(qǐng)求體相關(guān)的信息(如通過@Body
注解指定的請(qǐng)求體),也會(huì)正確地設(shè)置到Request
對(duì)象中。 - 配置Okhttp客戶端:Retrofit允許開發(fā)者配置Okhttp客戶端。可以通過
Retrofit.Builder
來設(shè)置OkHttpClient
,例如,Retrofit retrofit = new Retrofit.Builder().baseUrl("http://example.com").client(okHttpClient).build();
。這個(gè)OkHttpClient
可以預(yù)先配置好各種網(wǎng)絡(luò)參數(shù),如連接超時(shí)時(shí)間、讀取超時(shí)時(shí)間、攔截器等,Retrofit會(huì)使用這個(gè)配置好的客戶端來執(zhí)行網(wǎng)絡(luò)請(qǐng)求。
- 將接口方法轉(zhuǎn)換為Okhttp請(qǐng)求:在解析完接口方法的注解后,Retrofit會(huì)將這些信息轉(zhuǎn)換為Okhttp的
-
異步請(qǐng)求與回調(diào)處理階段
- 異步請(qǐng)求的執(zhí)行:Retrofit支持異步請(qǐng)求,通過接口方法返回的
Call
對(duì)象來執(zhí)行。例如,Call<User> call = apiService.getUser(1); call.enqueue(new Callback<User>() { // 回調(diào)處理 });
。在執(zhí)行異步請(qǐng)求時(shí),Retrofit會(huì)將構(gòu)建好的Okhttp的Call
對(duì)象放入線程池(通常是Okhttp內(nèi)部的線程池)中執(zhí)行。這樣可以避免在主線程中執(zhí)行網(wǎng)絡(luò)請(qǐng)求,防止UI線程阻塞。 - 回調(diào)處理機(jī)制:當(dāng)異步請(qǐng)求完成后,Okhttp會(huì)通過回調(diào)函數(shù)通知Retrofit。Retrofit會(huì)將Okhttp返回的
Response
對(duì)象進(jìn)行處理,根據(jù)接口方法的返回值類型(如User
),將響應(yīng)數(shù)據(jù)解析并轉(zhuǎn)換為對(duì)應(yīng)的對(duì)象。如果請(qǐng)求成功,會(huì)將解析后的對(duì)象傳遞給Callback
的onResponse
方法;如果請(qǐng)求失敗,會(huì)將錯(cuò)誤信息傳遞給onFailure
方法。這個(gè)過程涉及到數(shù)據(jù)的反序列化,Retrofit通常會(huì)根據(jù)接口方法返回值類型和響應(yīng)數(shù)據(jù)的格式(如JSON),使用相應(yīng)的轉(zhuǎn)換器(如GsonConverter)來進(jìn)行數(shù)據(jù)轉(zhuǎn)換。
- 異步請(qǐng)求的執(zhí)行:Retrofit支持異步請(qǐng)求,通過接口方法返回的
TCP/IP的理解
TCP/IP是一組重要的網(wǎng)絡(luò)通信協(xié)議,在安卓開發(fā)中應(yīng)用廣泛,以下是對(duì)它的理解:
TCP/IP協(xié)議棧模型
- 應(yīng)用層:是用戶與網(wǎng)絡(luò)進(jìn)行交互的接口,為應(yīng)用程序提供網(wǎng)絡(luò)服務(wù)。常見的協(xié)議有HTTP、HTTPS、FTP、SMTP等。例如,在安卓應(yīng)用中,使用HTTP協(xié)議進(jìn)行網(wǎng)頁瀏覽、文件下載,使用SMTP協(xié)議發(fā)送郵件等。
- 傳輸層:負(fù)責(zé)在兩臺(tái)主機(jī)之間提供可靠的端到端通信服務(wù)。主要協(xié)議有TCP和UDP。TCP協(xié)議提供可靠的、面向連接的通信服務(wù),通過三次握手建立連接,四次揮手?jǐn)嚅_連接,確保數(shù)據(jù)的可靠傳輸和順序正確性;UDP協(xié)議則是無連接的、不可靠的傳輸協(xié)議,但具有傳輸速度快、開銷小的特點(diǎn),常用于實(shí)時(shí)性要求較高的應(yīng)用,如視頻直播、語音通話等。
- 網(wǎng)絡(luò)層:主要負(fù)責(zé)數(shù)據(jù)包從源到目的地的傳輸和路由選擇,核心協(xié)議是IP協(xié)議,包括IPv4和IPv6。IP協(xié)議為每個(gè)網(wǎng)絡(luò)設(shè)備分配唯一的IP地址,使得數(shù)據(jù)能夠在不同的網(wǎng)絡(luò)之間進(jìn)行路由和轉(zhuǎn)發(fā)。例如,在網(wǎng)絡(luò)訪問時(shí),通過IP地址來確定目標(biāo)服務(wù)器的位置。
- 網(wǎng)絡(luò)接口層:定義了物理設(shè)備如何接入網(wǎng)絡(luò)以及如何在物理媒介上傳輸數(shù)據(jù)比特流,包括各種網(wǎng)絡(luò)接口標(biāo)準(zhǔn)和協(xié)議,如以太網(wǎng)、Wi-Fi等。它負(fù)責(zé)將網(wǎng)絡(luò)層的數(shù)據(jù)包轉(zhuǎn)換為物理信號(hào)在網(wǎng)絡(luò)中傳輸,以及將接收到的物理信號(hào)轉(zhuǎn)換為網(wǎng)絡(luò)層可處理的數(shù)據(jù)包。
TCP/IP的工作原理
- 數(shù)據(jù)封裝與解封:在發(fā)送端,數(shù)據(jù)從應(yīng)用層開始,依次經(jīng)過傳輸層、網(wǎng)絡(luò)層和網(wǎng)絡(luò)接口層進(jìn)行封裝。每一層都會(huì)在數(shù)據(jù)前面添加本層的協(xié)議頭,用于標(biāo)識(shí)該層的相關(guān)信息。在接收端,數(shù)據(jù)則按照相反的順序進(jìn)行解封,每層去除本層的協(xié)議頭,將數(shù)據(jù)交給上一層處理,直到最終到達(dá)應(yīng)用層。
- 路由選擇:網(wǎng)絡(luò)層的IP協(xié)議負(fù)責(zé)根據(jù)目標(biāo)IP地址進(jìn)行路由選擇,決定數(shù)據(jù)從源主機(jī)到目標(biāo)主機(jī)的傳輸路徑。路由器會(huì)根據(jù)路由表中的信息,將數(shù)據(jù)包轉(zhuǎn)發(fā)到下一跳路由器或目標(biāo)主機(jī)所在的網(wǎng)絡(luò)。在安卓設(shè)備中,當(dāng)訪問不同網(wǎng)絡(luò)中的服務(wù)器時(shí),需要通過網(wǎng)絡(luò)中的路由器進(jìn)行路由轉(zhuǎn)發(fā)。
- 差錯(cuò)控制與流量控制:傳輸層的TCP協(xié)議通過序列號(hào)、確認(rèn)號(hào)、校驗(yàn)和等機(jī)制來實(shí)現(xiàn)差錯(cuò)控制,確保數(shù)據(jù)的可靠傳輸。同時(shí),TCP還采用滑動(dòng)窗口機(jī)制進(jìn)行流量控制,根據(jù)接收方的接收能力和網(wǎng)絡(luò)狀況,調(diào)整發(fā)送方的發(fā)送窗口大小,避免發(fā)送方發(fā)送過多數(shù)據(jù)導(dǎo)致接收方無法及時(shí)處理而出現(xiàn)數(shù)據(jù)丟失或擁塞。
TCP/IP在安卓中的應(yīng)用
- 網(wǎng)絡(luò)連接與通信:安卓應(yīng)用通過TCP/IP協(xié)議與服務(wù)器進(jìn)行數(shù)據(jù)交互,實(shí)現(xiàn)各種網(wǎng)絡(luò)功能,如登錄驗(yàn)證、數(shù)據(jù)查詢、文件上傳下載等。開發(fā)者可以使用Java的Socket API或一些網(wǎng)絡(luò)框架(如OkHttp、Retrofit等)來建立TCP連接并進(jìn)行數(shù)據(jù)傳輸。
- HTTP通信:HTTP協(xié)議是基于TCP/IP協(xié)議的應(yīng)用層協(xié)議,安卓應(yīng)用廣泛使用HTTP協(xié)議來獲取網(wǎng)頁內(nèi)容、調(diào)用Web服務(wù)接口等。通過HTTP協(xié)議,安卓應(yīng)用可以向服務(wù)器發(fā)送請(qǐng)求,獲取服務(wù)器返回的HTML頁面、JSON數(shù)據(jù)、圖片等資源。
- 流媒體傳輸:在視頻播放、音頻直播等應(yīng)用中,常常使用基于UDP或TCP的流媒體傳輸協(xié)議。例如,使用RTMP協(xié)議進(jìn)行直播時(shí),底層也是基于TCP/IP協(xié)議進(jìn)行數(shù)據(jù)傳輸,以確保視頻和音頻數(shù)據(jù)的實(shí)時(shí)性和流暢性。
HTTP協(xié)議
-
HTTP的基本概念
- HTTP(超文本傳輸協(xié)議)是一種用于分布式、協(xié)作式和超媒體信息系統(tǒng)的應(yīng)用層協(xié)議。它是互聯(lián)網(wǎng)數(shù)據(jù)通信的基礎(chǔ),主要用于在Web瀏覽器和Web服務(wù)器之間傳輸數(shù)據(jù)。例如,當(dāng)用戶在安卓手機(jī)的瀏覽器中訪問一個(gè)網(wǎng)頁時(shí),瀏覽器和服務(wù)器之間就是通過HTTP協(xié)議來傳輸網(wǎng)頁的文本、圖片、腳本等各種資源。
- HTTP協(xié)議是基于請(qǐng)求 - 響應(yīng)模型的??蛻舳?#xff08;如安卓應(yīng)用中的網(wǎng)絡(luò)請(qǐng)求模塊)發(fā)送一個(gè)請(qǐng)求到服務(wù)器,服務(wù)器接收請(qǐng)求后返回一個(gè)響應(yīng)。請(qǐng)求和響應(yīng)都包含頭部(header)和主體(body)部分。頭部包含了關(guān)于請(qǐng)求或響應(yīng)的各種元信息,如請(qǐng)求方法、響應(yīng)狀態(tài)碼、內(nèi)容類型等;主體則包含了實(shí)際的數(shù)據(jù),如網(wǎng)頁內(nèi)容、文件數(shù)據(jù)等。
-
HTTP請(qǐng)求方法
- GET方法:這是最常用的方法之一。當(dāng)使用GET方法時(shí),客戶端請(qǐng)求服務(wù)器返回指定資源。例如,在安卓應(yīng)用中,通過GET方法請(qǐng)求服務(wù)器獲取一個(gè)用戶列表的JSON數(shù)據(jù),請(qǐng)求的URL通常包含了查詢參數(shù),這些參數(shù)會(huì)附加在URL后面,如
http://example.com/api/users?page=1&limit=10
,其中page
和limit
就是查詢參數(shù)。GET請(qǐng)求的數(shù)據(jù)會(huì)暴露在URL中,并且對(duì)同一資源的多次GET請(qǐng)求應(yīng)該是冪等的,即不會(huì)改變服務(wù)器的狀態(tài)。 - POST方法:用于向服務(wù)器提交數(shù)據(jù),通常用于創(chuàng)建新的資源。例如,當(dāng)用戶在安卓應(yīng)用中注冊(cè)一個(gè)新賬號(hào)時(shí),會(huì)通過POST方法將用戶的注冊(cè)信息(如用戶名、密碼等)發(fā)送到服務(wù)器。POST請(qǐng)求的數(shù)據(jù)包含在請(qǐng)求主體中,相比于GET方法,它更適合用于提交大量的數(shù)據(jù)或者敏感數(shù)據(jù),因?yàn)閿?shù)據(jù)不會(huì)顯示在URL中。
- PUT方法:主要用于更新服務(wù)器上已存在的資源。例如,如果要更新用戶的個(gè)人信息,安卓應(yīng)用可以使用PUT方法將更新后的信息發(fā)送到服務(wù)器。PUT請(qǐng)求也是冪等的,即多次執(zhí)行相同的PUT請(qǐng)求,對(duì)資源的更新效果是相同的。
- DELETE方法:顧名思義,用于刪除服務(wù)器上指定的資源。比如,當(dāng)用戶在安卓應(yīng)用中刪除自己的一條評(píng)論時(shí),可以使用DELETE方法向服務(wù)器發(fā)送請(qǐng)求,服務(wù)器接收到請(qǐng)求后會(huì)刪除對(duì)應(yīng)的評(píng)論資源。
- GET方法:這是最常用的方法之一。當(dāng)使用GET方法時(shí),客戶端請(qǐng)求服務(wù)器返回指定資源。例如,在安卓應(yīng)用中,通過GET方法請(qǐng)求服務(wù)器獲取一個(gè)用戶列表的JSON數(shù)據(jù),請(qǐng)求的URL通常包含了查詢參數(shù),這些參數(shù)會(huì)附加在URL后面,如
-
HTTP狀態(tài)碼
- 1xx(信息性狀態(tài)碼):這類狀態(tài)碼主要用于提供信息,比較少見。例如,
101 Switching Protocols
表示服務(wù)器已經(jīng)理解了客戶端的請(qǐng)求,并將通過升級(jí)協(xié)議來完成這個(gè)請(qǐng)求。 - 2xx(成功狀態(tài)碼):表明客戶端的請(qǐng)求已經(jīng)成功被服務(wù)器接收、理解并處理。最常見的是
200 OK
,表示請(qǐng)求成功,服務(wù)器返回了請(qǐng)求的資源。201 Created
表示請(qǐng)求成功并且服務(wù)器創(chuàng)建了新的資源,通常在POST請(qǐng)求后返回。 - 3xx(重定向狀態(tài)碼):當(dāng)服務(wù)器需要客戶端進(jìn)行進(jìn)一步操作才能完成請(qǐng)求時(shí),會(huì)返回這類狀態(tài)碼。例如,
301 Moved Permanently
表示所請(qǐng)求的資源已經(jīng)永久移動(dòng)到新的位置,客戶端應(yīng)該使用新的URL進(jìn)行訪問;302 Found
表示資源臨時(shí)移動(dòng),客戶端應(yīng)該使用新的URL進(jìn)行臨時(shí)訪問。 - 4xx(客戶端錯(cuò)誤狀態(tài)碼):這類狀態(tài)碼表示客戶端發(fā)送的請(qǐng)求有問題。比如,
400 Bad Request
通常是因?yàn)榭蛻舳税l(fā)送的請(qǐng)求語法錯(cuò)誤或者參數(shù)不合法;401 Unauthorized
表示客戶端沒有提供有效的認(rèn)證信息,無法訪問資源;404 Not Found
表示服務(wù)器無法找到客戶端請(qǐng)求的資源。 - 5xx(服務(wù)器錯(cuò)誤狀態(tài)碼):這意味著服務(wù)器在處理請(qǐng)求時(shí)出現(xiàn)了錯(cuò)誤。例如,
500 Internal Server Error
表示服務(wù)器內(nèi)部出現(xiàn)了錯(cuò)誤,無法完成請(qǐng)求;503 Service Unavailable
表示服務(wù)器暫時(shí)無法提供服務(wù),可能是由于服務(wù)器過載或者維護(hù)等原因。
- 1xx(信息性狀態(tài)碼):這類狀態(tài)碼主要用于提供信息,比較少見。例如,
-
HTTP的發(fā)展歷程(從HTTP/1.0到HTTP/3)
- HTTP/1.0:這是早期的HTTP版本,它的特點(diǎn)是簡(jiǎn)單直接。每次請(qǐng)求 - 響應(yīng)完成后就會(huì)關(guān)閉連接,這種方式在頻繁請(qǐng)求的情況下效率較低。它支持基本的請(qǐng)求方法(如GET、POST)和一些簡(jiǎn)單的頭部信息。
- HTTP/1.1:對(duì)HTTP/1.0進(jìn)行了改進(jìn),引入了持久連接,即一個(gè)TCP連接可以用于多次請(qǐng)求 - 響應(yīng),大大提高了效率。同時(shí),增加了更多的請(qǐng)求方法(如PUT、DELETE)和頭部字段,支持了更復(fù)雜的網(wǎng)絡(luò)應(yīng)用場(chǎng)景。但是,在高并發(fā)場(chǎng)景下,HTTP/1.1仍然存在隊(duì)首阻塞的問題,因?yàn)樗腔陧樞虻恼?qǐng)求 - 響應(yīng)模型。
- HTTP/2:主要的改進(jìn)是采用二進(jìn)制分幀層,將請(qǐng)求和響應(yīng)數(shù)據(jù)分割成更小的幀,這些幀可以交錯(cuò)發(fā)送,避免了隊(duì)首阻塞。并且,它支持頭部壓縮,減少了數(shù)據(jù)傳輸量。HTTP/2還支持服務(wù)器推送,即服務(wù)器可以主動(dòng)向客戶端推送相關(guān)資源,提高了網(wǎng)頁加載速度。
- HTTP/3:它基于QUIC協(xié)議,而不是傳統(tǒng)的TCP協(xié)議。QUIC是一種基于UDP的傳輸協(xié)議,它結(jié)合了UDP的速度優(yōu)勢(shì)和TCP的可靠性特點(diǎn)。HTTP/3通過QUIC協(xié)議進(jìn)一步優(yōu)化了傳輸性能,特別是在移動(dòng)網(wǎng)絡(luò)等不穩(wěn)定的網(wǎng)絡(luò)環(huán)境下,能夠提供更好的用戶體驗(yàn)。
-
HTTP在安卓開發(fā)中的應(yīng)用場(chǎng)景和注意事項(xiàng)
- 應(yīng)用場(chǎng)景:
- 網(wǎng)絡(luò)數(shù)據(jù)獲取:安卓應(yīng)用通過HTTP協(xié)議從服務(wù)器獲取各種數(shù)據(jù),如新聞資訊、用戶信息、商品列表等。這些數(shù)據(jù)通常以JSON或XML格式返回,安卓應(yīng)用會(huì)對(duì)這些數(shù)據(jù)進(jìn)行解析并展示給用戶。
- 文件上傳和下載:用于將安卓設(shè)備上的文件上傳到服務(wù)器,或者從服務(wù)器下載文件到安卓設(shè)備。例如,在云存儲(chǔ)應(yīng)用中,通過HTTP協(xié)議實(shí)現(xiàn)文件的上傳和下載操作。
- 與Web服務(wù)接口交互:如果安卓應(yīng)用需要調(diào)用后端的Web服務(wù)接口,如RESTful API,就需要使用HTTP協(xié)議。通過發(fā)送符合接口規(guī)范的請(qǐng)求,并解析返回的響應(yīng),實(shí)現(xiàn)應(yīng)用的各種功能。
- 注意事項(xiàng):
- 安全性:在HTTP通信中,數(shù)據(jù)是以明文形式傳輸?shù)?#xff0c;容易被竊取或篡改。因此,對(duì)于敏感信息的傳輸,如用戶登錄密碼、支付信息等,應(yīng)該使用HTTPS協(xié)議,它通過SSL/TLS加密來保證數(shù)據(jù)的安全性。
- 性能優(yōu)化:在安卓應(yīng)用中,可以通過一些技術(shù)來優(yōu)化HTTP請(qǐng)求的性能。例如,使用連接池來復(fù)用TCP連接,減少連接建立的時(shí)間;合理設(shè)置請(qǐng)求緩存策略,避免重復(fù)請(qǐng)求相同的數(shù)據(jù);根據(jù)網(wǎng)絡(luò)狀況調(diào)整請(qǐng)求的優(yōu)先級(jí)等。
- 應(yīng)用場(chǎng)景:
HTTPS協(xié)議
-
HTTPS的基本概念
- HTTPS(Hypertext Transfer Protocol Secure)是HTTP的安全版本。它在HTTP協(xié)議的基礎(chǔ)上,通過SSL(Secure Sockets Layer)或TLS(Transport Layer Security)協(xié)議進(jìn)行加密傳輸,確保數(shù)據(jù)在網(wǎng)絡(luò)傳輸過程中的安全性和完整性。在安卓開發(fā)中,當(dāng)涉及用戶隱私數(shù)據(jù)(如登錄信息、支付信息等)的傳輸時(shí),通常會(huì)使用HTTPS協(xié)議。
- 其工作原理是在客戶端和服務(wù)器之間建立一個(gè)安全的加密通道。這個(gè)通道使用公鑰和私鑰對(duì)數(shù)據(jù)進(jìn)行加密和解密,使得數(shù)據(jù)在傳輸過程中不會(huì)被第三方輕易竊取或篡改。例如,當(dāng)用戶在安卓手機(jī)上使用銀行應(yīng)用進(jìn)行轉(zhuǎn)賬操作時(shí),轉(zhuǎn)賬請(qǐng)求和銀行服務(wù)器的響應(yīng)都是通過HTTPS加密通道進(jìn)行傳輸?shù)摹?/li>
-
SSL/TLS協(xié)議基礎(chǔ)
- 加密算法:SSL/TLS使用多種加密算法來確保數(shù)據(jù)安全。包括對(duì)稱加密算法(如AES)和非對(duì)稱加密算法(如RSA、ECDSA)。對(duì)稱加密算法速度快,用于對(duì)大量數(shù)據(jù)進(jìn)行加密和解密;非對(duì)稱加密算法用于在客戶端和服務(wù)器之間交換對(duì)稱加密的密鑰,保證密鑰交換過程的安全性。
- 數(shù)字證書:數(shù)字證書是HTTPS的核心組成部分。服務(wù)器會(huì)向權(quán)威的證書頒發(fā)機(jī)構(gòu)(CA)申請(qǐng)數(shù)字證書,證書包含服務(wù)器的公鑰、服務(wù)器的身份信息(如域名等)以及CA的簽名??蛻舳嗽谂c服務(wù)器建立連接時(shí),會(huì)驗(yàn)證服務(wù)器的數(shù)字證書。如果證書驗(yàn)證通過,客戶端就可以信任服務(wù)器,并使用證書中的公鑰與服務(wù)器進(jìn)行安全的通信。
- 握手過程:SSL/TLS的握手過程是建立安全連接的關(guān)鍵步驟。大致過程如下:
- 客戶端向服務(wù)器發(fā)送一個(gè)“ClientHello”消息,其中包含客戶端支持的SSL/TLS版本、加密算法列表等信息。
- 服務(wù)器收到“ClientHello”后,選擇一個(gè)合適的SSL/TLS版本和加密算法,并發(fā)送“ServerHello”消息給客戶端,同時(shí)將自己的數(shù)字證書發(fā)送給客戶端。
- 客戶端收到服務(wù)器的數(shù)字證書后,會(huì)驗(yàn)證證書的有效性。如果證書有效,客戶端會(huì)生成一個(gè)隨機(jī)的對(duì)稱加密密鑰(稱為“pre - master secret”),并使用服務(wù)器證書中的公鑰進(jìn)行加密,然后發(fā)送給服務(wù)器。
- 服務(wù)器使用自己的私鑰解密收到的“pre - master secret”,得到對(duì)稱加密密鑰。之后,客戶端和服務(wù)器就可以使用這個(gè)對(duì)稱加密密鑰進(jìn)行數(shù)據(jù)的加密和解密,安全地傳輸數(shù)據(jù)。
-
HTTPS在安卓開發(fā)中的應(yīng)用場(chǎng)景
- 用戶認(rèn)證和登錄:當(dāng)用戶在安卓應(yīng)用中登錄賬號(hào)時(shí),通過HTTPS傳輸用戶名和密碼等登錄信息,可以防止這些信息被竊取。例如,社交應(yīng)用、電商應(yīng)用等在用戶登錄過程中都應(yīng)該使用HTTPS協(xié)議。
- 金融交易:對(duì)于金融類安卓應(yīng)用,如銀行轉(zhuǎn)賬、證券交易等,HTTPS是必不可少的。它可以確保資金交易信息的安全,保護(hù)用戶的財(cái)產(chǎn)安全。
- 隱私數(shù)據(jù)傳輸:除了登錄和金融信息外,其他涉及用戶隱私的數(shù)據(jù)(如個(gè)人資料、醫(yī)療信息、位置信息等)的傳輸也應(yīng)該使用HTTPS協(xié)議,以保護(hù)用戶的隱私。
-
安卓中實(shí)現(xiàn)HTTPS通信的要點(diǎn)
- 信任管理:在安卓應(yīng)用中,需要正確地管理服務(wù)器數(shù)字證書的信任。可以通過將服務(wù)器證書的公鑰或整個(gè)證書添加到應(yīng)用的信任存儲(chǔ)中來實(shí)現(xiàn)信任。不過,需要注意的是,如果信任管理不當(dāng),可能會(huì)導(dǎo)致安全漏洞。例如,不能隨意信任自簽名證書,除非是在開發(fā)環(huán)境或經(jīng)過嚴(yán)格安全評(píng)估的內(nèi)部網(wǎng)絡(luò)環(huán)境中。
- 網(wǎng)絡(luò)庫支持:許多安卓網(wǎng)絡(luò)庫(如OkHttp、Retrofit等)都提供了對(duì)HTTPS的支持。這些庫通常會(huì)自動(dòng)處理SSL/TLS握手過程和數(shù)據(jù)加密解密。在使用這些網(wǎng)絡(luò)庫時(shí),開發(fā)者可以通過配置相關(guān)參數(shù)來優(yōu)化HTTPS通信,如設(shè)置SSL/TLS版本、加密算法等。
- 性能考慮:與HTTP相比,HTTPS由于加密解密過程會(huì)帶來一定的性能開銷。在安卓開發(fā)中,可以通過一些方式來優(yōu)化性能。例如,使用硬件加速(如果設(shè)備支持)來加速加密解密過程;合理選擇加密算法,平衡安全性和性能;優(yōu)化網(wǎng)絡(luò)請(qǐng)求,減少不必要的HTTPS請(qǐng)求次數(shù)等。
進(jìn)程?;?/h3>
-
進(jìn)程?;畹谋尘昂椭匾?/strong>
- 在安卓系統(tǒng)中,當(dāng)系統(tǒng)內(nèi)存不足或者用戶長(zhǎng)時(shí)間未使用某個(gè)應(yīng)用時(shí),系統(tǒng)會(huì)回收應(yīng)用進(jìn)程以釋放資源。然而,對(duì)于一些需要持續(xù)在后臺(tái)運(yùn)行的應(yīng)用(如音樂播放應(yīng)用、即時(shí)通訊應(yīng)用的消息推送服務(wù)等),進(jìn)程被回收可能會(huì)導(dǎo)致功能中斷或用戶體驗(yàn)下降。進(jìn)程?;罴夹g(shù)就是為了讓應(yīng)用在系統(tǒng)有回收機(jī)制的情況下,盡可能長(zhǎng)時(shí)間地保持進(jìn)程的存活,以確保應(yīng)用的關(guān)鍵功能能夠持續(xù)運(yùn)行。
-
安卓系統(tǒng)的進(jìn)程回收機(jī)制
- 優(yōu)先級(jí)機(jī)制:安卓系統(tǒng)根據(jù)進(jìn)程的重要性和對(duì)用戶的價(jià)值分配不同的優(yōu)先級(jí)。一般來說,前臺(tái)進(jìn)程(正在與用戶交互的進(jìn)程,如當(dāng)前顯示在屏幕上的Activity所在的進(jìn)程)優(yōu)先級(jí)最高,系統(tǒng)會(huì)盡量避免回收;其次是可見進(jìn)程(如包含一個(gè)用戶可見但不可交互的Activity的進(jìn)程);然后是服務(wù)進(jìn)程(包含正在運(yùn)行服務(wù)的進(jìn)程);接著是后臺(tái)進(jìn)程(包含不可見Activity的進(jìn)程);最后是空進(jìn)程(沒有任何活躍組件的進(jìn)程),優(yōu)先級(jí)最低,最容易被回收。
- 內(nèi)存不足時(shí)的回收:當(dāng)系統(tǒng)內(nèi)存緊張時(shí),系統(tǒng)會(huì)按照優(yōu)先級(jí)從低到高的順序回收進(jìn)程。例如,如果內(nèi)存不足,系統(tǒng)可能會(huì)先回收空進(jìn)程和后臺(tái)進(jìn)程,以釋放內(nèi)存來維持系統(tǒng)的正常運(yùn)行和前臺(tái)應(yīng)用的流暢性。
-
常見的進(jìn)程?;罘椒霸?/strong>
- 利用前臺(tái)服務(wù)(Foreground Service):
- 原理:將服務(wù)設(shè)置為前臺(tái)服務(wù),會(huì)在系統(tǒng)的通知欄創(chuàng)建一個(gè)持續(xù)存在的通知。這樣可以提升服務(wù)所在進(jìn)程的優(yōu)先級(jí),使其不容易被系統(tǒng)回收。因?yàn)榍芭_(tái)服務(wù)被系統(tǒng)視為對(duì)用戶有直接價(jià)值的服務(wù),類似于前臺(tái)應(yīng)用。
- 實(shí)現(xiàn)方式:在服務(wù)的
onCreate
方法中調(diào)用startForeground()
方法。例如,Notification notification = new Notification.Builder(this).build(); startForeground(1, notification);
,這里的1
是一個(gè)唯一的通知標(biāo)識(shí),notification
是一個(gè)簡(jiǎn)單的通知對(duì)象。這樣就將服務(wù)提升到了前臺(tái)狀態(tài),增加了進(jìn)程保活的能力。
- 多進(jìn)程守護(hù):
- 原理:通過創(chuàng)建多個(gè)相互關(guān)聯(lián)的進(jìn)程,讓它們之間相互監(jiān)控。當(dāng)一個(gè)進(jìn)程被系統(tǒng)回收時(shí),其他進(jìn)程可以嘗試重新啟動(dòng)被回收的進(jìn)程。這種方法類似于互相“拉一把”,以維持應(yīng)用的關(guān)鍵進(jìn)程的存活。
- 實(shí)現(xiàn)方式:在安卓應(yīng)用的
AndroidManifest.xml
文件中,通過android:process
屬性為不同的組件(如服務(wù)或Activity)指定不同的進(jìn)程名,從而創(chuàng)建多個(gè)進(jìn)程。例如,<service android:name=".MyService" android:process=":my_service_process"/>
,然后在代碼中實(shí)現(xiàn)進(jìn)程間的通信和監(jiān)控機(jī)制,當(dāng)發(fā)現(xiàn)某個(gè)進(jìn)程消失時(shí),通過am
命令(在安卓系統(tǒng)中用于啟動(dòng)組件的命令)或其他方式重新啟動(dòng)該進(jìn)程。
- 與系統(tǒng)服務(wù)綁定(如JobScheduler、WorkManager):
- 原理:安卓系統(tǒng)提供了一些系統(tǒng)服務(wù)來管理后臺(tái)任務(wù),如JobScheduler和WorkManager。通過將應(yīng)用的后臺(tái)任務(wù)與這些系統(tǒng)服務(wù)綁定,可以讓系統(tǒng)更合理地安排任務(wù)的執(zhí)行,并且在一定程度上提高進(jìn)程的存活幾率。因?yàn)檫@些系統(tǒng)服務(wù)會(huì)根據(jù)系統(tǒng)的資源狀況和任務(wù)的優(yōu)先級(jí)來調(diào)度任務(wù),避免因?yàn)橄到y(tǒng)資源緊張而被隨意回收。
- 實(shí)現(xiàn)方式:使用JobScheduler時(shí),首先創(chuàng)建一個(gè)
JobService
的子類,在其中實(shí)現(xiàn)onStartJob
和onStopJob
方法來定義任務(wù)的開始和停止邏輯。然后通過JobScheduler
的實(shí)例來調(diào)度任務(wù),例如,JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(this, MyJobService.class)).build(); jobScheduler.schedule(jobInfo);
。對(duì)于WorkManager,使用方式類似,通過定義Worker
類和相關(guān)的任務(wù)配置來將任務(wù)交給WorkManager進(jìn)行調(diào)度。
-
進(jìn)程?;畹娘L(fēng)險(xiǎn)和注意事項(xiàng)
- 系統(tǒng)資源占用和性能影響:過度的進(jìn)程?;畲胧┛赡軙?huì)占用過多的系統(tǒng)資源,如內(nèi)存、CPU等。例如,使用多進(jìn)程守護(hù)方法時(shí),如果多個(gè)進(jìn)程不斷地相互監(jiān)控和重啟,可能會(huì)導(dǎo)致系統(tǒng)資源的浪費(fèi),甚至影響系統(tǒng)的整體性能和其他應(yīng)用的正常運(yùn)行。
- 兼容性和系統(tǒng)更新問題:安卓系統(tǒng)在不斷更新,其進(jìn)程管理策略也可能會(huì)發(fā)生變化。某些進(jìn)程?;罘椒赡茉谂f版本系統(tǒng)中有效,但在新版本系統(tǒng)中由于系統(tǒng)機(jī)制的改變而失效,甚至可能會(huì)被系統(tǒng)視為異常行為而受到限制。例如,一些利用系統(tǒng)漏洞進(jìn)行進(jìn)程?;畹姆椒?#xff0c;在系統(tǒng)安全更新后可能會(huì)被禁止。
- 用戶體驗(yàn)和隱私問題:如果應(yīng)用不合理地保活進(jìn)程,可能會(huì)導(dǎo)致用戶電量消耗過快、流量消耗增加等問題,影響用戶體驗(yàn)。而且,一些?;罘椒赡苌婕暗綄?duì)用戶隱私數(shù)據(jù)的不當(dāng)獲取或使用,如為了實(shí)現(xiàn)進(jìn)程間的監(jiān)控而收集過多用戶信息,這可能會(huì)引發(fā)隱私風(fēng)險(xiǎn)。
如何提升應(yīng)用的穩(wěn)定性和可靠性
-
代碼質(zhì)量?jī)?yōu)化
- 遵循編碼規(guī)范:
- 嚴(yán)格遵循Android官方的編碼規(guī)范以及團(tuán)隊(duì)內(nèi)部既定的規(guī)范。例如,采用合適的命名規(guī)則,使代碼的可讀性增強(qiáng)。變量名和方法名應(yīng)該能夠清晰地反映其用途,這樣在后續(xù)的維護(hù)和問題排查中能夠快速理解代碼意圖。
- 合理使用代碼縮進(jìn)和空格,讓代碼結(jié)構(gòu)更加清晰。對(duì)于復(fù)雜的邏輯判斷和循環(huán)結(jié)構(gòu),適當(dāng)添加注釋來解釋代碼的功能和目的。
- 異常處理機(jī)制:
- 在代碼中合理地使用try - catch塊來捕獲可能出現(xiàn)的異常。例如,在進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),使用
try { // 網(wǎng)絡(luò)請(qǐng)求操作 } catch (IOException e) { // 處理網(wǎng)絡(luò)異常,如顯示錯(cuò)誤提示給用戶 }
。對(duì)于數(shù)據(jù)庫操作,也應(yīng)該在可能出現(xiàn)錯(cuò)誤的地方(如插入、查詢數(shù)據(jù))添加異常捕獲代碼,防止因?yàn)橐粋€(gè)小的異常導(dǎo)致整個(gè)應(yīng)用崩潰。 - 可以設(shè)置全局的未捕獲異常處理器(
UncaughtExceptionHandler
),在Application
類中通過Thread.setDefaultUncaughtExceptionHandler()
方法來設(shè)置。當(dāng)應(yīng)用中出現(xiàn)未被捕獲的異常時(shí),這個(gè)處理器可以記錄異常信息,如將異常堆棧信息保存到本地文件或者上傳到服務(wù)器,以便開發(fā)者分析問題。
-
內(nèi)存管理優(yōu)化
- 避免內(nèi)存泄漏:
- 檢查Activity、Fragment等組件的生命周期,確保在組件銷毀時(shí),釋放與之相關(guān)的資源。例如,在Activity的
onDestroy
方法中,取消注冊(cè)廣播接收器、關(guān)閉數(shù)據(jù)庫連接、釋放圖片加載庫中與該Activity相關(guān)的資源等。 - 注意靜態(tài)變量的使用,避免因?yàn)殪o態(tài)變量持有對(duì)象引用導(dǎo)致對(duì)象無法被垃圾回收。比如,如果一個(gè)靜態(tài)變量持有一個(gè)Activity的引用,那么這個(gè)Activity在理論上應(yīng)該被銷毀時(shí)也無法被回收,從而導(dǎo)致內(nèi)存泄漏。
- 優(yōu)化內(nèi)存占用:
- 對(duì)于圖片等資源,采用合適的壓縮和緩存策略。例如,使用圖片加載庫(如Glide),它可以根據(jù)設(shè)備的屏幕分辨率和內(nèi)存狀況自動(dòng)對(duì)圖片進(jìn)行壓縮,并且提供了內(nèi)存緩存和磁盤緩存機(jī)制,減少圖片的重復(fù)加載,降低內(nèi)存占用。
- 合理控制對(duì)象的創(chuàng)建數(shù)量,避免頻繁地創(chuàng)建和銷毀大量的短期對(duì)象,這可能會(huì)導(dǎo)致內(nèi)存抖動(dòng)。在需要頻繁創(chuàng)建對(duì)象的場(chǎng)景下,可以考慮使用對(duì)象池技術(shù),將已經(jīng)創(chuàng)建的對(duì)象進(jìn)行復(fù)用。
-
性能優(yōu)化
- 啟動(dòng)速度優(yōu)化:
- 冷啟動(dòng)時(shí),精簡(jiǎn)
Application
類的onCreate
方法中的初始化操作。可以將非關(guān)鍵的初始化(如某些第三方庫的初始化)推遲到真正需要使用的時(shí)候。對(duì)于Activity的啟動(dòng),優(yōu)化布局文件,減少布局的嵌套層次,提高布局加載速度。 - 熱啟動(dòng)時(shí),及時(shí)清理在后臺(tái)占用資源的任務(wù),確保應(yīng)用能夠快速恢復(fù)到前臺(tái)可交互狀態(tài)。例如,暫停不必要的網(wǎng)絡(luò)請(qǐng)求、釋放一些內(nèi)存緩存等。
- 響應(yīng)性能優(yōu)化:
- 在主線程中避免執(zhí)行耗時(shí)操作,如網(wǎng)絡(luò)請(qǐng)求、復(fù)雜的計(jì)算等。將這些耗時(shí)操作放到子線程(如使用
AsyncTask
、HandlerThread
或線程池)中執(zhí)行。例如,在處理用戶點(diǎn)擊按鈕觸發(fā)的網(wǎng)絡(luò)請(qǐng)求時(shí),應(yīng)該在子線程中進(jìn)行,當(dāng)網(wǎng)絡(luò)請(qǐng)求完成后,通過Handler
將結(jié)果發(fā)送回主線程更新UI。 - 優(yōu)化數(shù)據(jù)庫查詢操作,合理設(shè)計(jì)數(shù)據(jù)庫表結(jié)構(gòu)和查詢語句,使用索引來提高查詢速度。對(duì)于復(fù)雜的業(yè)務(wù)邏輯,盡量采用高效的算法和數(shù)據(jù)結(jié)構(gòu),減少處理時(shí)間。
-
測(cè)試與質(zhì)量保證
- 單元測(cè)試:
- 對(duì)應(yīng)用中的各個(gè)功能模塊進(jìn)行單元測(cè)試,使用測(cè)試框架(如JUnit)來編寫測(cè)試用例。例如,對(duì)于一個(gè)工具類中的方法,通過編寫多個(gè)測(cè)試用例來驗(yàn)證其在不同輸入情況下的輸出是否正確。單元測(cè)試可以幫助發(fā)現(xiàn)代碼中的邏輯錯(cuò)誤,并且在代碼修改后能夠快速驗(yàn)證是否引入了新的問題。
- 對(duì)于涉及到界面的模塊,可以使用Espresso等測(cè)試框架進(jìn)行UI單元測(cè)試。它可以模擬用戶的操作,如點(diǎn)擊按鈕、輸入文本等,來測(cè)試界面的響應(yīng)是否正確。
- 集成測(cè)試和系統(tǒng)測(cè)試:
- 進(jìn)行集成測(cè)試,確保不同模塊之間的接口和交互是正確的。例如,當(dāng)一個(gè)Activity需要調(diào)用一個(gè)Service來獲取數(shù)據(jù)時(shí),通過集成測(cè)試來驗(yàn)證這個(gè)調(diào)用過程以及數(shù)據(jù)的傳遞是否正常。
- 系統(tǒng)測(cè)試則是從用戶的角度出發(fā),對(duì)整個(gè)應(yīng)用進(jìn)行全面的測(cè)試。包括功能測(cè)試、性能測(cè)試、兼容性測(cè)試等。在不同的設(shè)備型號(hào)、屏幕尺寸、安卓系統(tǒng)版本下進(jìn)行測(cè)試,確保應(yīng)用在各種情況下都能夠穩(wěn)定運(yùn)行。
-
依賴管理與更新策略
- 依賴庫管理:
- 謹(jǐn)慎選擇第三方依賴庫,確保其質(zhì)量和穩(wěn)定性。在引入新的依賴庫之前,對(duì)其進(jìn)行充分的調(diào)研,查看其在社區(qū)中的口碑、更新頻率和維護(hù)情況。例如,如果一個(gè)依賴庫存在很多未解決的問題或者長(zhǎng)時(shí)間沒有更新,可能會(huì)給應(yīng)用帶來潛在的風(fēng)險(xiǎn)。
- 定期更新依賴庫,以獲取最新的功能和安全補(bǔ)丁。但在更新時(shí),需要進(jìn)行充分的測(cè)試,確保新的依賴庫版本不會(huì)與應(yīng)用中的現(xiàn)有代碼產(chǎn)生沖突或者引入新的問題。
- 應(yīng)用自身更新策略:
- 建立合理的應(yīng)用更新機(jī)制,當(dāng)發(fā)現(xiàn)應(yīng)用中存在穩(wěn)定性或可靠性問題時(shí),及時(shí)發(fā)布更新版本??梢酝ㄟ^在應(yīng)用中設(shè)置自動(dòng)更新功能(在用戶同意的情況下),或者提示用戶進(jìn)行更新,以確保用戶能夠使用到修復(fù)后的版本。
- 在更新內(nèi)容方面,除了解決已知的問題,還可以對(duì)應(yīng)用的性能和穩(wěn)定性進(jìn)行持續(xù)優(yōu)化,如優(yōu)化代碼結(jié)構(gòu)、更新數(shù)據(jù)庫模式等。
熟練掌握 Gradle 插件功能開發(fā),具備開發(fā)高質(zhì)量插件工具的能力,顯著提高項(xiàng)目構(gòu)建與開發(fā)效率。
android studio gradle插件開發(fā)流程
-
環(huán)境搭建與準(zhǔn)備
- 安裝必要軟件:確保已經(jīng)安裝了Android Studio和Java Development Kit(JDK)。Gradle插件開發(fā)需要JDK來編譯代碼,Android Studio提供了開發(fā)和調(diào)試插件的集成環(huán)境。一般建議使用較新版本的JDK(如JDK 8或更高版本),因?yàn)椴煌腉radle版本對(duì)JDK版本有一定要求。
- 了解Gradle基礎(chǔ)知識(shí):在開發(fā)Gradle插件之前,需要熟悉Gradle的基本概念,如項(xiàng)目結(jié)構(gòu)、構(gòu)建腳本(
build.gradle
)、任務(wù)(Task)、依賴管理等。例如,知道如何在build.gradle
文件中配置項(xiàng)目的依賴關(guān)系,以及Gradle任務(wù)是如何定義和執(zhí)行的。 - 創(chuàng)建插件項(xiàng)目:在Android Studio中,可以通過新建一個(gè)Java或Groovy項(xiàng)目來開始Gradle插件開發(fā)。如果使用Java開發(fā),需要確保項(xiàng)目的構(gòu)建路徑中包含Gradle API的依賴。如果使用Groovy,由于Gradle本身就是基于Groovy語言構(gòu)建的,開發(fā)起來會(huì)更加方便,它可以更自然地與Gradle的腳本語言相融合。
-
定義插件接口和功能
- 確定插件功能目標(biāo):明確插件要實(shí)現(xiàn)的功能,例如,插件是用于自動(dòng)生成代碼、管理資源文件、還是進(jìn)行依賴版本控制等。以一個(gè)自動(dòng)生成代碼的插件為例,它可能需要讀取項(xiàng)目中的某些配置文件,根據(jù)配置信息生成特定的Java或Kotlin代碼。
- 設(shè)計(jì)插件接口(如果需要):對(duì)于一些復(fù)雜的插件,可能需要設(shè)計(jì)接口來方便其他開發(fā)者擴(kuò)展或與插件進(jìn)行交互。例如,一個(gè)用于處理項(xiàng)目打包的插件,可以設(shè)計(jì)一個(gè)接口,讓其他開發(fā)者能夠自定義打包過程中的某些步驟,如添加自定義的文件到APK包中。
- 學(xué)習(xí)Gradle API相關(guān)知識(shí):根據(jù)插件的功能目標(biāo),學(xué)習(xí)Gradle API中與之相關(guān)的部分。例如,如果要?jiǎng)?chuàng)建一個(gè)新的Gradle任務(wù),需要了解
org.gradle.api.Task
接口和相關(guān)的創(chuàng)建方法;如果要處理項(xiàng)目的依賴關(guān)系,需要熟悉org.gradle.api.artifacts
包中的相關(guān)類和方法。
-
插件開發(fā)實(shí)現(xiàn)階段
- 編寫插件代碼(以Groovy為例):
- 定義插件類,插件類需要實(shí)現(xiàn)
org.gradle.api.Plugin
接口。例如:
import org.gradle.api.Plugin
import org.gradle.api.Projectclass MyPlugin implements Plugin<Project> {@Overridevoid apply(Project project) {// 在這里添加插件的具體功能代碼project.task('myTask') {doLast {println "My custom task is executed."}}}
}
進(jìn)程?;畹谋尘昂椭匾?/strong>
- 在安卓系統(tǒng)中,當(dāng)系統(tǒng)內(nèi)存不足或者用戶長(zhǎng)時(shí)間未使用某個(gè)應(yīng)用時(shí),系統(tǒng)會(huì)回收應(yīng)用進(jìn)程以釋放資源。然而,對(duì)于一些需要持續(xù)在后臺(tái)運(yùn)行的應(yīng)用(如音樂播放應(yīng)用、即時(shí)通訊應(yīng)用的消息推送服務(wù)等),進(jìn)程被回收可能會(huì)導(dǎo)致功能中斷或用戶體驗(yàn)下降。進(jìn)程?;罴夹g(shù)就是為了讓應(yīng)用在系統(tǒng)有回收機(jī)制的情況下,盡可能長(zhǎng)時(shí)間地保持進(jìn)程的存活,以確保應(yīng)用的關(guān)鍵功能能夠持續(xù)運(yùn)行。
安卓系統(tǒng)的進(jìn)程回收機(jī)制
- 優(yōu)先級(jí)機(jī)制:安卓系統(tǒng)根據(jù)進(jìn)程的重要性和對(duì)用戶的價(jià)值分配不同的優(yōu)先級(jí)。一般來說,前臺(tái)進(jìn)程(正在與用戶交互的進(jìn)程,如當(dāng)前顯示在屏幕上的Activity所在的進(jìn)程)優(yōu)先級(jí)最高,系統(tǒng)會(huì)盡量避免回收;其次是可見進(jìn)程(如包含一個(gè)用戶可見但不可交互的Activity的進(jìn)程);然后是服務(wù)進(jìn)程(包含正在運(yùn)行服務(wù)的進(jìn)程);接著是后臺(tái)進(jìn)程(包含不可見Activity的進(jìn)程);最后是空進(jìn)程(沒有任何活躍組件的進(jìn)程),優(yōu)先級(jí)最低,最容易被回收。
- 內(nèi)存不足時(shí)的回收:當(dāng)系統(tǒng)內(nèi)存緊張時(shí),系統(tǒng)會(huì)按照優(yōu)先級(jí)從低到高的順序回收進(jìn)程。例如,如果內(nèi)存不足,系統(tǒng)可能會(huì)先回收空進(jìn)程和后臺(tái)進(jìn)程,以釋放內(nèi)存來維持系統(tǒng)的正常運(yùn)行和前臺(tái)應(yīng)用的流暢性。
常見的進(jìn)程?;罘椒霸?/strong>
- 利用前臺(tái)服務(wù)(Foreground Service):
- 原理:將服務(wù)設(shè)置為前臺(tái)服務(wù),會(huì)在系統(tǒng)的通知欄創(chuàng)建一個(gè)持續(xù)存在的通知。這樣可以提升服務(wù)所在進(jìn)程的優(yōu)先級(jí),使其不容易被系統(tǒng)回收。因?yàn)榍芭_(tái)服務(wù)被系統(tǒng)視為對(duì)用戶有直接價(jià)值的服務(wù),類似于前臺(tái)應(yīng)用。
- 實(shí)現(xiàn)方式:在服務(wù)的
onCreate
方法中調(diào)用startForeground()
方法。例如,Notification notification = new Notification.Builder(this).build(); startForeground(1, notification);
,這里的1
是一個(gè)唯一的通知標(biāo)識(shí),notification
是一個(gè)簡(jiǎn)單的通知對(duì)象。這樣就將服務(wù)提升到了前臺(tái)狀態(tài),增加了進(jìn)程保活的能力。
- 多進(jìn)程守護(hù):
- 原理:通過創(chuàng)建多個(gè)相互關(guān)聯(lián)的進(jìn)程,讓它們之間相互監(jiān)控。當(dāng)一個(gè)進(jìn)程被系統(tǒng)回收時(shí),其他進(jìn)程可以嘗試重新啟動(dòng)被回收的進(jìn)程。這種方法類似于互相“拉一把”,以維持應(yīng)用的關(guān)鍵進(jìn)程的存活。
- 實(shí)現(xiàn)方式:在安卓應(yīng)用的
AndroidManifest.xml
文件中,通過android:process
屬性為不同的組件(如服務(wù)或Activity)指定不同的進(jìn)程名,從而創(chuàng)建多個(gè)進(jìn)程。例如,<service android:name=".MyService" android:process=":my_service_process"/>
,然后在代碼中實(shí)現(xiàn)進(jìn)程間的通信和監(jiān)控機(jī)制,當(dāng)發(fā)現(xiàn)某個(gè)進(jìn)程消失時(shí),通過am
命令(在安卓系統(tǒng)中用于啟動(dòng)組件的命令)或其他方式重新啟動(dòng)該進(jìn)程。
- 與系統(tǒng)服務(wù)綁定(如JobScheduler、WorkManager):
- 原理:安卓系統(tǒng)提供了一些系統(tǒng)服務(wù)來管理后臺(tái)任務(wù),如JobScheduler和WorkManager。通過將應(yīng)用的后臺(tái)任務(wù)與這些系統(tǒng)服務(wù)綁定,可以讓系統(tǒng)更合理地安排任務(wù)的執(zhí)行,并且在一定程度上提高進(jìn)程的存活幾率。因?yàn)檫@些系統(tǒng)服務(wù)會(huì)根據(jù)系統(tǒng)的資源狀況和任務(wù)的優(yōu)先級(jí)來調(diào)度任務(wù),避免因?yàn)橄到y(tǒng)資源緊張而被隨意回收。
- 實(shí)現(xiàn)方式:使用JobScheduler時(shí),首先創(chuàng)建一個(gè)
JobService
的子類,在其中實(shí)現(xiàn)onStartJob
和onStopJob
方法來定義任務(wù)的開始和停止邏輯。然后通過JobScheduler
的實(shí)例來調(diào)度任務(wù),例如,JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(this, MyJobService.class)).build(); jobScheduler.schedule(jobInfo);
。對(duì)于WorkManager,使用方式類似,通過定義Worker
類和相關(guān)的任務(wù)配置來將任務(wù)交給WorkManager進(jìn)行調(diào)度。
進(jìn)程?;畹娘L(fēng)險(xiǎn)和注意事項(xiàng)
- 系統(tǒng)資源占用和性能影響:過度的進(jìn)程?;畲胧┛赡軙?huì)占用過多的系統(tǒng)資源,如內(nèi)存、CPU等。例如,使用多進(jìn)程守護(hù)方法時(shí),如果多個(gè)進(jìn)程不斷地相互監(jiān)控和重啟,可能會(huì)導(dǎo)致系統(tǒng)資源的浪費(fèi),甚至影響系統(tǒng)的整體性能和其他應(yīng)用的正常運(yùn)行。
- 兼容性和系統(tǒng)更新問題:安卓系統(tǒng)在不斷更新,其進(jìn)程管理策略也可能會(huì)發(fā)生變化。某些進(jìn)程?;罘椒赡茉谂f版本系統(tǒng)中有效,但在新版本系統(tǒng)中由于系統(tǒng)機(jī)制的改變而失效,甚至可能會(huì)被系統(tǒng)視為異常行為而受到限制。例如,一些利用系統(tǒng)漏洞進(jìn)行進(jìn)程?;畹姆椒?#xff0c;在系統(tǒng)安全更新后可能會(huì)被禁止。
- 用戶體驗(yàn)和隱私問題:如果應(yīng)用不合理地保活進(jìn)程,可能會(huì)導(dǎo)致用戶電量消耗過快、流量消耗增加等問題,影響用戶體驗(yàn)。而且,一些?;罘椒赡苌婕暗綄?duì)用戶隱私數(shù)據(jù)的不當(dāng)獲取或使用,如為了實(shí)現(xiàn)進(jìn)程間的監(jiān)控而收集過多用戶信息,這可能會(huì)引發(fā)隱私風(fēng)險(xiǎn)。
代碼質(zhì)量?jī)?yōu)化
- 遵循編碼規(guī)范:
- 嚴(yán)格遵循Android官方的編碼規(guī)范以及團(tuán)隊(duì)內(nèi)部既定的規(guī)范。例如,采用合適的命名規(guī)則,使代碼的可讀性增強(qiáng)。變量名和方法名應(yīng)該能夠清晰地反映其用途,這樣在后續(xù)的維護(hù)和問題排查中能夠快速理解代碼意圖。
- 合理使用代碼縮進(jìn)和空格,讓代碼結(jié)構(gòu)更加清晰。對(duì)于復(fù)雜的邏輯判斷和循環(huán)結(jié)構(gòu),適當(dāng)添加注釋來解釋代碼的功能和目的。
- 異常處理機(jī)制:
- 在代碼中合理地使用try - catch塊來捕獲可能出現(xiàn)的異常。例如,在進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),使用
try { // 網(wǎng)絡(luò)請(qǐng)求操作 } catch (IOException e) { // 處理網(wǎng)絡(luò)異常,如顯示錯(cuò)誤提示給用戶 }
。對(duì)于數(shù)據(jù)庫操作,也應(yīng)該在可能出現(xiàn)錯(cuò)誤的地方(如插入、查詢數(shù)據(jù))添加異常捕獲代碼,防止因?yàn)橐粋€(gè)小的異常導(dǎo)致整個(gè)應(yīng)用崩潰。 - 可以設(shè)置全局的未捕獲異常處理器(
UncaughtExceptionHandler
),在Application
類中通過Thread.setDefaultUncaughtExceptionHandler()
方法來設(shè)置。當(dāng)應(yīng)用中出現(xiàn)未被捕獲的異常時(shí),這個(gè)處理器可以記錄異常信息,如將異常堆棧信息保存到本地文件或者上傳到服務(wù)器,以便開發(fā)者分析問題。
- 在代碼中合理地使用try - catch塊來捕獲可能出現(xiàn)的異常。例如,在進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),使用
內(nèi)存管理優(yōu)化
- 避免內(nèi)存泄漏:
- 檢查Activity、Fragment等組件的生命周期,確保在組件銷毀時(shí),釋放與之相關(guān)的資源。例如,在Activity的
onDestroy
方法中,取消注冊(cè)廣播接收器、關(guān)閉數(shù)據(jù)庫連接、釋放圖片加載庫中與該Activity相關(guān)的資源等。 - 注意靜態(tài)變量的使用,避免因?yàn)殪o態(tài)變量持有對(duì)象引用導(dǎo)致對(duì)象無法被垃圾回收。比如,如果一個(gè)靜態(tài)變量持有一個(gè)Activity的引用,那么這個(gè)Activity在理論上應(yīng)該被銷毀時(shí)也無法被回收,從而導(dǎo)致內(nèi)存泄漏。
- 檢查Activity、Fragment等組件的生命周期,確保在組件銷毀時(shí),釋放與之相關(guān)的資源。例如,在Activity的
- 優(yōu)化內(nèi)存占用:
- 對(duì)于圖片等資源,采用合適的壓縮和緩存策略。例如,使用圖片加載庫(如Glide),它可以根據(jù)設(shè)備的屏幕分辨率和內(nèi)存狀況自動(dòng)對(duì)圖片進(jìn)行壓縮,并且提供了內(nèi)存緩存和磁盤緩存機(jī)制,減少圖片的重復(fù)加載,降低內(nèi)存占用。
- 合理控制對(duì)象的創(chuàng)建數(shù)量,避免頻繁地創(chuàng)建和銷毀大量的短期對(duì)象,這可能會(huì)導(dǎo)致內(nèi)存抖動(dòng)。在需要頻繁創(chuàng)建對(duì)象的場(chǎng)景下,可以考慮使用對(duì)象池技術(shù),將已經(jīng)創(chuàng)建的對(duì)象進(jìn)行復(fù)用。
性能優(yōu)化
- 啟動(dòng)速度優(yōu)化:
- 冷啟動(dòng)時(shí),精簡(jiǎn)
Application
類的onCreate
方法中的初始化操作。可以將非關(guān)鍵的初始化(如某些第三方庫的初始化)推遲到真正需要使用的時(shí)候。對(duì)于Activity的啟動(dòng),優(yōu)化布局文件,減少布局的嵌套層次,提高布局加載速度。 - 熱啟動(dòng)時(shí),及時(shí)清理在后臺(tái)占用資源的任務(wù),確保應(yīng)用能夠快速恢復(fù)到前臺(tái)可交互狀態(tài)。例如,暫停不必要的網(wǎng)絡(luò)請(qǐng)求、釋放一些內(nèi)存緩存等。
- 冷啟動(dòng)時(shí),精簡(jiǎn)
- 響應(yīng)性能優(yōu)化:
- 在主線程中避免執(zhí)行耗時(shí)操作,如網(wǎng)絡(luò)請(qǐng)求、復(fù)雜的計(jì)算等。將這些耗時(shí)操作放到子線程(如使用
AsyncTask
、HandlerThread
或線程池)中執(zhí)行。例如,在處理用戶點(diǎn)擊按鈕觸發(fā)的網(wǎng)絡(luò)請(qǐng)求時(shí),應(yīng)該在子線程中進(jìn)行,當(dāng)網(wǎng)絡(luò)請(qǐng)求完成后,通過Handler
將結(jié)果發(fā)送回主線程更新UI。 - 優(yōu)化數(shù)據(jù)庫查詢操作,合理設(shè)計(jì)數(shù)據(jù)庫表結(jié)構(gòu)和查詢語句,使用索引來提高查詢速度。對(duì)于復(fù)雜的業(yè)務(wù)邏輯,盡量采用高效的算法和數(shù)據(jù)結(jié)構(gòu),減少處理時(shí)間。
- 在主線程中避免執(zhí)行耗時(shí)操作,如網(wǎng)絡(luò)請(qǐng)求、復(fù)雜的計(jì)算等。將這些耗時(shí)操作放到子線程(如使用
測(cè)試與質(zhì)量保證
- 單元測(cè)試:
- 對(duì)應(yīng)用中的各個(gè)功能模塊進(jìn)行單元測(cè)試,使用測(cè)試框架(如JUnit)來編寫測(cè)試用例。例如,對(duì)于一個(gè)工具類中的方法,通過編寫多個(gè)測(cè)試用例來驗(yàn)證其在不同輸入情況下的輸出是否正確。單元測(cè)試可以幫助發(fā)現(xiàn)代碼中的邏輯錯(cuò)誤,并且在代碼修改后能夠快速驗(yàn)證是否引入了新的問題。
- 對(duì)于涉及到界面的模塊,可以使用Espresso等測(cè)試框架進(jìn)行UI單元測(cè)試。它可以模擬用戶的操作,如點(diǎn)擊按鈕、輸入文本等,來測(cè)試界面的響應(yīng)是否正確。
- 集成測(cè)試和系統(tǒng)測(cè)試:
- 進(jìn)行集成測(cè)試,確保不同模塊之間的接口和交互是正確的。例如,當(dāng)一個(gè)Activity需要調(diào)用一個(gè)Service來獲取數(shù)據(jù)時(shí),通過集成測(cè)試來驗(yàn)證這個(gè)調(diào)用過程以及數(shù)據(jù)的傳遞是否正常。
- 系統(tǒng)測(cè)試則是從用戶的角度出發(fā),對(duì)整個(gè)應(yīng)用進(jìn)行全面的測(cè)試。包括功能測(cè)試、性能測(cè)試、兼容性測(cè)試等。在不同的設(shè)備型號(hào)、屏幕尺寸、安卓系統(tǒng)版本下進(jìn)行測(cè)試,確保應(yīng)用在各種情況下都能夠穩(wěn)定運(yùn)行。
依賴管理與更新策略
- 依賴庫管理:
- 謹(jǐn)慎選擇第三方依賴庫,確保其質(zhì)量和穩(wěn)定性。在引入新的依賴庫之前,對(duì)其進(jìn)行充分的調(diào)研,查看其在社區(qū)中的口碑、更新頻率和維護(hù)情況。例如,如果一個(gè)依賴庫存在很多未解決的問題或者長(zhǎng)時(shí)間沒有更新,可能會(huì)給應(yīng)用帶來潛在的風(fēng)險(xiǎn)。
- 定期更新依賴庫,以獲取最新的功能和安全補(bǔ)丁。但在更新時(shí),需要進(jìn)行充分的測(cè)試,確保新的依賴庫版本不會(huì)與應(yīng)用中的現(xiàn)有代碼產(chǎn)生沖突或者引入新的問題。
- 應(yīng)用自身更新策略:
- 建立合理的應(yīng)用更新機(jī)制,當(dāng)發(fā)現(xiàn)應(yīng)用中存在穩(wěn)定性或可靠性問題時(shí),及時(shí)發(fā)布更新版本??梢酝ㄟ^在應(yīng)用中設(shè)置自動(dòng)更新功能(在用戶同意的情況下),或者提示用戶進(jìn)行更新,以確保用戶能夠使用到修復(fù)后的版本。
- 在更新內(nèi)容方面,除了解決已知的問題,還可以對(duì)應(yīng)用的性能和穩(wěn)定性進(jìn)行持續(xù)優(yōu)化,如優(yōu)化代碼結(jié)構(gòu)、更新數(shù)據(jù)庫模式等。
環(huán)境搭建與準(zhǔn)備
- 安裝必要軟件:確保已經(jīng)安裝了Android Studio和Java Development Kit(JDK)。Gradle插件開發(fā)需要JDK來編譯代碼,Android Studio提供了開發(fā)和調(diào)試插件的集成環(huán)境。一般建議使用較新版本的JDK(如JDK 8或更高版本),因?yàn)椴煌腉radle版本對(duì)JDK版本有一定要求。
- 了解Gradle基礎(chǔ)知識(shí):在開發(fā)Gradle插件之前,需要熟悉Gradle的基本概念,如項(xiàng)目結(jié)構(gòu)、構(gòu)建腳本(
build.gradle
)、任務(wù)(Task)、依賴管理等。例如,知道如何在build.gradle
文件中配置項(xiàng)目的依賴關(guān)系,以及Gradle任務(wù)是如何定義和執(zhí)行的。 - 創(chuàng)建插件項(xiàng)目:在Android Studio中,可以通過新建一個(gè)Java或Groovy項(xiàng)目來開始Gradle插件開發(fā)。如果使用Java開發(fā),需要確保項(xiàng)目的構(gòu)建路徑中包含Gradle API的依賴。如果使用Groovy,由于Gradle本身就是基于Groovy語言構(gòu)建的,開發(fā)起來會(huì)更加方便,它可以更自然地與Gradle的腳本語言相融合。
定義插件接口和功能
- 確定插件功能目標(biāo):明確插件要實(shí)現(xiàn)的功能,例如,插件是用于自動(dòng)生成代碼、管理資源文件、還是進(jìn)行依賴版本控制等。以一個(gè)自動(dòng)生成代碼的插件為例,它可能需要讀取項(xiàng)目中的某些配置文件,根據(jù)配置信息生成特定的Java或Kotlin代碼。
- 設(shè)計(jì)插件接口(如果需要):對(duì)于一些復(fù)雜的插件,可能需要設(shè)計(jì)接口來方便其他開發(fā)者擴(kuò)展或與插件進(jìn)行交互。例如,一個(gè)用于處理項(xiàng)目打包的插件,可以設(shè)計(jì)一個(gè)接口,讓其他開發(fā)者能夠自定義打包過程中的某些步驟,如添加自定義的文件到APK包中。
- 學(xué)習(xí)Gradle API相關(guān)知識(shí):根據(jù)插件的功能目標(biāo),學(xué)習(xí)Gradle API中與之相關(guān)的部分。例如,如果要?jiǎng)?chuàng)建一個(gè)新的Gradle任務(wù),需要了解
org.gradle.api.Task
接口和相關(guān)的創(chuàng)建方法;如果要處理項(xiàng)目的依賴關(guān)系,需要熟悉org.gradle.api.artifacts
包中的相關(guān)類和方法。
插件開發(fā)實(shí)現(xiàn)階段
- 編寫插件代碼(以Groovy為例):
- 定義插件類,插件類需要實(shí)現(xiàn)
org.gradle.api.Plugin
接口。例如:
- 定義插件類,插件類需要實(shí)現(xiàn)
import org.gradle.api.Plugin
import org.gradle.api.Projectclass MyPlugin implements Plugin<Project> {@Overridevoid apply(Project project) {// 在這里添加插件的具體功能代碼project.task('myTask') {doLast {println "My custom task is executed."}}}
}
在這個(gè)例子中,MyPlugin
是一個(gè)簡(jiǎn)單的Gradle插件,它在apply
方法中為項(xiàng)目添加了一個(gè)名為myTask
的任務(wù),當(dāng)這個(gè)任務(wù)執(zhí)行時(shí),會(huì)打印一條消息。
- 如果插件需要處理項(xiàng)目的配置文件,例如讀取build.gradle
中的自定義配置參數(shù),可以使用project.extensions
來訪問這些參數(shù)。假設(shè)在build.gradle
中有一個(gè)自定義配置myPluginConfig
,可以這樣讀取:
class MyPlugin implements Plugin<Project> {@Overridevoid apply(Project project) {def myConfig = project.extensions.myPluginConfig// 根據(jù)myConfig的值來執(zhí)行相關(guān)操作}
}
- 處理依賴關(guān)系(如果需要):如果插件依賴其他庫或插件,需要在插件的構(gòu)建文件(通常是
build.gradle
)中添加依賴。例如,添加對(duì)某個(gè)第三方庫的依賴:
dependencies {implementation 'com.example:mylibrary:1.0.0'
}
- 測(cè)試插件功能(本地測(cè)試):可以在本地項(xiàng)目中對(duì)插件進(jìn)行測(cè)試。首先,將插件項(xiàng)目構(gòu)建并發(fā)布到本地的Maven倉庫或直接將插件的編譯結(jié)果添加到測(cè)試項(xiàng)目的依賴中。然后,在測(cè)試項(xiàng)目的
build.gradle
文件中應(yīng)用插件,例如:
apply plugin: 'com.example.myplugin'
接著,執(zhí)行相關(guān)的Gradle任務(wù),觀察插件是否按照預(yù)期工作。
- 插件打包與發(fā)布
- 插件打包:在插件開發(fā)完成并測(cè)試通過后,需要將插件打包成合適的格式。通常是將插件打包成JAR文件。在Gradle項(xiàng)目中,可以通過
jar
任務(wù)來創(chuàng)建JAR文件。例如,在插件項(xiàng)目的build.gradle
文件中配置jar
任務(wù)的相關(guān)屬性,如指定主類、包含的文件等。 - 發(fā)布插件:
- 發(fā)布到本地Maven倉庫:可以將插件發(fā)布到本地的Maven倉庫,方便在本地其他項(xiàng)目中使用。在插件項(xiàng)目的
build.gradle
文件中配置maven-publish
插件,設(shè)置發(fā)布的倉庫地址、插件的坐標(biāo)(groupId、artifactId、version)等信息。例如:
- 發(fā)布到本地Maven倉庫:可以將插件發(fā)布到本地的Maven倉庫,方便在本地其他項(xiàng)目中使用。在插件項(xiàng)目的
- 插件打包:在插件開發(fā)完成并測(cè)試通過后,需要將插件打包成合適的格式。通常是將插件打包成JAR文件。在Gradle項(xiàng)目中,可以通過
publishing {publications {myPlugin(MavenPublication) {groupId = 'com.example'artifactId = 'myplugin'version = '1.0.0'from components.java}}repositories {maven {url uri('../local_maven_repository')}}
}
- 發(fā)布到公共Maven倉庫或插件倉庫:如果希望更廣泛地分享插件,可以將插件發(fā)布到公共的Maven倉庫(如JCenter、Maven Central)或者專門的Gradle插件倉庫。這通常需要進(jìn)行一些額外的步驟,如注冊(cè)賬號(hào)、獲取發(fā)布權(quán)限、遵循倉庫的發(fā)布規(guī)范等。
熟練掌握安卓逆向技術(shù),熟練運(yùn)用 JAD、JEB、Frida、AndroidKiller、IDA 等工具,能夠深入分析與優(yōu)化應(yīng)用。
手機(jī)HTTPS抓包
Magisk安裝
https://zhaojian.blog.csdn.net/article/details/128341043
使用Charles進(jìn)行HTTPS抓包
https://zhaojian.blog.csdn.net/article/details/130281149
使用Frida 脫殼
FART脫殼機(jī)學(xué)習(xí)
https://zhaojian.blog.csdn.net/article/details/137570818
360加固脫殼實(shí)戰(zhàn)
https://zhaojian.blog.csdn.net/article/details/137523091
脫殼之常用的加固樣本特征
https://zhaojian.blog.csdn.net/article/details/137156244
熟悉 IOS/Flutter 開發(fā),擁有上線項(xiàng)目經(jīng)驗(yàn);熟悉 uniapp / 鴻蒙開發(fā),具備一定的音視頻開發(fā)基礎(chǔ),為跨平臺(tái)應(yīng)用開發(fā)提供了更廣闊的技術(shù)視野。
具備開發(fā) SDK 及編寫對(duì)外 SDK 接口文檔的能力,對(duì)反作弊 sdk 有一定了解,為應(yīng)用安全與功能拓展提供有力保障。
熟練使用AI工具進(jìn)行實(shí)際問題查詢與解決,顯著提升工作效率與創(chuàng)新能力。
熟悉 jenkins 等項(xiàng)目構(gòu)建搭建流程,確保項(xiàng)目高效穩(wěn)定交付。
資料
Java中9種常見的CMS GC問題分析與解決