PS:以記筆記的方式栗恩,匯總一些android基礎(chǔ)知識男窟。
1势决、android 四種啟動模式
1步淹、standard 標(biāo)準(zhǔn)模式
2从隆、singleTop 棧頂復(fù)用模式诚撵,activity 不在棧頂時跟standard一樣,復(fù)用時調(diào)用onNewIntent()方法
3键闺、singleInstance 棧內(nèi)復(fù)用模式,復(fù)用時清除棧內(nèi)該Activity上層的所有Activity(clear top)寿烟,調(diào)用onNewIntent()方法
4、singleTask 獨自放在一個任務(wù)棧里面辛燥,相當(dāng)于自己就是一個應(yīng)用筛武,有自己的上下文activity
2、activity或fragment被系統(tǒng)銷毀時數(shù)據(jù)緩存
activity 緩存: onSaveInstanceState() 和 onRestoreInstanceState()
fragment緩存: onSaveInstanceState() 和 onViewStateRestored()
3挎塌、為什么在Service中創(chuàng)建子線程而不是再Activity中徘六?
因為Activity很難對Thread進行控制,當(dāng)Activity銷毀后就沒有任何辦法獲取之前創(chuàng)建的子線程的實例了榴都。然而Service就不一樣待锈,任何Activity都可以與之關(guān)聯(lián),又能獲取原有Service穿件的Bindle實例嘴高。從而更好的控制后臺任務(wù)竿音。
4、Service兩種啟動方法及區(qū)別
startService : activity啟動service之后拴驮,service并不和activity產(chǎn)生關(guān)聯(lián)
bindService : service和activity的context關(guān)聯(lián)并啟動春瞬,生命周期與context一致。
5套啤、廣播(BroadCast Receiver)的兩種注冊狀態(tài)(靜態(tài)注冊和動態(tài)注冊)
靜態(tài)注冊:在Manifest里面注冊快鱼,應(yīng)用退出后依然在工作
動態(tài)注冊:代碼中注冊,應(yīng)用退出后無法工作
6纲岭、如何保持Android進程不被殺死
1抹竹、1px Activity進程保活止潮,應(yīng)用退出后臺時啟動1像素的Activity窃判,占用內(nèi)存小,降低被回收的概率
2、提升Service 進程優(yōu)先級
3凄吏、onDestory的時候重啟service
7婶恼、android動畫
1、tween 補間動畫:通過制定View的初末狀態(tài)和變化時間唆樊、方式,對View的內(nèi)容完成一系列的變化方式來實現(xiàn)刻蟹。Alpha , Scale , Translate , Rotate 逗旁。
2、frame 幀動畫:AnimationDrawable 控制animation-list xml布局
3舆瘪、PropertyAnimation 屬性動畫
4片效、SVG矢量動畫
8红伦、自定義View 過程:onMeasure() onLayout() onDraw()
1、自定義屬性的聲明和獲鹊硪隆:
a昙读、分析需要的自定義屬性
b、在res/values/attr.xml定義聲明
c膨桥、在layout文件中進行使用
d蛮浑、在View的構(gòu)造方法中進行獲取
2、測量onMeasure
3只嚣、布局onLayout(ViewGroup)
4沮稚、繪制onDraw
5、onTouchEvent
6介牙、onInterceptTouchEvent(ViewGroup) :事件分發(fā)
7壮虫、狀態(tài)的恢復(fù)和保存
9、android事件分發(fā)機制
dispatchTouchEvent()
onFilterTouchEventForSecurity() ( onInterceptTouchEvent())
onTouch()
onTouchEvent()
onClick()
View中的dispatchTouchEvent()方法源碼如下:
public boolean dispatchTouchEvent(MotionEvent event) {
// If the event should be handled by accessibility focus first
......
boolean result = false;
......
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
......
return result;
}
可以看到onFilterTouchEventSecurity() 為開關(guān)环础,并且當(dāng)onTouch()方法返回True時囚似,之后不會調(diào)用onTouchEvent()方法,并且進一步查看TextView的onTouchEvent()源碼可以看到里面調(diào)用了onClick()方法线得。
如下log可以看到調(diào)用的相關(guān)方法饶唤,推測出事件的傳遞機制:
09-04 14:45:11.519 2998-2998/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 1
09-04 14:45:11.519 2998-2998/com.sleep.sunshine I/TestTouchEventLayout: onFilterTouchEventForSecurity:
09-04 14:45:11.519 2998-2998/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 1
09-04 14:45:11.519 2998-2998/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 1
09-04 14:45:11.519 2998-2998/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 1
09-04 14:45:11.519 2998-2998/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 1
09-04 14:45:11.521 2998-2998/com.sleep.sunshine I/TestTouchEventActivity: onClick:
10、Handler消息機制
Handler
Looper :輪詢器贯钩,每個線程只能有一個Looper
MessageQueue:消息隊列募狂,儲存消息,先進先出
Message
11角雷、子線程中創(chuàng)建handler
1祸穷、方法1:利用子線程的Looper
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
handler.sendEmptyMessage(1);
Looper.loop();
}
}).start();
2、方法2:獲取主線程的looper勺三,或者說是UI線程的looper
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(Looper.getMainLooper()){ // 區(qū)別在這@坠觥!B鸺帷祈远!
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
};
}).start();
12、內(nèi)存泄漏
原因:生命周期長的對象持有生命周期短的對象的引用導(dǎo)致該對象不能及時回收商源,導(dǎo)致內(nèi)存泄漏车份。
容易導(dǎo)致內(nèi)存泄露的地方:
1、單例對象初始化時持有外部對象的引用(其他類或者context)
2牡彻、非靜態(tài)內(nèi)部類默認持有外部類的引用扫沼,這時候創(chuàng)建內(nèi)部類的靜態(tài)實例會造成內(nèi)存泄露
3、匿名內(nèi)部類和異步線程:匿名內(nèi)部類會持有外部類的引用
4、handler造成內(nèi)存泄漏:延時消息可能會導(dǎo)致handler與activity生命周期不一致充甚。(用弱引用)
5以政、cursor 霸褒、bitmap 伴找、broadcast 、soeket 废菱、stream 等及時關(guān)閉
handler弱引用示例:
private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
private final MyHandler mHandler = new MyHandler(this);
/**
* Instances of anonymous classes do not hold an implicit
* reference to their outer class when they are "static".
*/
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { /* ... */ }
};
13技矮、Android 性能優(yōu)化
1、合理管理內(nèi)存:
a殊轴、節(jié)制使用service
b衰倦、界面不可見時釋放內(nèi)存,bitmap不要加載不需要的分辨率等
c旁理、少用依賴注入框架
2樊零、分析內(nèi)存使用情況,解決內(nèi)存泄露等問題:LeakCanary等工具
3孽文、高性能編碼驻襟,如:
a、字符串拼接時用StringBuffer或者StringBuilder ,少用String
b芋哭、多用系統(tǒng)API
c沉衣、ArrayList 遍歷傳統(tǒng)方式最快,數(shù)組等用增強for循環(huán)最快等
d减牺、避免在內(nèi)部調(diào)用Getters/Setters方法
4豌习、布局優(yōu)化、避免復(fù)雜布局或者嵌套布局
14拔疚、取消Android TextView 內(nèi)邊距’
android:includeFontPadding=“false"
15肥隆、Android彈出軟鍵盤后點擊鍵盤外面關(guān)閉
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (isShouldHideInput(v, ev)) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
return super.dispatchTouchEvent(ev);
}
// 必不可少,否則所有的組件都不會有TouchEvent了
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
public boolean isShouldHideInput(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] leftTop = {0, 0};
//獲取輸入框當(dāng)前的location位置
v.getLocationInWindow(leftTop);
int left = leftTop[0];
int top = leftTop[1];
int bottom = top + v.getHeight();
int right = left + v.getWidth();
if (event.getX() > left && event.getX() < right
&& event.getY() > top && event.getY() < bottom) {
// 點擊的是輸入框區(qū)域稚失,保留點擊EditText的事件
return false;
} else {
//使EditText觸發(fā)一次失去焦點事件
v.setFocusable(false);
// v.setFocusable(true); //這里不需要是因為下面一句代碼會同時實現(xiàn)這個功能
v.setFocusableInTouchMode(true);
return true;
}
}
return false;
}
16栋艳、gson 解析List<T>
Gson gson = new Gson();
Type founderListType = new TypeToken<ArrayList<Founder>>(){}.getType();
List<Founder> founderList = gson.fromJson(founderJson, founderListType);
17、RecyclerView加載更多
/**
* 提前多少個item觸發(fā)加載更多
*/
private int visibleThreshold = 2;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int itemCount = layoutManager.getItemCount();
int lastPosition = layoutManager.findLastVisibleItemPosition();
//如果當(dāng)前不是正在加載更多墩虹,并且到了該加載更多的位置嘱巾,加載更多。
if (!isLoading && (lastPosition >= (itemCount - visibleThreshold))) {
loadMore();
}
}
});
18诫钓、Android5.0水波紋效果ripple實現(xiàn)
// 波紋有邊界
android:background="?android:attr/selectableItemBackground"
// 波紋超出邊界
android:background="?android:attr/selectableItemBackgroundBorderless"
<a />
19旬昭、混淆代碼后崩潰日志中不顯示行號的問題
原因是在混淆代碼時默認會去掉class文件中的調(diào)試信息(源碼的行號、源文件信息等)菌湃,需要在混淆配置文件中申明保持這些信息:
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable