Android當中保持60幀以上算是流暢:60fps ——>16ms/幀(數字量化)java
準則:儘可能保證每次在16ms內處理完全部的cpu與Gpu計算、繪製、渲染等操做,不然會形成丟幀卡頓等問題android
緣由:在主線程中執行耗時工做,把事件分發給合適的view或者widget的git
handler
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
複製代碼
佈局Layout過於複雜,沒法在16ms內完成渲染github
View的過分繪製安全
View頻繁的觸發measure、layoutbash
內存頻繁的觸發GC過多(STW,建立太多的臨時變量)實現的核心原理網絡
###Blockcanary工具 在主線程ActivityThread中的 dispatchMessge(msg)上下方打印時間,計算閥值,超過了就打印併發
postMessage(Handler)app
Queue.next()獲取咱們的消息less
是否超過咱們的閥值 (Dump all Allocation)
DisplayActivity在 release 版本不會顯示
核心邏輯在BlockCanaryInternals:
LooperMonitor:判斷是否卡頓 isBlock
private boolean isBlock(long endTime) {
return endTime - mStartTimestamp > mBlockThresholdMillis;
}
private void notifyBlockEvent(final long endTime) {
final long startTime = mStartTimestamp;
final long startThreadTime = mStartThreadTimestamp;
final long endThreadTime = SystemClock.currentThreadTimeMillis();
HandlerThreadFactory.getWriteLogThreadHandler().post(new Runnable() {
@Override
public void run() {
mBlockListener.onBlockEvent(startTime, endTime, startThreadTime, endThreadTime);
}
});
}
private void startDump() {
if (null != BlockCanaryInternals.getInstance().stackSampler) {
BlockCanaryInternals.getInstance().stackSampler.start();
}
if (null != BlockCanaryInternals.getInstance().cpuSampler) {
BlockCanaryInternals.getInstance().cpuSampler.start();
}
}
複製代碼
stackSampler:
public ArrayList<String> getThreadStackEntries(long startTime, long endTime) {
ArrayList<String> result = new ArrayList<>();
synchronized (sStackMap) {
for (Long entryTime : sStackMap.keySet()) {
if (startTime < entryTime && entryTime < endTime) {
result.add(BlockInfo.TIME_FORMATTER.format(entryTime)
+ BlockInfo.SEPARATOR
+ BlockInfo.SEPARATOR
+ sStackMap.get(entryTime));
}
}
}
return result;
}
@Override
protected void doSample() {
StringBuilder stringBuilder = new StringBuilder();
for (StackTraceElement stackTraceElement : mCurrentThread.getStackTrace()) {
stringBuilder
.append(stackTraceElement.toString())
.append(BlockInfo.SEPARATOR);
}
synchronized (sStackMap) {
if (sStackMap.size() == mMaxEntryCount && mMaxEntryCount > 0) {
sStackMap.remove(sStackMap.keySet().iterator().next());
}
sStackMap.put(System.currentTimeMillis(), stringBuilder.toString());
}
}
複製代碼
CpuSampler:
@Override
protected void doSample() {
BufferedReader cpuReader = null;
BufferedReader pidReader = null;
try {
cpuReader = new BufferedReader(new InputStreamReader(
new FileInputStream("/proc/stat")), BUFFER_SIZE);
String cpuRate = cpuReader.readLine();
if (cpuRate == null) {
cpuRate = "";
}
if (mPid == 0) {
mPid = android.os.Process.myPid();
}
pidReader = new BufferedReader(new InputStreamReader(
new FileInputStream("/proc/" + mPid + "/stat")), BUFFER_SIZE);
String pidCpuRate = pidReader.readLine();
if (pidCpuRate == null) {
pidCpuRate = "";
}
parse(cpuRate, pidCpuRate);
} catch (Throwable throwable) {
Log.e(TAG, "doSample: ", throwable);
} finally {
try {
if (cpuReader != null) {
cpuReader.close();
}
if (pidReader != null) {
pidReader.close();
}
} catch (IOException exception) {
Log.e(TAG, "doSample: ", exception);
}
}
}
複製代碼
watchDog-anr是如何監控anr的?
主線程耗時操做 ()
主線程被鎖住
cpu被其它的進程佔用
建立一個監控線程
private final Handler _uiHandler = new Handler(Looper.getMainLooper());
複製代碼
改線程不斷往UI線程post一個任務
private final Runnable _ticker = new Runnable() {
@Override public void run() {
_tick = (_tick + 1) % Integer.MAX_VALUE;
}
};
@Override
public void run() {
setName("|ANR-WatchDog|");
int lastTick;
int lastIgnored = -1;
while (!isInterrupted()) {
lastTick = _tick;
_uiHandler.post(_ticker);
try {
//睡眠固定時間
Thread.sleep(_timeoutInterval);
}
catch (InterruptedException e) {
_interruptionListener.onInterrupted(e);
return ;
}
// If the main thread has not handled _ticker, it is blocked. ANR.
if (_tick == lastTick) {
if (!_ignoreDebugger && Debug.isDebuggerConnected()) {
if (_tick != lastIgnored)
Log.w("ANRWatchdog", "An ANR was detected but ignored because the debugger is connected (you can prevent this with setIgnoreDebugger(true))");
lastIgnored = _tick;
continue ;
}
ANRError error;
if (_namePrefix != null)
error = ANRError.New(_namePrefix, _logThreadsWithoutStackTrace);
else
error = ANRError.NewMainOnly();
_anrListener.onAppNotResponding(error);
return;
}
}
}
複製代碼
存在的問題:
Process.setThreadPriority(Process.THREAD_PRIO_RITY_BACKGROUD), 須要把線程優先級下降
Handler handler = new Handler(){
void handlerMessage(){
do UI things...
}
}
New Thread(){
void run(){
handler. sendMessage();
}
}.start();
handler.post(runnable);
Activity.runOnUiThread(Runnable)
複製代碼
AsynTask的線程優先級是background不會阻塞UI。
AsyncTask 3.0以後改爲順序執行,當一個進程中有多個AsynTask同時並行執行,他們會公用線程池,主要緣由在doInBackground()中訪問相同的資源,線程池會形成線程的併發訪問形成線程安全問題,因此設計成串行的,就不會有線程安全問題。
Runnable做爲匿名內部類的話會持有外部類的引用,容易內存泄漏,不建議採起這種方式
它集成了Thread
它有本身的內部Looper對象,經過Looper.loop()進行looper循環
HandlerThread的looper對象傳遞給Handler對象,而後在handleMessge()方法中執行異步任務
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/** * This method returns the Looper associated with this thread. If this thread not been started * @return The looper. */
//這個是在UI線程中調用,須要解決同步問題,由於looper對象在 run方法裏運行。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/** * @return a shared {@link Handler} associated with this thread * @hide */
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
/** * Quits the handler thread's looper. * <p> * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. * @see #quitSafely */
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
//清空全部消息
looper.quit();
return true;
}
return false;
}
/** * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. */
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
//清除全部的延遲消息
looper.quitSafely();
return true;
}
return false;
}
/** * Returns the identifier of this thread. See Process.myTid(). */
public int getThreadId() {
return mTid;
}
}
複製代碼
HandlerThread適合單線程或者異步隊列,I/O流讀取文件,進行異步轉化比較合適,只有一個線程。
網絡的數據須要併發處理,不太適合。
intentService是Service類的子類
單獨開啓一個線程來處理全部的Intent請求所對應的任務
當IntentService處理完任務以後,會本身在合適的時候結束
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/** * Unless you provide binding for your service, you don't need to implement this * method, because the default implementation returns null. * @see android.app.Service#onBind */
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
複製代碼
//餓漢
public class Singleton{
private static Singleton intance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
//懶漢
public class SingletonLazy{
private static SingletonLazy intance = null;
private Singleton(){}
public static SingletonLazy getInstance(){
if(null == instance){
instance = new SingletonLazy();
}
return instance;
}
//性能損耗較大
public static synchronized SingletonLazy getInstance1(){
if(null == instance){
instance = new SingletonLazy();
}
return instance;
}
}
//雙重校驗鎖
public class SingletonDouble{
private static volatile SingletonDouble intance = null;
private SingletonDouble(){}
public static SingletonDouble getInstance(){
if(null == instance){
synchronized(SingletonDouble.this){
if(null == instance){
instance = new SingletonDouble();
}
}
}
return instance;
}
}
複製代碼