Q:為什么整理知識(shí)忆家,以及copy其它的文章灯变?
A:因?yàn)橹笆詹亓撕枚嗪馨舻奈恼峦舶牵袅撕镁煤蟠蜷_失效了墓拜,也是為了鞏固一下知識(shí),android知識(shí)比較雜亂信认,需要定期整理罪郊。
1.讀取dp數(shù)據(jù)益愈,返回px
getResources().getDimensionPixelOffset(R.dimen.xxx);
2.ListView與ScrollView滑動(dòng)沖突解決
重寫onMeasure
3.沉浸式原理
隱藏狀態(tài)欄户誓,即全屏饼灿。
新建出一個(gè)狀態(tài)欄代替。
decorView是一個(gè)FrameLayout帝美,內(nèi)部是一個(gè)LinearLayout(本身只有一個(gè)赔退,內(nèi)部是我們的布局,哈哈证舟,廢話!)窗骑。隱藏狀態(tài)欄時(shí)(設(shè)置為透明)女责,LinearLayout會(huì)上移,所以添加新的狀態(tài)欄時(shí)(新建一個(gè)View占空間)创译,需要進(jìn)行margin/Padding處理(高度為getStatusBarHeight(activity))抵知,或者設(shè)置LinearLayout的最外層布局屬性android:fitsSystemWindows="true"。
view.getRootView()
獲取到的是decorView
,即根ViewGroup刷喜。decorView
不包括狀態(tài)欄和導(dǎo)航欄残制,它們屬于SystemUI,當(dāng)它們設(shè)置為透明或隱藏時(shí)掖疮,decorView
高度會(huì)填充它們的位置初茶。這也是沉浸式的原理。
getWindow().getDecorView()
獲取到的也是decorView!
額外說一下浊闪,android.R.id.content
指的是上圖中的ContentView
(綠色框)恼布,切記!切記搁宾!別搞混了~~~~
findViewById(android.R.id.content)
4.Android5.0中的colorPrimary折汞、colorPrimaryDark、colorAccent
在5.0以上手機(jī)上直接設(shè)置colorPrimaryDark顏色盖腿,即可修改狀態(tài)欄顏色爽待;直接設(shè)置colorPrimary顏色,即可修改標(biāo)題欄顏色翩腐;直接設(shè)置colorAccent顏色鸟款,即可修改默認(rèn)的內(nèi)容顏色。
5.padding和margin區(qū)別(與H5不一樣)
6.webView的padding設(shè)置有先天bug栗菜!
無論怎么設(shè)置padding都是不好使的欠雌,可以在web頁面中設(shè)置padding,也可以在Android的webview加載頁面時(shí)(原理一樣)疙筹,這樣做富俄,如下:
view.loadUrl(String.format(Locale.CHINA, "javascript:document.body.style.paddingTop='%fpx'; void 0", DensityUtil.px2dp(webView.getPaddingTop())));
7.RecyclerView中使用SnapHelper
SnapHelper snapHelper =new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
效果圖:
8.performClick
performClick 是使用代碼主動(dòng)去調(diào)用控件的點(diǎn)擊事件(模擬人手去觸摸控件)
boolean android.view.View.performClick()
Call this view's OnClickListener, if it is defined.
Returns:
True there was an assigned OnClickListener that was called, false otherwise is returned.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
btn1 = (Button) findViewById(R.id.button1);
tv1 = (TextView) findViewById(R.id.textView1);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
tv1.setText("已經(jīng)被點(diǎn)擊過了");
}
});
// 模擬點(diǎn)擊事件
btn1.performClick();
}
9.代碼中設(shè)置Intent模式
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
FLAG_ACTIVITY_NEW_TASK和Intent.FLAG_ACTIVITY_CLEAR_TOP一起使用的作用等同于singleTask。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS的意思是不在最近啟動(dòng)的列表中顯示而咆。
10.禁止截屏和錄屏
設(shè)置Activity的屬性:可防止系統(tǒng)截屏
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
11.設(shè)置application的allowBackup或者label沖突
<application
android:name=".MyApplication"
android:allowBackup="false"
android:hardwareAccelerated="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/appName"
android:supportsRtl="true"
android:theme="@style/NoTitle"
tools:replace="android:label,android:allowBackup">
沖突是由于該應(yīng)用manifest中android:allowBackup和module或jar包中沖突導(dǎo)致霍比,解決方法是使用tools:replace標(biāo)注來替換,多個(gè)屬性之間用“,”來分隔暴备。
12.SurfaceView與TextureView的區(qū)別
SurfaceView有獨(dú)立的Surface悠瞬,通過“挖洞”原理顯示它。以致它在執(zhí)行旋轉(zhuǎn)時(shí)涯捻,畫面不會(huì)跟隨旋轉(zhuǎn)浅妆;同時(shí)設(shè)置透明度或者執(zhí)行透明值動(dòng)畫時(shí),顯示有問題障癌。Android N以上的SurfaceView在視頻進(jìn)行縮放旋轉(zhuǎn)時(shí)會(huì)同步變化凌外,不會(huì)看到黑色邊,官方推薦使用SurfaceView涛浙。TextureView作為普通View在View hierarchy中管理與繪制康辑,更適用于小窗播放視頻功能摄欲。但TextureView需要硬件加速層,使得TextureView比SurfaceView和GLSurfaceView更耗性能疮薇。
原鏈接:https://cloud.tencent.com/developer/article/1034235
13.讀取視頻文件資源
AssetFileDescriptor afd1 = getResources().openRawResourceFd(R.raw.big_buck_bunny_720p_20mb);
try {
mMediaPlayer.setDataSource(afd1.getFileDescriptor(), afd1.getStartOffset(), afd1.getLength());
} catch (IOException e) {
e.printStackTrace();
}
14.TextView設(shè)置刪除線/下劃線/加粗
txt1 = ((TextView) findViewById(R.id.txt1));
txt2 = ((TextView) findViewById(R.id.txt2));
txt3 = ((TextView) findViewById(R.id.txt3));
//添加刪除線
txt1.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
//在代碼中設(shè)置加粗
txt2.getPaint().setFlags(Paint.FAKE_BOLD_TEXT_FLAG);
//添加下劃線
txt3.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);
15.禁用截屏胸墙、錄屏
在onCreate中加入如下代碼:
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
16.對于Application,Service按咒,Activity三者的Context的應(yīng)用場景
其中: NO1表示 Application 和 Service 需要?jiǎng)?chuàng)建一個(gè)新的 task 任務(wù)隊(duì)列迟隅,才可以啟動(dòng)一個(gè) Activity。即
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
而對于 Dialog 而言胖齐,只有在 Activity 中才能創(chuàng)建玻淑。
17.內(nèi)存泄漏總結(jié)
根本原因是:長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內(nèi)存泄漏,盡管短生命周期對象已經(jīng)不再需要呀伙,但是因?yàn)殚L生命周期持有它的引用而導(dǎo)致不能被回收补履。
可以這么理解,長生命周期A含有短生命周期B的引用剿另,此時(shí)需要回收B的內(nèi)存箫锤,但是因?yàn)锳(B),導(dǎo)致內(nèi)存無法回收雨女。
具體例子如下:
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static AppManager getInstance(Context context) {
if (instance == null) {
instance = new AppManager(context);
}
return instance;
}
}
1谚攒、如果此時(shí)傳入的是 Application 的 Context,因?yàn)?Application 的生命周期就是整個(gè)應(yīng)用的生命周期氛堕,所以這將沒有任何問題馏臭。
2、如果此時(shí)傳入的是 Activity 的 Context讼稚,當(dāng)這個(gè) Context 所對應(yīng)的 Activity 退出時(shí)括儒,由于該 Context 的引用被單例對象所持有,其生命周期等于整個(gè)應(yīng)用程序的生命周期锐想,所以當(dāng)前 Activity 退出時(shí)它的內(nèi)存并不會(huì)被回收帮寻,這就造成泄漏了。
場景
類的靜態(tài)變量持有大數(shù)據(jù)對象
靜態(tài)變量長期維持到大數(shù)據(jù)對象的引用赠摇,阻止垃圾回收固逗。非靜態(tài)內(nèi)部類的靜態(tài)實(shí)例
非靜態(tài)內(nèi)部類會(huì)維持一個(gè)到外部類實(shí)例的引用,如果非靜態(tài)內(nèi)部類的實(shí)例是靜態(tài)的藕帜,就會(huì)間接長期維持著外部類的引用烫罩,阻止被回收掉。資源對象未關(guān)閉
資源性對象如Cursor洽故、File贝攒、Socket,應(yīng)該在使用后及時(shí)關(guān)閉收津。未在finally中關(guān)閉饿这,會(huì)導(dǎo)致異常情況下資源對象未被釋放的隱患。注冊對象未反注冊
未反注冊會(huì)導(dǎo)致觀察者列表里維持著對象的引用撞秋,阻止垃圾回收长捧。Handler臨時(shí)性內(nèi)存泄露
Handler通過發(fā)送Message與主線程交互,Message發(fā)出之后是存儲(chǔ)在MessageQueue中的吻贿,有些Message也不是馬上就被處理的串结。在Message中存在一個(gè) target,是Handler的一個(gè)引用舅列,如果Message在Queue中存在的時(shí)間越長肌割,就會(huì)導(dǎo)致Handler無法被回收。如果Handler是非靜態(tài)的帐要,則會(huì)導(dǎo)致Activity或者Service不會(huì)被回收把敞。
由于AsyncTask內(nèi)部也是Handler機(jī)制,同樣存在內(nèi)存泄漏的風(fēng)險(xiǎn)榨惠。
此種內(nèi)存泄露奋早,一般是臨時(shí)性的。
18.RxJava的些許問題
-
doOnNext
public Observable<TestBean> getInfor() {
Observable observable = retrofitService.getInfor()
// .observeOn(Schedulers.io())
.doOnNext(new Consumer<TestBean>() {
@Override
public void accept(@NonNull TestBean testBean) throws Exception {
Log.d("LKK", "doOnNext=========" + Thread.currentThread().getName());
}
})
.compose(this.toMain());
return observable;
}
doOnNext
是在onNext()
之前運(yùn)行的赠橙,并且默認(rèn)在io線程
運(yùn)行耽装。
注意:observeOn
必須指定在doOnNext
之前才起作用。
-
doOnSubscribe
我們知道observeOn()
可以多次調(diào)用期揪,實(shí)現(xiàn)線程的多次切換掉奄。但是subscribeOn()
只是第一次的設(shè)置起作用。
從圖中可以看出凤薛,subscribeOn() 和 observeOn() 都做了線程切換的工作(圖中的 "schedule..." 部位)姓建。不同的是, subscribeOn() 的線程切換發(fā)生在 OnSubscribe 中枉侧,即在它通知上一級(jí) OnSubscribe 時(shí)引瀑,這時(shí)事件還沒有開始發(fā)送,因此 subscribeOn() 的線程控制可以從事件發(fā)出的開端就造成影響榨馁;而 observeOn() 的線程切換則發(fā)生在它內(nèi)建的 Subscriber 中憨栽,即發(fā)生在它即將給下一級(jí) Subscriber 發(fā)送事件時(shí),因此 observeOn() 控制的是它后面的線程翼虫。
這個(gè)時(shí)候要想subscribeOn
起作用屑柔,需要用到Observable.doOnSubscribe()
。它和 Subscriber.onStart()
同樣是在subscribe()
調(diào)用后而且在事件發(fā)送前執(zhí)行珍剑,但區(qū)別在于它可以指定線程掸宛。默認(rèn)情況下, doOnSubscribe()
執(zhí)行在subscribe()
發(fā)生的線程招拙;而如果在 doOnSubscribe()
之后有 subscribeOn()
的話唧瘾,它將執(zhí)行后面離它最近的 subscribeOn()
所指定的線程措译。
19.如何避免后臺(tái)進(jìn)程被殺死
- 調(diào)用
startForegound
,讓你的Service所在的線程成為前臺(tái)進(jìn)程 - Service的
onDestroy
里面重新啟動(dòng)自己 - Service的
onStartCommond
返回START_STICKY
或START_REDELIVER_INTENT
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
... ...
return START_REDELIVER_INTENT;
}
值得注意的是在onStartCommand中返回值饰序,常用的返回值有:START_NOT_STICKY
领虹、START_SICKY
和START_REDELIVER_INTENT
,這三個(gè)都是靜態(tài)常理值。
START_NOT_STICKY
:表示當(dāng)Service運(yùn)行的進(jìn)程被Android系統(tǒng)強(qiáng)制殺掉之后求豫,不會(huì)重新創(chuàng)建該Service塌衰,如果想重新實(shí)例化該Service,就必須重新調(diào)用startService來啟動(dòng)蝠嘉。使用場景:表示當(dāng)Service在執(zhí)行工作中被中斷幾次無關(guān)緊要或者對Android內(nèi)存緊張的情況下需要被殺掉且不會(huì)立即重新創(chuàng)建這種行為也可接受的話最疆,這是可以在onStartCommand返回值中設(shè)置該值。如在Service中定時(shí)從服務(wù)器中獲取最新數(shù)據(jù)
START_STICKY
:表示Service運(yùn)行的進(jìn)程被Android系統(tǒng)強(qiáng)制殺掉之后蚤告,Android系統(tǒng)會(huì)將該Service依然設(shè)置為started狀態(tài)(即運(yùn)行狀態(tài))努酸,但是不再保存onStartCommand方法傳入的intent對象,然后Android系統(tǒng)會(huì)嘗試再次重新創(chuàng)建該Service罩缴,并執(zhí)行onStartCommand回調(diào)方法蚊逢,這時(shí)onStartCommand回調(diào)方法的Intent參數(shù)為null,也就是onStartCommand方法雖然會(huì)執(zhí)行但是獲取不到intent信息箫章。使用場景:如果你的Service可以在任意時(shí)刻運(yùn)行或結(jié)束都沒什么問題烙荷,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY檬寂,比如一個(gè)用來播放背景音樂功能的Service就適合返回該值终抽。
START_REDELIVER_INTENT
:表示Service運(yùn)行的進(jìn)程被Android系統(tǒng)強(qiáng)制殺掉之后,與返回START_STICKY的情況類似桶至,Android系統(tǒng)會(huì)將再次重新創(chuàng)建該Service昼伴,并執(zhí)行onStartCommand回調(diào)方法,但是不同的是镣屹,Android系統(tǒng)會(huì)再次將Service在被殺掉之前最后一次傳入onStartCommand方法中的Intent再次保留下來并再次傳入到重新創(chuàng)建后的Service的onStartCommand方法中圃郊,這樣我們就能讀取到intent參數(shù)。使用場景:如果我們的Service需要依賴具體的Intent才能運(yùn)行(需要從Intent中讀取相關(guān)數(shù)據(jù)信息等)女蜈,并且在強(qiáng)制銷毀后有必要重新創(chuàng)建運(yùn)行持舆,那么這樣的Service就適合返回START_REDELIVER_INTENT。
20.App蔽苯眩活
參考:https://blog.csdn.net/AndrExpert/article/details/75045678
币菰ⅲ活手段
當(dāng)前業(yè)界的Android進(jìn)程保活手段主要分為黑覆山、白竹伸、灰三種,其大致的實(shí)現(xiàn)思路如下:
黑色贝乜恚活:不同的app進(jìn)程勋篓,用廣播相互喚醒(包括利用系統(tǒng)提供的廣播進(jìn)行喚醒)
白色卑上恚活:啟動(dòng)前臺(tái)Service
灰色保活:利用系統(tǒng)的漏洞啟動(dòng)前臺(tái)Service
白色逼┫活與灰色卑颐铮活
①白色保活
- 提升service優(yōu)先級(jí)
在
AndroidManifest.xml
文件中對于intent-filter可以通過android:priority = “1000”
這個(gè)屬性設(shè)置最高優(yōu)先級(jí)孤荣,1000是最高值,如果數(shù)字越小則優(yōu)先級(jí)越低须揣,同時(shí)適用于廣播盐股。
- 服務(wù)設(shè)置為前臺(tái)進(jìn)程
白色保活手段非常簡單耻卡,就是調(diào)用系統(tǒng)api啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程疯汁,這樣會(huì)在系統(tǒng)的通知欄生成一個(gè)Notification,用來讓用戶知道有這樣一個(gè)app在運(yùn)行著卵酪,哪怕當(dāng)前的app退到了后臺(tái)幌蚊。就像QQ音樂那樣。
public ForeService extends Service{
public void onCreate(){
super.onCreate();
//創(chuàng)建NOtification對象
Notification notificatin=new Notification(R.drawable.icon,"前臺(tái)service",System.currentTImeMillis());
Intent intent=new Intent(this,MainActivity.class);
PendingIntent pending=PendingIntent.getActivity(this,0,intent,0);
//為通知設(shè)置布局和數(shù)據(jù)
notification.setLastestEventInfo(this,"","",pending);
//將service設(shè)置為前臺(tái)service
startForeground(1,notification);
}
}
② 灰色崩?ǎ活
這種币缍梗活手段是應(yīng)用范圍最廣泛。它是利用系統(tǒng)的漏洞來啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程瘸羡,與普通的啟動(dòng)方式區(qū)別在于漩仙,它不會(huì)在系統(tǒng)通知欄處出現(xiàn)一個(gè)Notification,看起來就如同運(yùn)行著一個(gè)后臺(tái)Service進(jìn)程一樣犹赖。這樣做帶來的好處就是队他,用戶無法察覺到你運(yùn)行著一個(gè)前臺(tái)進(jìn)程(因?yàn)榭床坏絅otification),但你的進(jìn)程優(yōu)先級(jí)又是高于普通后臺(tái)進(jìn)程的。這樣在低內(nèi)存時(shí)被kill的幾率會(huì)低一些峻村。
方式按系統(tǒng)分為:
- API<18 : 啟動(dòng)前臺(tái)service麸折,直接傳入一個(gè) new Notification()
- API>18 : 同時(shí)啟動(dòng)兩個(gè)NOTICE_ID相同的前臺(tái)service,然后將后啟動(dòng)的service進(jìn)行stop操作粘昨。(對API大于18而言垢啼,startForeground()方法需要彈出一個(gè)可見通知,如果你覺得不爽雾棺,可以開啟另一個(gè)Service將通知欄移除)
/**前臺(tái)Service膊夹,使用startForeground
* 這個(gè)Service盡量要輕,不要占用過多的系統(tǒng)資源捌浩,否則
* 系統(tǒng)在資源緊張時(shí)放刨,照樣會(huì)將其殺死
*/
public class DaemonService extends Service {
private static final String TAG = "DaemonService";
public static final int NOTICE_ID = 100;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
if(Contants.DEBUG)
Log.d(TAG,"DaemonService---->onCreate被調(diào)用,啟動(dòng)前臺(tái)service");
//如果API大于18尸饺,需要彈出一個(gè)可見通知
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("KeepAppAlive");
builder.setContentText("DaemonService is runing...");
startForeground(NOTICE_ID,builder.build());
// 如果覺得常駐通知欄體驗(yàn)不好
// 可以通過啟動(dòng)CancelNoticeService进统,將通知移除助币,oom_adj值不變
Intent intent = new Intent(this,CancelNoticeService.class);
startService(intent);
}else{
startForeground(NOTICE_ID,new Notification());
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 如果Service被終止
// 當(dāng)資源允許情況下,重啟service
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
// 如果Service被殺死螟碎,干掉通知
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){
NotificationManager mManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
mManager.cancel(NOTICE_ID);
}
if(Contants.DEBUG)
Log.d(TAG,"DaemonService---->onDestroy眉菱,前臺(tái)service被殺死");
// 重啟自己
Intent intent = new Intent(getApplicationContext(),DaemonService.class);
startService(intent);
}
}
/** 移除前臺(tái)Service通知欄標(biāo)志,這個(gè)Service選擇性使用
*
* Created by jianddongguo on 2017/7/7.
* http://blog.csdn.net/andrexpert
*/
public class CancelNoticeService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2){
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
startForeground(DaemonService.NOTICE_ID,builder.build());
// 開啟一條線程掉分,去移除DaemonService彈出的通知
new Thread(new Runnable() {
@Override
public void run() {
// 延遲1s
SystemClock.sleep(1000);
// 取消CancelNoticeService的前臺(tái)
stopForeground(true);
// 移除DaemonService彈出的通知
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
manager.cancel(DaemonService.NOTICE_ID);
// 任務(wù)完成俭缓,終止自己
stopSelf();
}
}).start();
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
- onDestroy方法里重啟service
- 1像素
鎖屏?xí)r生成一個(gè)1像素的
Activity
在前臺(tái)運(yùn)行,保證不被系統(tǒng)殺死酥郭,解鎖時(shí)銷毀這個(gè)Activity
- 雙進(jìn)程守護(hù)
顧名思義华坦,啟動(dòng)兩個(gè)Service互相監(jiān)聽,保證其中一個(gè)被殺死時(shí)不从,另一個(gè)將其拉起惜姐。
- 播放音樂
Service在后臺(tái)播放一個(gè)無聲音樂,能夠保證不被系統(tǒng)殺死椿息。
當(dāng)然歹袁,后兩種方案需要設(shè)置onStartCommand
的返回值為START_STICKY
或START_REDELIVER_INTENT
。
需要注意的是:
service
的onCreate
只會(huì)執(zhí)行一次寝优,onBind
也只會(huì)執(zhí)行一次条舔,onStartCommand
可以執(zhí)行多次。
也就是說多次創(chuàng)建service
乏矾,不管是再次調(diào)用bindService
還是startService
逞刷,onCreate
和onBind
只會(huì)執(zhí)行一次,多次調(diào)用startService
會(huì)多次執(zhí)行onstartCommand
妻熊。
21.LruCache 替代 SoftReference (軟引用)
SoftReference 只有當(dāng)系統(tǒng)內(nèi)存不足時(shí)夸浅,GC清理時(shí)才會(huì)回收SoftReference標(biāo)注的引用。它并不能及時(shí)的清理已經(jīng)無用的引用對象扔役,回收是不可控的帆喇。
LruCache(Least Recently Used),最近最少使用算法亿胸。
當(dāng)成一個(gè) Map 用就可以了坯钦,只不過實(shí)現(xiàn)了 LRU 緩存策略。
private static final float ONE_MIB = 1024 * 1024;
// 7MB
private static final int CACHE_SIZE = (int) (7 * ONE_MIB);
private LruCache<String, Bitmap> bitmapCache;
this.bitmapCache = new LruCache<String, Bitmap>(CACHE_SIZE) {
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
...
}
};
注意:
1.需要提供一個(gè)緩存容量作為構(gòu)造參數(shù)侈玄。
2.覆寫 sizeOf 方法 婉刀,自定義設(shè)計(jì)一條數(shù)據(jù)放進(jìn)來的容量計(jì)算,如果不覆寫就無法預(yù)知數(shù)據(jù)的容量序仙,不能保證緩存容量限定在最大容量以內(nèi)突颊。
因?yàn)?code>getByteCount要求的API版本較高,因此對于使用較低版本的開發(fā)者,
getRowBytes() * getHeight()
律秃。
LruCache原理
內(nèi)部由一個(gè)LinkedHashMap存儲(chǔ)緩存數(shù)據(jù)爬橡,而LinkedHashMap的特性是最新訪問的數(shù)據(jù)排在后面。
例如:
public static final void main(String[] args) {
LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>(0, 0.75f, true);
map.put(0, 0);
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
map.put(4, 4);
map.put(5, 5);
map.put(6, 6);
map.get(1);
map.get(2);
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
輸出結(jié)果:
0 0
3 3
4 4
5 5
6 6
1 1
2 2
即:當(dāng)LruCache空間滿了的時(shí)候棒动,去除LinkedHashMap的第一組數(shù)據(jù)(最舊的糙申,使用最少的),并將新的數(shù)據(jù)填加在最后(最新的)船惨。
map中的第一個(gè)元素就是最近最少使用的那個(gè)元素柜裸。
原文章:http://www.reibang.com/p/31ca573a59e0
22.ViewPager左右禁止滑動(dòng)
/**
* 禁止左右滑動(dòng)
* Created by LiuKuo at 2018/5/22
*/
public class CustomeViewPager extends ViewPager {
/**
* true:可以滑動(dòng);false:不能滑動(dòng)
*/
private boolean isScoll;
public CustomeViewPager(Context context) {
this(context, null);
}
public CustomeViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return isScoll && super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return isScoll && super.onTouchEvent(ev);
}
public void setScoll(boolean scoll) {
isScoll = scoll;
}
}
23.OkHttp寫法
法1:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_WRITE_TIME_OUT, TimeUnit.SECONDS)
.addInterceptor(interceptor);
OkHttpClient client = bulider.build();
法2:
OkHttpClient client = new OkHttpClient().newBuilder()
.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_WRITE_TIME_OUT, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.build();
24.更換主題
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final Context contextThemeWrapper = new ContextThemeWrapper(
getActivity(), isDay ? R.style.day : R.style.night);
LayoutInflater localInflater = inflater
.cloneInContext(contextThemeWrapper);
View v = localInflater.inflate(R.layout.fragment_layout, container,
false);
return v;
}
25.app包和v4包中的fragment的區(qū)別
1粱锐、app包中的fragment是在3.0之后才有的粘室,支持的版本太高。
2卜范、v4包中的Fragment可以兼容到1.6的版本。
所以鹿榜,日常使用時(shí)海雪,一般使用V4包中的fragment。
補(bǔ)充:
學(xué)習(xí)Glide源碼時(shí)电湘,其中發(fā)現(xiàn).with()
的源碼中延曙,
- 將
Activity
和android.app.Fragment
歸為一類處理概作,他們都是3.0之后的。 - 將
FragmentActivity
和android.support.v4.app.Fragment
歸一類處理湾宙,他們可以支持到1.6版本。
Fragment是Android 3.0以后的東西冈绊,為了在低版本中使用Fragment就要用到android-support-v4.jar兼容包,而FragmentActivity就是這個(gè)兼容包里面的侠鳄,它提供了操作Fragment的一些方法,其功能跟3.0及以后的版本的Activity的功能一樣死宣。
26.Android 5.0新增跳轉(zhuǎn)動(dòng)畫
Pair<View, String> p1 = Pair.create((View)holder.imgBg, "img_view_1");
Pair<View, String> p2 = Pair.create((View)holder.tvTitle, "title_1");
Pair<View, String> p3 = Pair.create((View)holder.tvBottom, "tv_bottom");
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(Activity_2.this, p1,p2,p3);
startActivity(intent,options.toBundle());
xml布局
<ImageView
android:id="@+id/img_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@mipmap/skid_right_1"
android:transitionName="img_view_1" />
<ImageView
android:id="@+id/img_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:scaleType="centerCrop"
android:transitionName="img_view_1" />
27.RecyclerView的getViewForPosition和getChildAt區(qū)別
- getViewForPosition(
RecyclerView
的方法)
獲取的是RecyclerView
順序的子元素伟恶。 - getChildAt (
ViewGroup
的方法)
獲取的是子View
疊加出現(xiàn)的順序。
例如毅该,一個(gè)疊加顯示的
RecyclerView
(最上層顯示第1個(gè)子View)博秫,它的getViewForPosition(0)
返回的是最上層的View,而getChildAt(0)
返回的是最下層的子View眶掌,它只與顯示的層級(jí)有關(guān)挡育,和RecyclerView
的順序無關(guān)。
28.伸縮效果的EditText
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="年齡"
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
29.startActivityForResult的使用
說起來丟人朴爬,真丟人即寒,這個(gè)我竟然搞混了!!蒿叠!不記下來不行
Activity1.class
Intent intent = new Intent(Activity1.this, Activity2.class);
startActivityForResult(intent, 1);
//返回接收處理
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
Activity2.class
Intent i = new Intent();
setResult(1, i);
finish();
說一下搞混的內(nèi)容:
- 1.Activity2中的Intent明垢,不需要設(shè)置具體的Class。
- 2.
setResult
語句不會(huì)直接返回市咽!不會(huì)返回痊银!不會(huì)返回,我竟然記成了它會(huì)直接返回 :( 施绎,需要調(diào)用finish()
手動(dòng)關(guān)閉當(dāng)前頁面溯革,然后會(huì)回調(diào)onActivityResult
。
30.PorterDuff.Mode
官方給出的是兩個(gè)w,h相同的Bitmap疊加的效果谷醉,而不是一個(gè)Bitamp中致稀,兩個(gè)圖形的疊加效果,正確的為:
黃色的圓先畫俱尼,藍(lán)色的方塊后畫抖单。
https://blog.csdn.net/u013085697/article/details/52096703
31.Fragment通信
-
Fragment與Activity間通信
①Activity向Fragment發(fā)送信息(通過setArguments(Bundle)
)
Activity.class
FragmentTransaction transaction = mManager.beginTransaction();
RightFragment fragment = new RightFragment();
//創(chuàng)建Bundle對象
Bundle bundle = new Bundle();
//向Bundle輸入數(shù)據(jù)
bundle.putInt("data", 100);
//對fragment設(shè)置Bundle參數(shù)
fragment.setArguments(bundle);
transaction.replace(R.id.fl_content, fragment);
transaction.commit();
Fragment.class
Bundle bundle = getArguments();
當(dāng)然也可以通過接口的方式實(shí)現(xiàn)。
②Fragment向Activity發(fā)送信息
Fragment.class
//強(qiáng)制轉(zhuǎn)換為當(dāng)前Activity對象后遇八,直接調(diào)用它的方法
((MainActivity)getActivity()).test(String sss);
Activity.class
public void test(String s){
Toast.makeText(this,s,Toast.LENGTH_LONG).show();
}
這種方式簡單粗暴矛绘,你也可以自己定義接口,如下:
Interface.class
public interface Listener {
void setText(String s);
}
Activity.class
public class MainActivity extends AppCompatActivity implements Listener {
... ...
@Override
public void setText(String s){
Toast.makeText(this,s,Toast.LENGTH_LONG).show();
}
}
Fragment.class
((Listener)getActivity()).setText(String sss);
-
Fragment與Fragment間通信
Fragment之間是不能直接通信的刃永,需要Activity來協(xié)助货矮。
Fragment1 -> Activity ->Fragment2
比如一個(gè)Activity有兩個(gè)Fragment,點(diǎn)擊左側(cè)Fragment1的按鈕斯够,右側(cè)Fragment2會(huì)變色囚玫。
Fragment1.class
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((MainActivity)getActivity()).setColor(red);
}
}
MainActivity.class
public void setColor(int color){
FragmentManager fm = getSupportFragmentManager();
fragment2 = fm.findFragmentByTag("fragment2");
fragment2.setColorChange(color);
}
Fragment2.class
private void setColorChange(int color){
layout.setBackgroundColor(color);
}
32.GreenDao的使用
在工程的build.gradle中添加
dependencies {
... ...
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
}
在項(xiàng)目的build.gradle中添加
apply plugin: 'org.greenrobot.greendao'
android {
... ...
greendao {
//版本號(hào),升級(jí)時(shí)可配置
schemaVersion 1
//dao的包名读规,包名默認(rèn)是entity所在的包
daoPackage 'com.example.common.dao'
//生成數(shù)據(jù)庫文件的目錄
targetGenDir 'src/main/java'
}
}
dependencies {
... ...
api 'org.greenrobot:greendao:3.2.2'
}
BaseApplication.class
public class BaseApplication extends Application {
private static DaoSession mDaoSession;
@Override
public void onCreate() {
super.onCreate();
initGreenDao();
}
private void initGreenDao() {
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, "lk.db", null);
SQLiteDatabase sqLiteDatabase = devOpenHelper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(sqLiteDatabase);
mDaoSession = daoMaster.newSession();
}
public static DaoSession getDaoSession() {
return mDaoSession;
}
}
注意:如果不先創(chuàng)建相關(guān)Bean類的情況下抓督,是找不到DaoMaster相關(guān)的!J鳌本昏!
工具類
public class GdUserUtil {
private static GdUserDao getDao() {
DaoSession session = BaseApplication.getDaoSession();
GdUserDao dao = session.getGdUserDao();
return dao;
}
public static List<GdUser> queryAllData() {
return getDao().loadAll();
}
public static List<GdUser> queryData(String name) {
return getDao().queryBuilder().where(GdUserDao.Properties.Name.eq(name)).list();
}
public static void insertData(GdUser user) {
getDao().insert(user);
}
public static void removeData(GdUser user) {
getDao().delete(user);
}
public static void removeData(Long key) {
getDao().deleteByKey(key);
}
public static void updateData(GdUser user) {
getDao().update(user);
}
}
報(bào)錯(cuò):android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: GD_USER._id
GdUser.class
@Entity
public class GdUser {
@Id(autoincrement = true)
private long id;
private String name;
private String age;
}
錯(cuò)誤原因就是。枪汪。涌穆。別打我:) 。雀久。宿稀。 id的類型必須設(shè)置為Long
,大寫的L赖捌,是包裝類祝沸,不是基本數(shù)據(jù)類型矮烹,一定要注意。
官方給出的答案是:支持的最小gradle是2.3.2罩锐。
Please update your Android Gradle Plugin to 2.3.2 (com.android.tools.build:gradle:2.3.2). Version 2.2.x is not supported.
33. Handler內(nèi)存溢出問題
在Handler消息隊(duì)列 還有未處理的消息 / 正在處理消息時(shí)奉狈,此時(shí)若需銷毀外部類MainActivity,但由于上述引用關(guān)系涩惑,垃圾回收器(GC)無法回收MainActivity仁期,從而造成內(nèi)存泄漏。
解決方法:
private static class MyHandler extends Handler{
// 定義 弱引用實(shí)例
private WeakReference<Activity> reference;
// 在構(gòu)造方法中傳入需持有的Activity實(shí)例
public FHandler(Activity activity) {
// 使用WeakReference弱引用持有Activity實(shí)例
reference = new WeakReference<Activity>(activity);
}
// 通過復(fù)寫handlerMessage() 從而確定更新UI的操作
@Override
public void handleMessage(Message msg) {
Activity activity = reference.get();
if(activity != null){
... ...
}
}
}
注意:handler.postDelayed()
無法防止內(nèi)存溢出竭恬,最好使用sendMessage
這種形式跛蛋。
PS:當(dāng)可能出現(xiàn)Handler內(nèi)存溢出時(shí),AS會(huì)提示痊硕。赊级。。
34.new Handler()和new Handler(Looper.getMainLooper())區(qū)別
如果你不帶參數(shù)的實(shí)例化:
Handler handler = new Handler();
會(huì)默認(rèn)用當(dāng)前線程的Looper對象岔绸。
一般而言理逊,如果你的Handler是要用來刷新UI的,那么就需要在主線程下運(yùn)行盒揉。
情況:
刷新UI晋被,handler要用到主線程的Looper對象。那么在主線程
Handler handler=new Handler();
如果在其他非主線程也要滿足這個(gè)功能的話预烙,要Handler handler=new Handler(Looper.getMainLooper());
不用刷新UI,只是處理消息道媚。當(dāng)前消息如果是主線程的話扁掸,
Handler handler=new Handler();
;非主線程的話最域,Looper.prepare(); Handler handler=new Handler();Looper.loop()
或者Handler handler=new Handle(Looper.getMainLooper());
若是實(shí)例化的時(shí)候調(diào)用Looper.getMainLooper()
就表示放到主線程中去處理谴分;若有不是的話,UI 線程默認(rèn)執(zhí)行過Loop.prepare()
和Loop.loop()
镀脂,其他線程需要手動(dòng)調(diào)用這兩個(gè)牺蹄。否則會(huì)報(bào)錯(cuò)。
35.ImageView.ScaleType設(shè)置圖解
- android:scaleType=“center”
保持原圖的大小薄翅,顯示在ImageView的中心沙兰。當(dāng)原圖的size大于ImageView的size時(shí),多出來的部分被截掉翘魄。 - android:scaleType=“center_inside”
以原圖正常顯示為目的鼎天,如果原圖大小大于ImageView的size,就按照比例縮小原圖的寬高暑竟,居中顯示在ImageView中斋射。如果原圖size小于ImageView的size,則不做處理居中顯示圖片。 - android:scaleType=“center_crop”
以原圖填滿ImageView為目的罗岖,如果原圖size大于ImageView的size涧至,則與center_inside一樣,按比例縮小桑包,直到寬或高等于ImageView的size南蓬,其余部分裁剪,居中填充滿顯示在ImageView上捡多。如果原圖size小于ImageView的size蓖康,則按比例拉升原圖的寬和高,直到寬或高等于ImageView的size垒手,其余部分裁剪蒜焊,填充滿ImageView居中顯示。 - android:scaleType=“matrix”
不改變原圖的大小科贬,從ImageView的左上角開始繪制泳梆,超出部分做剪切處理。 - androd:scaleType=“fit_xy”
把圖片按照指定的大小在ImageView中顯示榜掌,拉伸顯示圖片优妙,不保持原比例,填滿ImageView. - android:scaleType=“fit_start”
把原圖按照比例放大縮小到ImageView的高度憎账,顯示在ImageView的start(前部/上部)套硼。 - android:sacleType=“fit_center”
把原圖按照比例放大縮小到ImageView的高度,顯示在ImageView的center(中部/居中顯示)胞皱。 - android:scaleType=“fit_end”
把原圖按照比例放大縮小到ImageView的高度邪意,顯示在ImageVIew的end(后部/尾部/底部)
https://blog.csdn.net/larryl2003/article/details/6919513
https://blog.csdn.net/u012702547/article/details/50586946
36.getRawX和getX區(qū)別
37.WindowManager添加控件顯示懸浮框時(shí)遇到的問題
- 1.默認(rèn)控件顯示的位置是正中間,這是因?yàn)橹虚g的坐標(biāo)為(0反砌,0)雾鬼。
- 2.
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
不設(shè)置的話,懸浮框始終獲取焦點(diǎn)宴树,此時(shí)無法操作策菜,桌面都回不到了。 - 3.作touch設(shè)置時(shí)酒贬,要使用down和move的getRawX/Y的差值+lp.x/y又憨,不能直接使用getRawX/Y,因?yàn)榇藭r(shí)屏幕的左上角不是原點(diǎn)锭吨。
38.View的位置坐標(biāo)
View 提供了如下 5 種方法獲取 View 的坐標(biāo):
- View.getTop()竟块、View.getLeft()、View.getBottom()耐齐、View.getRight();
- View.getX()浪秘、View.getY();
- View.getTranslationX()蒋情、View.getTranslationY();
- View.getLocationOnScreen(int[] position);
- View.getLocationInWindow(int[] position);
1. View.getTop()、View.getLeft()耸携、View.getBottom()棵癣、View.getRight()
2. View.getX()河劝、View.getY()
getX()與getY()方法獲取的是View左上角相對于父容器的坐標(biāo),當(dāng)View沒有發(fā)生平移操作時(shí)矛紫,getX()==getLeft()
赎瞎、getY==getTop()
。
3. View.getTranslationX()颊咬、View.getTranslationY()
translationX
與 translationY
是View左上角相對于父容器的偏移量:translationX = getX() - getLeft()
,當(dāng)View未發(fā)生平移操作時(shí)务甥,translationX
與translationY
都為0。
4. getLocationOnScreen
獲取View相對于整個(gè)屏幕的坐標(biāo)喳篇。
5. getLocationInWindow
獲取View相對于Window的坐標(biāo)(忽略狀態(tài)欄及ActionBar)敞临。
其中,
getLocationInWindow
是以B為原點(diǎn)的C的坐標(biāo)其中麸澜,
getLocationOnScreen
是以A為原點(diǎn)的C的坐標(biāo)
39.Activity的構(gòu)造方法
正如《Android Activity的啟動(dòng)和跳轉(zhuǎn)》一文所說,在Android APP中啟動(dòng)一個(gè)Activity都是通過startActivity()或startActivityForResult()來實(shí)現(xiàn)炊邦,并不會(huì)直接在APP代碼中new一個(gè)Activity對象來使用编矾,直接new出來的Activity對象是無法使用的。一般來說我們在實(shí)現(xiàn)一個(gè)Activity類時(shí)會(huì)將初始化的一些操作放到onCreate()中執(zhí)行铣耘,并不會(huì)實(shí)現(xiàn)其構(gòu)造方法洽沟。但是這并不是說Activity類沒有構(gòu)造方法以故,或者構(gòu)造方法不會(huì)被調(diào)用蜗细。
事實(shí)上,調(diào)用startActivity()或startActivityForResult()之后怒详,Android框架中的代碼會(huì)完成Activity對象的創(chuàng)建炉媒。在創(chuàng)建Activity對象時(shí)仍然會(huì)執(zhí)行Activity類的構(gòu)造方法。
在android.app.Instrumentation類中有一個(gè)newActivity方法昆烁。Android框架正是通過此方法來創(chuàng)建一個(gè)Activity對象的吊骤。其代碼如下。
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
可以看到静尼,這里通過ClassLoader的loadClass()方法來加載指定的Activity類白粉,得到對應(yīng)的Class對象传泊,然后再調(diào)用Class對象的newInstance()方法創(chuàng)建Activity對象。
由于Class對象的newInstance()方法在創(chuàng)建對象時(shí)會(huì)調(diào)用該類的無參構(gòu)造方法鸭巴,因此眷细,如果確實(shí)需要在Activity構(gòu)造的時(shí)候執(zhí)行一些操作,可以在這個(gè)Activity類中增加一個(gè)無參的構(gòu)造方法鹃祖,這個(gè)構(gòu)造方法會(huì)在newInstance()時(shí)被自動(dòng)調(diào)用溪椎。
這里有兩點(diǎn)需要注意:
- 一個(gè)Activity類中只有無參的構(gòu)造方法會(huì)被執(zhí)行,定義有參數(shù)的構(gòu)造方法是沒有意義的恬口。
- 一個(gè)Activity類中如果沒有無參構(gòu)造方法校读,或者無參構(gòu)造方法不是public的,則在執(zhí)行newInstance()的時(shí)候會(huì)產(chǎn)生異常祖能。
40.scrollTo 和scrollBy 相關(guān)問題
- 每一個(gè)View中歉秫,系統(tǒng)都提供了
scrollTo
、scrollBy
兩種方式來改變一個(gè)View的位置芯杀。這兩個(gè)方法的區(qū)別非常好理解端考,與英文中To與By的區(qū)別類似,scrollTo(x, y)
標(biāo)識(shí)移動(dòng)到一個(gè)具體的坐標(biāo)點(diǎn)(x, y)揭厚,而scrollBy(dx, dy)
表示移動(dòng)的增量為dx却特、dy。
但是筛圆,當(dāng)我們拖動(dòng)View的時(shí)候裂明,你會(huì)發(fā)現(xiàn)View并沒有移動(dòng)!難道是我們方法寫錯(cuò)了嗎太援?其實(shí)闽晦,方法并沒有寫錯(cuò),View也確實(shí)移動(dòng)了提岔,只是它移動(dòng)的并不是我們想要移動(dòng)的東西仙蛉。
scrollTo
、scrollBy
方法移動(dòng)的是View的content碱蒙,即讓View的內(nèi)容移動(dòng)荠瘪,如果在ViewGroup
中使用scrollTo
、scrollBy
方法赛惩,那么移動(dòng)的將是所有子View哀墓,但如果在View中使用,那么移動(dòng)的將是View的內(nèi)容喷兼,例如TextView
篮绰,content就是它的文本;ImageView
季惯,content就是它的drawable對象吠各。
相信通過上面的分析臀突,應(yīng)該知道為什么不能再View中使用這兩個(gè)方法來拖動(dòng)這個(gè)View了。那么我們就該View所有的ViewGroup中來使用scrollBy
方法贾漏,移動(dòng)它的子View惧辈,代碼如下所示:
((View) getParent()).scrollBy(-offsetX,-offsetY);
注意:滾動(dòng)的正負(fù)號(hào)?拇伞:谐荨!@场(向上滾動(dòng)-offsetY边翁,向左滾動(dòng)-offsetX)
41.底部彈窗
1.PopupWindow實(shí)現(xiàn)底部彈窗
2.dialog實(shí)現(xiàn)底部彈窗
3.dialogFragment實(shí)現(xiàn)底部彈窗
4.BottomSheetDialog實(shí)現(xiàn)底部彈窗
http://www.reibang.com/p/8292fdbc4c2b
42.Activity動(dòng)畫
- 使用 style 的方式定義 Activity 的切換動(dòng)畫
- 使用 overridePendingTransition 方法實(shí)現(xiàn) Activity 跳轉(zhuǎn)動(dòng)畫
- 使用 ActivityOptions 切換動(dòng)畫實(shí)現(xiàn) Activity 跳轉(zhuǎn)動(dòng)畫(部分動(dòng)畫可支持到 api >= 16)
- 使用 ActivityOptions 動(dòng)畫共享組件的方式實(shí)現(xiàn)跳轉(zhuǎn) Activity 動(dòng)畫(api >= 21)
overridePendingTransition方法必須在startActivity的后面或者finish()之后被調(diào)用才生效。
43.PriorityQueue優(yōu)先級(jí)隊(duì)列
PriorityQueue<BundleProxy> bundleQueue = new PriorityQueue<>(
10,
new Comparator<BundleProxy>() {
@Override
public int compare(BundleProxy o1, BundleProxy o2) {
return o2.getConfig().p.value() - o1.getConfig().p.value();
}
}
);
44.RecyclerView獲取滾動(dòng)距離
僅限于LinearLayout
public int getScollYDistance() {
LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
int position = layoutManager.findFirstVisibleItemPosition();
View firstVisiableChildView = layoutManager.findViewByPosition(position);
int itemHeight = firstVisiableChildView.getHeight();
return (position) * itemHeight - firstVisiableChildView.getTop();
}