日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

带你梳理一遍 Android 核心知识

發(fā)布時間:2023/12/20 Android 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 带你梳理一遍 Android 核心知识 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文導讀|???點擊標題閱讀

互聯(lián)網(wǎng)寒冬下,程序員如何突圍提升自己?

Flutter 與 React Native 誰主沉浮?

女面試官:我拉鏈開了你怎么提醒我?

作者:薛定貓的諤

https://juejin.im/post/5c46db4ae51d4503834d8227

超長好文,建議慢慢品用,由于篇幅超越微信限制,略微有點刪減,不影響閱讀。


0、一句話知識點


1. Android 9 (API level 28) 開始廢棄了 Loader API,包括 LoaderManager 和 CursorLoader 等類的使用。推薦使用 ViewModel 和 LiveData 在 Activity 或 Fragment 生命周期中加載數(shù)據(jù);


2. Activity 可以通過 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) 保持屏幕常亮,這是最推薦、最簡單、最安全的保持屏幕常亮的方法,給 view 添加 android:keepScreenOn="true" 也是一樣的。


這個只在這個 Activity 生命周期內(nèi)有效,所以大可放心,如果想提前解除常亮,只需要清除這個 flag 即可。


3. WAKE_LOCK 可以阻止系統(tǒng)睡眠,保持 CPU 一直運行,需要 android.permission.WAKE_LOCK 權(quán)限。


通過 powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag") 創(chuàng)建實例


通過 wakeLock.acquire() 方法請求鎖,通過 wakelock.release() 釋放鎖


4.?WakefulBroadcastReceiver 結(jié)合 IntentService 也可以阻止系統(tǒng)睡眠;


5. Android 8.0 (API level 26) 開始支持自適應啟動圖標,自適應啟動圖標必須由前景和背景兩部分組成,尺寸必須都是 108 x 108 dp,其中內(nèi)部的 72 x 72 dp 用來顯示圖標,靠近四個邊緣的 18 dp 是保留區(qū)域,用來進行視覺交互


6. 對于字體大小自適應的 TextView 寬和高都不能是 wrap_content,autoSizeTextType 默認是 none,設(shè)置為 uniform 開啟自適應,默認最小 12sp,最大 112sp,粒度 1px。autoSizePresetSizes 屬性可以設(shè)置預置的一些大小


7. Android 8.0 (API level 26) 開始支持 XML 自定義字體,兼容庫可以兼容到 Android 4.1 (API level 16),字體文件路徑為 res/font/,使用屬性為 fontFamily,獲取 Typeface 為 getResources().getFont(R.font.myfont);,兼容庫使用 ResourcesCompat.getFont(context, R.font.myfont)


8. Android 9 (API level 28) 支持控件放大鏡功能,Magnifier 的 show() 方法的參數(shù)是相對于被放大 View 的左上角的坐標


9. 工程中的 Drawable 資源只能有一個狀態(tài),你不應該手動更改它的任何屬性,否則會影響到其它使用這個 Drawable 資源的地方


10. Android 7.0 (API level 24) 開始支持在 XML 文件中使用自定義 Drawable,公共頂級類使用全限定名作為標簽名即可 <com.myapp.MyDrawable>,公共靜態(tài)內(nèi)部類可以使用 class 屬性 class="com.myapp.MyTopLevelClass$MyDrawable"


11. Android 5.0 (API level 21) 開始支持為 Drawable 設(shè)置 tint


12. Android 5.0 (API level 21) 開始支持矢量圖,支持庫可以支持到 Android 2.1 (API level 7+),兼容低版本是需要 Gradle 插件版本大于 2.0+ 時添加 vectorDrawables.useSupportLibrary = true 并使用 VectorDrawableCompat 和 AnimatedVectorDrawableCompat


1、應用資源


1. 添加資源限定符的順序為:?


SIM 卡所屬的國家代碼和移動網(wǎng)代碼 → 語言區(qū)域代碼 → 布局方向 → 最小寬度 → 可用寬度 → 可用高度 → 屏幕大不大 → 屏幕長不長 → 屏幕圓不圓 → 屏幕色域?qū)挷粚?→ 屏幕支持的動態(tài)范圍高不高 → 屏幕方向 → 設(shè)備的 UI 模式 → 夜間模式 → 屏幕像素密度 → 觸摸屏類型 → 鍵盤類型 → 主要的文字輸入方式 ?→ 導航鍵是否可用 → 主要的非觸摸導航方式 → 支持的 API level


2. 一個資源目錄的每種資源限定符最多只能出現(xiàn)一次;


3. 必須提供缺省的資源文件;


4. 資源目錄名是大小寫不敏感的;


5. drawable 資源取別名:


<?xml?version="1.0"?encoding="utf-8"?><resources>????<drawable?name="icon">@drawable/icon_ca</drawable></resources>
<resources>
????<drawable?name="icon">@drawable/icon_ca</drawable>
</resources>

6.?布局文件取別名:


<?xml?version="1.0"?encoding="utf-8"?><merge>????<include?layout="@layout/main_ltr"/></merge>
<merge>
????<include?layout="@layout/main_ltr"/>
</merge>


只有動畫、菜單、raw 資源 以及 xml/ 目錄中的資源不能使用別名


7. 尋找使用最優(yōu)資源的流程:



8. 在應用程序運行時,設(shè)備的配置可能會發(fā)生變化(如屏幕方向變化、切換到多窗口模式,切換了系統(tǒng)語言),默認情況下系統(tǒng)會銷毀重建正在運行的 Activity ,所以應用程序必須保證銷毀重建的過程中用戶的數(shù)據(jù)和頁面狀態(tài)完好無損地恢復。


如果不想系統(tǒng)銷毀重建你的 Activity 只需要在 manifest 文件的 <activity> 標簽的 android:configChanges 屬性中添加你想自己處理的配置更改,多個配置使用 "|" 隔開,此時系統(tǒng)就不會在這些配置更改后銷毀重建你的這個 Activity 而是直接調(diào)用它的 onConfigurationChanged() 回調(diào)方法,你需要在這個回調(diào)中自己處理配置更改后的行為。


9. Activity 的銷毀重建不但發(fā)生在設(shè)備配置更改后,只要用戶離開了某個 Activity,那么那個 Activity 就隨時可能被系統(tǒng)銷毀。所以銷毀重建是無法避免的,也不應該逃避,而是應該想辦法保存和恢復狀態(tài)


10. 由于各種各樣的硬件都能安裝 Android 操作系統(tǒng),Android 操作系統(tǒng)之間也可能千差萬別,而應用程序的一些功能是與這些軟硬件息息相關(guān)的,如拍照應用需要設(shè)備必須有攝像頭才能正常工作。


應用可以通過 <uses-feature> 標簽聲明只有滿足這些軟硬件要求的設(shè)備才能安裝,通過它的 android:required 屬性設(shè)置該要求是不是必須的,程序中可以通過 PackageManager.hasSystemFeature() 方法判斷.

2、動態(tài)申請權(quán)限


1. Android 6.0 (API level 23) 開始 targetSdkVersion >= 23 的應用必須在運行時動態(tài)申請權(quán)限


2. 權(quán)限請求對話框是操作系統(tǒng)進行管理的,應用無法也不應該干預。


3. 系統(tǒng)對話框描述的是權(quán)限組而不是某個具體權(quán)限


4. 調(diào)用 requestPermissions() 并不意味著系統(tǒng)一定會彈出權(quán)限請求對話框,也就是說不能假設(shè)調(diào)用該方法后就發(fā)生了用戶交互,因為如果用戶之前勾選了 “禁止后不再詢問” 或者系統(tǒng)策略禁止應用獲取權(quán)限,那么系統(tǒng)會直接拒絕此次權(quán)限請求,沒有任何交互


5. 如果某個權(quán)限跟應用的主要功能無關(guān),如應用中廣告可能需要位置權(quán)限,用戶可能很費解,此時在申請權(quán)限之前彈出對話框向用戶解釋為什么需要這個權(quán)限是個不錯的選擇。但不要在所有申請權(quán)限之前都彈出對話框解釋,因為頻繁地打斷用戶的操作或讓用戶進行選擇容易讓用戶不耐煩


6. Fragment 中的 onRequestPermissionsResult() 方法只有在使用 Fragment#requestPermissions() 方法申請權(quán)限時才可能接收到回調(diào),建議將權(quán)限放在所屬 Activity 中申請和處理


7. 應用應該盡量少地申請權(quán)限,像讓用戶拍一張照片或者選擇一張圖片完全不需要相機權(quán)限和外存權(quán)限,可以通過隱式 Intent 拉起系統(tǒng)相機或其他應用完成,應用只需要在 onActivityResult() 回調(diào)中接收數(shù)據(jù)就行了。但是有一點一定要注意,如果你在 AndroidManifest.xml 文件中聲明了相機權(quán)限,你就必須得動態(tài)申請并獲得相機權(quán)限才能拉起系統(tǒng)相機.


//?請求通訊錄權(quán)限的模板代碼如下private?void?showContactsWithPermissionsCheck()?{????if?(ContextCompat.checkSelfPermission(MainActivity.this,????????????Manifest.permission.READ_CONTACTS)????????????!=?PackageManager.PERMISSION_GRANTED)?{????????if?(ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,????????????????Manifest.permission.READ_CONTACTS))?{????????????//?TODO:?彈框解釋為什么需要這個權(quán)限.?【下一步】?->?再次請求權(quán)限????????}?else?{????????????ActivityCompat.requestPermissions(MainActivity.this,????????????????????new?String[]{Manifest.permission.READ_CONTACTS},????????????????????RC_CONTACTS);????????}????}?else?{????????showContacts();????}}private?void?showContacts()?{????startActivity(ContactsActivity.getIntent(MainActivity.this));}@Overridepublic?void?onRequestPermissionsResult(int?requestCode,?@NonNull?String[]?permissions,???????????????????????????????????????@NonNull?int[]?grantResults)?{????super.onRequestPermissionsResult(requestCode,?permissions,?grantResults);????switch?(requestCode)?{????????case?RC_CONTACTS:????????????if?(grantResults.length?>?0????????????????????&&?grantResults[0]?==?PackageManager.PERMISSION_GRANTED)?{????????????????showContacts();????????????}?else?{????????????????if?(!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,????????????????????????Manifest.permission.READ_CONTACTS))?{????????????????????//?TODO:?彈框引導用戶去設(shè)置頁主動授予該權(quán)限.?【去設(shè)置】?->?應用信息頁????????????????}?else?{????????????????????//?TODO:?彈框解釋為什么需要這個權(quán)限.?【下一步】?->?再次請求權(quán)限????????????????}????????????}????????????break;????????default:????????????break;????}}@Overrideprotected?void?onActivityResult(int?requestCode,?int?resultCode,?@Nullable?Intent?data)?{????super.onActivityResult(requestCode,?resultCode,?data);????if?(requestCode?==?RC_SETTINGS)?{????????//?TODO:?在用戶主動授予權(quán)限后重新檢查權(quán)限,但不要在這里進行事務(wù)提交等生命周期敏感操作????}}
private?void?showContactsWithPermissionsCheck()?{
????if?(ContextCompat.checkSelfPermission(MainActivity.this,
????????????Manifest.permission.READ_CONTACTS)
????????????!=?PackageManager.PERMISSION_GRANTED)?{
????????if?(ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
????????????????Manifest.permission.READ_CONTACTS))?{
????????????//?TODO:?彈框解釋為什么需要這個權(quán)限.?【下一步】?->?再次請求權(quán)限
????????}?else?{
????????????ActivityCompat.requestPermissions(MainActivity.this,
????????????????????new?String[]{Manifest.permission.READ_CONTACTS},
????????????????????RC_CONTACTS);
????????}
????}?else?{
????????showContacts();
????}
}
private?void?showContacts()?{
????startActivity(ContactsActivity.getIntent(MainActivity.this));
}
@Override
public?void?onRequestPermissionsResult(int?requestCode,?@NonNull?String[]?permissions,
???????????????????????????????????????@NonNull?int[]?grantResults)
?
{
????super.onRequestPermissionsResult(requestCode,?permissions,?grantResults);
????switch?(requestCode)?{
????????case?RC_CONTACTS:
????????????if?(grantResults.length?>?0
????????????????????&&?grantResults[0]?==?PackageManager.PERMISSION_GRANTED)?{
????????????????showContacts();
????????????}?else?{
????????????????if?(!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
????????????????????????Manifest.permission.READ_CONTACTS))?{
????????????????????//?TODO:?彈框引導用戶去設(shè)置頁主動授予該權(quán)限.?【去設(shè)置】?->?應用信息頁
????????????????}?else?{
????????????????????//?TODO:?彈框解釋為什么需要這個權(quán)限.?【下一步】?->?再次請求權(quán)限
????????????????}
????????????}
????????????break;
????????default:
????????????break;
????}
}
@Override
protected?void?onActivityResult(int?requestCode,?int?resultCode,?@Nullable?Intent?data)?{
????super.onActivityResult(requestCode,?resultCode,?data);
????if?(requestCode?==?RC_SETTINGS)?{
????????//?TODO:?在用戶主動授予權(quán)限后重新檢查權(quán)限,但不要在這里進行事務(wù)提交等生命周期敏感操作
????}
}


注意看上述代碼中TODO標識。

3、Shortcut


1. 類似于 iOS 的 3D Touch,長按啟動圖標彈出幾個快捷入口,入口最好不要超過 4 個,像搜索、掃描二維碼、發(fā)帖等應用程序最常用功能的入口被稱為靜態(tài) shortcut,不會隨著用戶不同或隨著用戶使用而改變。


還有一種像從某個存檔點繼續(xù)游戲、任務(wù)進度等與用戶相關(guān)的上下文敏感入口被稱為動態(tài) shortcut,會因用戶不同或隨著用戶使用不斷變化。還有一種在 Android 8.0 (API level 26) 及以上系統(tǒng)版本上像固定網(wǎng)頁標簽等用戶主動固定到桌面的快捷方式被稱為固定 shortcut


2. 靜態(tài) shortcut 系統(tǒng)可以自動備份和恢復,動態(tài) shortcut 需要應用自己備份和恢復,固定 shortcut 的圖標系統(tǒng)無法備份和恢復因此需要應用自己完成


3. android:shortcutId 和 android:shortcutShortLabel 屬性是必須的,android:shortcutShortLabel 不能超過 10 個字符,android:shortcutLongLabel 不能超過 25 個字符,android:icon 不能包含 tint


4. 獲取 ShortcutManager 的方式有兩個: getSystemService(ShortcutManager.class) 和 getSystemService(Context.SHORTCUT_SERVICE)


5. 創(chuàng)建固定 shortcut:


ShortcutManager?mShortcutManager?=????????context.getSystemService(ShortcutManager.class);if?(mShortcutManager.isRequestPinShortcutSupported())?{????ShortcutInfo?pinShortcutInfo?=????????????new?ShortcutInfo.Builder(context,?"my-shortcut").build();????Intent?pinnedShortcutCallbackIntent?=????????????mShortcutManager.createShortcutResultIntent(pinShortcutInfo);????PendingIntent?successCallback?=?PendingIntent.getBroadcast(context,?0,????????????pinnedShortcutCallbackIntent,?0);????mShortcutManager.requestPinShortcut(pinShortcutInfo,????????????successCallback.getIntentSender());}class);
if?(mShortcutManager.isRequestPinShortcutSupported())?{
????ShortcutInfo?pinShortcutInfo?=
????????????new?ShortcutInfo.Builder(context,?"my-shortcut").build();
????Intent?pinnedShortcutCallbackIntent?=
????????????mShortcutManager.createShortcutResultIntent(pinShortcutInfo);
????PendingIntent?successCallback?=?PendingIntent.getBroadcast(context,?0,
????????????pinnedShortcutCallbackIntent,?0);
????mShortcutManager.requestPinShortcut(pinShortcutInfo,
????????????successCallback.getIntentSender());
}

4、系統(tǒng)欄適配


1. Android 4.1 (API level 16) 開始可以通過 setSystemUiVisibility() 方法在各個 view 層次中(一般是在 DecorView 中)配置 UI flag 實現(xiàn)系統(tǒng)欄(狀態(tài)欄、導航欄統(tǒng)稱)配置,最終匯總體現(xiàn)到 window 級


2.?View.SYSTEM_UI_FLAG_FULLSCREEN 可以隱藏狀態(tài)欄,View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 可以隱藏導航欄。但是: 用戶的任何交互包括觸摸屏幕都會導致 flag 被清除進而系統(tǒng)欄保持可見,一旦離開當前 Activity flag 就會被清除,所以如果在 onCreate() 方法中設(shè)置了這個 flag 那么按 HOME 鍵再回來狀態(tài)欄又保持可見了。


非要這樣設(shè)置的話一般要放在 onResume() ?或 onWindowFocusChanged() 方法中,而且這樣設(shè)置只有在目標 View 可見時才會生效,狀態(tài)欄/導航欄的顯示隱藏會導致顯示內(nèi)容的大小尺寸跟著變化。



3. View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 可以讓內(nèi)容顯示在狀態(tài)欄后面,View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 可以讓內(nèi)容顯示在導航欄后面,這樣無論系統(tǒng)欄顯示還是隱藏內(nèi)容都不會跟著變化。


但不要讓可交互的內(nèi)容出現(xiàn)在系統(tǒng)欄區(qū)域內(nèi),通過將 android:fitsSystemWindows 屬性設(shè)置為 true 可以讓父容器調(diào)整 padding 以便為系統(tǒng)欄留出空間,如果想自定義這個 padding 可以通過覆寫 View 的 fitSystemWindows(Rect insets) 方法(API level 20 以上覆寫 onApplyWindowInsets(WindowInsets insets) 方法)完成


4. lean back 全屏模式: View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION,隱藏狀態(tài)欄和導航欄,任何交互都會清除 flag 使系統(tǒng)欄保持可見


5. Immersive 全屏模式: View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION,隱藏狀態(tài)欄和導航欄,從被隱藏的系統(tǒng)欄邊緣向內(nèi)滑動會使系統(tǒng)欄保持可見,應用無法響應這個手勢


6. sticky immersive 全屏模式: View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION,隱藏狀態(tài)欄和導航欄,從被隱藏的系統(tǒng)欄邊緣向內(nèi)滑動會使系統(tǒng)欄暫時可見,flag 不會被清除,且系統(tǒng)欄的背景是半透明的,會覆蓋應用的內(nèi)容,應用也可以響應這個手勢,在用戶沒有任何交互或者沒有系統(tǒng)欄交互幾秒鐘后系統(tǒng)欄會自動隱藏


7. 真正的沉浸式全屏體驗需要 6 個 flag:?


View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |?

View.SYSTEM_UI_FLAG_LAYOUT_STABLE |?

View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |?

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |?

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |?

View.SYSTEM_UI_FLAG_FULLSCREEN


8. 監(jiān)聽系統(tǒng)欄可見性(sticky immersive 全屏模式無法監(jiān)聽):


decorView.setOnSystemUiVisibilityChangeListener(new?View.OnSystemUiVisibilityChangeListener()?{????@Override????public?void?onSystemUiVisibilityChange(int?visibility)?{????????if?((visibility?&?View.SYSTEM_UI_FLAG_FULLSCREEN)?==?0)?{????????????//?TODO:?The?system?bars?are?visible.?Make?any?desired????????}?else?{????????????//?TODO:?The?system?bars?are?NOT?visible.?Make?any?desired????????}????}});
????@Override
????public?void?onSystemUiVisibilityChange(int?visibility)?{
????????if?((visibility?&?View.SYSTEM_UI_FLAG_FULLSCREEN)?==?0)?{
????????????//?TODO:?The?system?bars?are?visible.?Make?any?desired
????????}?else?{
????????????//?TODO:?The?system?bars?are?NOT?visible.?Make?any?desired
????????}
????}
});


9. 全面屏適配只需要指定支持的最大寬高比即可:?


<meta-data android:name="android.max_aspect" android:value="2.4"/>


10. Android 9 (API level 28) 開始支持劉海屏 cutout 的配置,window 的屬性 layoutInDisplayCutoutMode 默認是 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,豎屏時可以渲染到劉海區(qū),橫屏時不允許渲染到劉海區(qū)。


LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 橫豎屏都可以渲染到劉海區(qū)。


LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 橫豎屏都不允許渲染到劉海區(qū),可以在 values-v28/styles.xml 文件中通過 android:windowLayoutInDisplayCutoutMode 指定默認的劉海區(qū)渲染模式


11. 華為手機通過 <meta-data android:name="android.notch_support" android:value="true" /> 屬性聲明應用是否已經(jīng)適配了劉海屏,如果沒適配,那么在橫屏或者豎屏不顯示狀態(tài)欄時會禁止渲染到劉海區(qū),可以參考: 《華為劉海屏手機安卓O版本適配指導》。


12. 小米手機通過 <meta-data android:name="notch.config" android:value="portrait|landscape" /> 設(shè)置默認的劉海區(qū)渲染模式,開發(fā)者文檔:?


小米劉海屏 Android O 適配

https://dev.mi.com/console/doc/detail?pId=1293


小米劉海屏 Android P 適配?

https://dev.mi.com/console/doc/detail?pId=1341


13. 其他手機的開發(fā)者文檔有: OPPO 手機的?


OPPO凹形屏適配說明

https://open.oppomobile.com/wiki/doc#id=10159


VIVO 手機的?

異形屏應用適配指南?https://dev.vivo.com.cn/documentCenter/doc/103


錘子手機的

Smartisan 開發(fā)者文檔https://resource.smartisan.com/resource/61263ed9599961d1191cc4381943b47a.pdf


14. Android 5.0 (API level 21) 開始支持通過 window 的 setStatusBarColor() 方法設(shè)置狀態(tài)欄背景色,要求 window 必須添加 WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 的 flag 并且清除 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS 的 flag


15. Android 6.0 (API level 23) 開始可以通過 setSystemUiVisibility() 方法設(shè)置 View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR flag 兼容亮色背景的狀態(tài)欄,同樣要求 window 必須添加 WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 的 flag 并且清除 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS 的 flag


16. 小米手機在 MIUI 開發(fā)版 7.7.13 之前需要通過反射兼容亮色背景的狀態(tài)欄,開發(fā)者文檔:《MIUI 9 & 10“狀態(tài)欄黑色字符”實現(xiàn)方法變更通知》

https://dev.mi.com/console/doc/detail?pId=1159


17. 魅族手機同樣需要通過反射兼容亮色背景的狀態(tài)欄,開發(fā)者文檔:?

《狀態(tài)欄變色》

http://open-wiki.flyme.cn/doc-wiki/index#id?79


5、動畫


view 動畫系統(tǒng)只能作用于 view 對象,只能改變 view 的部分樣式,只是簡單改變了 view 繪制,并沒有改變 view 真正的位置和屬性。核心類是 android.view.animation.Animation 和它的 ScaleAnimation 等子類,一般使用 AnimationUtils.loadAnimation() 方法加載。不建議使用,除非為了方便又能滿足現(xiàn)在和將來的需求


1. 屬性動畫系統(tǒng)是一個健壯的、優(yōu)雅的動畫系統(tǒng),可以對任意對象的屬性做動畫。核心類是 android.animation.Animator 的子類 ValueAnimator、ObjectAnimator、AnimatorSet


2. 通過調(diào)用 ValueAnimator 的 ofInt()、ofFloat() 等工廠方法獲取 ValueAnimator 對象,通過它的 addUpdateListener() 方法可以監(jiān)聽動畫值并在里面進行自定義操作


3. ObjectAnimator 作為 ValueAnimator 的子類可以自動地為目標對象的命名屬性設(shè)置動畫,但是對目標對象有嚴格的要求: 目標對象必須有對應屬性的 setter 方法,如果在工廠方法中只提供了一個動畫值那么它會作為終止值,起始值為目標對象的當前值,此時為了獲取當前屬性值目標對象必須有對應屬性的 getter 方法。有些屬性的更改不會導致 view 重新渲染,此時需要主動調(diào)用 invalidate() 方法強制觸發(fā)重繪


4. AnimatorListenerAdapter 提供了 Animator.AnimatorListener 接口的空實現(xiàn)


5. 多數(shù)情況下可以直接使用系統(tǒng)提供的幾個動畫 duration,如 getResources().getInteger(android.R.integer.config_shortAnimTime)


6. 可以調(diào)用任意 view 對象的 animate() 方法獲取 ViewPropertyAnimator 對象,鏈式調(diào)用這個對象的 scaleX()、alpha() 等方法可以簡單方便地同時對 view 的多個屬性做動畫


7. 為了更好地重用和管理屬性動畫,最好使用 XML 文件來描述動畫并放到 res/animator/ 目錄下,ValueAnimator 對應 <animator> ,ObjectAnimator 對應 <objectAnimator>,AnimatorSet 對應 <set>,使用 AnimatorInflater.loadAnimator() 可以加載這些動畫


8. 動態(tài) Drawable 的實現(xiàn)有兩種,最傳統(tǒng)最簡單的就是像電影關(guān)鍵幀一樣依次指定關(guān)鍵幀和每一幀的停留時間,AnimationDrawable 對應于 XML 文件中的 <animation-list>,保存目錄為 res/drawable/,AnimationDrawable 的 start() 方法可以在 onStart() 中調(diào)用。還有一種是 AnimatedVectorDrawable,需要 res/drawable/ 中的 <animated-vector> 引用 res/drawable/ 中的 <vector> 對其使用 res/animator/ 中的 <objectAnimator> 動畫


9. 突然更改顯示的內(nèi)容會讓視覺感受非常突兀不和諧,而且可能意識不到哪些內(nèi)容突然變了,所以很多場景下需要使用動畫過渡一下,而不是突然更改顯示的內(nèi)容


10. 顯示隱藏 view 的常用動畫有三個: crossfade 動畫,card flip 動畫,circular reveal 動畫


11. crossfade 動畫就是內(nèi)容淡出另一個內(nèi)容淡入交叉進行,也被稱為溶入動畫。實現(xiàn)方式為: 事先將淡入 view 的 visibility 設(shè)置為 GONE → 開始動畫時將淡入 view 的 alpha 設(shè)置為 0,visibility 設(shè)置為 VISIBLE → 將淡入 view 的 alpha 動畫到 1,將淡出 view 的 alpha 動畫到 0 并在動畫結(jié)束時將淡出 view 的 visibility 設(shè)置為 GONE


12. card flip 動畫就是卡片翻轉(zhuǎn)動畫,需要四個動畫描述: card_flip_right_in、card_flip_right_out、card_flip_left_in、card_flip_left_out


13. Android 5.0 (API level 21) 開始支持 circular reveal 圓形裁剪動畫,實現(xiàn)方式為: 事先將 view 的 visibility 設(shè)置為 INVISIBLE → 利用 ViewAnimationUtils.createCircularReveal() 方法創(chuàng)建半徑從 0 到 Math.hypot(cx, cy) 的圓形裁剪動畫 → 將 view 的 visibility 設(shè)置為 VISIBLE 然后開啟動畫


14. 直線動畫移動 view 只需要借助 ObjectAnimator.ofFloat() 方法動畫設(shè)置 view 的 translationX 或 translationY 屬性即可


15. 曲線動畫移動 view 還需要借助 Android 5.0 (API level 21) 開始提供的 PathInterpolator 插值器(對應于 XML 文件中的 <pathInterpolator>),他需要個 Path 對象描述運動的貝塞爾曲線??梢允褂?ObjectAnimator.ofFloat(view, "translationX", 100f) 同時設(shè)置 PathInterpolator 也可以直接設(shè)置 view 動畫路徑 ObjectAnimator.ofFloat(view, View.X, View.Y, path)。系統(tǒng)提供的 fast_out_linear_in.xml、fast_out_slow_in.xml、linear_out_slow_in.xml 三個基礎(chǔ)的曲線插值器可以直接使用


16. 放大預覽動畫只需要同時動畫更改目標 view 的 X,Y,SCALE_X,SCALE_Y 屬性即可,不過要先計算好兩個 view 最終的位置和初始縮放比


17. Android 提供了預加載的布局改變動畫,可以通過 android:animateLayoutChanges="true" 屬性告訴系統(tǒng)開啟默認動畫,或者通過 LayoutTransition API 設(shè)置


18. Activity 內(nèi)部的布局過渡動畫: 過渡動畫框架可以在開始 Scene 和結(jié)束 Scene 開始過渡動畫,Scene 存儲著 view hierarchy 狀態(tài),包括所有 view 和其屬性值,開始 Scene 可以通過 setExitAction() 定義過渡動畫開始前要執(zhí)行的操作,結(jié)束 Scene 可以通過 Scene.setEnterAction() 定義過渡動畫完成后要執(zhí)行的操作。


如果 view hierarchy 是靜態(tài)不變的,可以通過布局文件描述和加載 Scene.getSceneForLayout(mSceneRoot, R.layout.a_scene, this),否則可以手動創(chuàng)建 new Scene(mSceneRoot, mViewHierarchy)。Transition 的內(nèi)置子類包括 AutoTransition、Fade、ChangeBounds,可以在 res/transition/ 目錄下定義內(nèi)置的 <fade xmlns:android="http://schemas.android.com/apk/res/android" />,多個組合包裹在 <transitionSet> 標簽中,然后使用 TransitionInflater.from(this).inflateTransition(R.transition.fade_transition) 加載。


還可以手動創(chuàng)建 new Fade()。開始過渡動畫時只需要執(zhí)行 TransitionManager.go(mEndingScene, mFadeTransition) 即可。默認是對 Scene 中所有的 view 作動畫,可以通過 addTarget() 或 removeTarget() 在開始過渡動畫前進行調(diào)整。如果不想在兩個 view hierarchy 間進行過渡,而是在同一個 view hierarchy 狀態(tài)更改后執(zhí)行過渡動畫,那就不需要使用 Scene 了,先利用 TransitionManager.beginDelayedTransition(mRootView, mFade) 讓系統(tǒng)記錄 view 的更改,然后增刪 view 來更改 view hierarchy 的狀態(tài),系統(tǒng)會在重繪 UI 時執(zhí)行延遲過渡動畫。


由于 SurfaceView 由非 UI 線程更新,所以它的過渡可能有問題,TextureView 在一些過渡類型上可能有問題,AdapterView 與過渡動畫框架不兼容,TextView 的大小過渡動畫可能有問題


19. Activity 之間的過渡動畫: 需要 Android 5.0 (API level 21) ,內(nèi)置的進入退出過渡動畫包括: explode 從中央進入或退出,slide 從一邊進入或退出,fade 透明度漸變進入或退出。


內(nèi)置的共享元素過渡動畫包括: changeBounds 動態(tài)更改目標 view 的邊界,changeClipBounds 動態(tài)裁剪目標 view 的邊界,changeTransform 動態(tài)更改目標 view 的縮放和旋轉(zhuǎn),changeImageTransform 動態(tài)更改目標 view 的縮放和尺寸。


過渡動畫需要兩個 Activity 都要開啟 window 的內(nèi)容過渡: android:windowActivityTransitions 屬性設(shè)置為 true 或者代碼中手動 getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS) 開啟。setExitTransition() 和 setSharedElementExitTransition() 方法可以為起始 Activity 設(shè)置退出過渡動畫,setEnterTransition() 和 setSharedElementEnterTransition() 方法可以為目標 Activity 設(shè)置進入過渡動畫。


激活目標 Activity 的時候需要攜帶 ActivityOptions.makeSceneTransitionAnimation(this).toBundle() 的 Bundle,返回的時候要使用 finishAfterTransition() 方法。共享元素需要使用 android:transitionName 屬性或者 View.setTransitionName() 方法指定名字,多個共享元素使用 Pair.create(view1, "agreedName1") 傳遞信息


20. 自定義過渡動畫需要繼承 Transition,實現(xiàn) captureStartValues() 和 captureEndValues() 方法捕獲過渡的 view 屬性值并告訴過渡框架,具體實現(xiàn)為通過 transitionValues.view 檢索當前 view,通過 transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground()) 存儲屬性值,為了避免沖突 key 的格式必須為 package_name:transition_name:property_name。


同時還要實現(xiàn) createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) 方法,框架調(diào)用這個方法的次數(shù)取決于開始和結(jié)束 scene 需要更改的元素數(shù)


21. 動畫可能會影響性能,必要時可以啟用 Profile GPU Rendering 進行調(diào)試


6、BroadcastReceiver 相關(guān)


1. Android 9 (API level 28) 開始 NETWORK_STATE_CHANGED_ACTION 廣播不再包含 SSID,BSSID 等信息


2. Android 8.0 (API level 26) 開始限制應用靜態(tài)注冊一些非當前應用專屬的隱式廣播的 BroadcastReceiver,免除這項限制的廣播包括 ACTION_LOCKED_BOOT_COMPLETED 等不太可能影響用戶體驗的廣播


3. Android 7.0 (API level 24) 開始不能發(fā)送和接收 ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO 系統(tǒng)廣播,可以通過 JobInfo 和 JobParameters 完成。不能靜態(tài)注冊 CONNECTIVITY_ACTION 廣播,如果想在網(wǎng)絡(luò)變化時調(diào)度任務(wù)可以選擇使用 WorkManager,如果只在應用運行期間監(jiān)聽網(wǎng)絡(luò)變化使用 ConnectivityManager 比動態(tài)注冊注銷 BroadcastReceiver 更優(yōu)雅


4. 應該盡量在代碼中動態(tài)注冊注銷 BroadcastReceiver


5. onReceive() 方法中不能進行復雜工作否則會導致 ANR,onReceive() 方法一旦執(zhí)行完,系統(tǒng)可能就認為這個廣播接收器已經(jīng)沒用了,隨時會殺掉包含這個廣播接收器的進程,包括這個進程啟動的線程。使用 goAsync() 方法可以在 PendingResult#finish() 方法執(zhí)行前為廣播接收器的存活爭取更多的時間,但最好還是使用 JobScheduler 等方式進行長時間處理工作


6. 使用 sendBroadcast() 方法發(fā)的廣播屬于常規(guī)廣播,所有能接收這個廣播的廣播接收器接收到廣播的順序是不可控的


7. 使用 sendOrderedBroadcast() 方法發(fā)的廣播屬于有序廣播,根據(jù)廣播接收器的優(yōu)先級一個接一個地傳遞這條廣播,相同優(yōu)先級的順序不可控,廣播接收器可以選擇繼續(xù)傳遞給下一個,也可以選擇直接丟掉


8. 使用 LocalBroadcastManager.getInstance(this).sendBroadcast() 方法發(fā)的廣播屬于應用進程內(nèi)的本地廣播,這樣的廣播只有應用自己知道,比系統(tǒng)級的全局廣播更安全更有效率


9. 為了保證廣播的 action 全局唯一,action 的名字最好使用應用的包名作為前綴,最好聲明成靜態(tài)字符串常量.


7、數(shù)據(jù)存儲與共享


分享文件


為了安全地共享文件,分享的文件必須通過 content URI 表示,必須授予這個 content URI 臨時訪問權(quán)限。FileProvider 作為 ContentProvider 的特殊子類,它的 getUriForFile() 靜態(tài)方法可以為文件生成 content URI。


<provider????android:name="android.support.v4.content.FileProvider"????android:authorities="com.example.myapp.fileprovider"????android:grantUriPermissions="true"????android:exported="false">????<meta-data????????android:name="android.support.FILE_PROVIDER_PATHS"????????android:resource="@xml/filepaths"?/></provider>
????<meta-data
????????android:name="android.support.FILE_PROVIDER_PATHS"
????????android:resource="@xml/filepaths"?/>

</provider>


<paths>????<files-path?path="images/"?name="myimages"?/></paths>
????<files-path?path="images/"?name="myimages"?/>
</paths>

android:authorities 屬性一般是以當前應用包名為前綴的字符串,用來標志數(shù)據(jù)的所有者,多個的話用分號隔開


  • <files-path/> 代表 getFilesDir()

  • <cache-path/> 代表 getCacheDir()

  • <external-path/> 代表 Environment.getExternalStorageDirectory()

  • <external-files-path> 代表 getExternalFilesDir(null)

  • <external-cache-path> 代表 getExternalCacheDir()

  • <external-media-path> 代表 getExternalMediaDirs()


  • File?imagePath?=?new?File(getFilesDir(),?"images");File?newFile?=?new?File(imagePath,?"default_image.jpg");Uri?contentUri?=?FileProvider.getUriForFile(getContext(),?"com.example.myapp.fileprovider",?newFile);"images");
    File?newFile?=?new?File(imagePath,?"default_image.jpg");
    Uri?contentUri?=?FileProvider.getUriForFile(getContext(),?"com.example.myapp.fileprovider",?newFile);


    1. 給 Intent 添加 FLAG_GRANT_READ_URI_PERMISSION 或 FLAG_GRANT_WRITE_URI_PERMISSION 的 flag 授予對這個 content URI 的臨時訪問權(quán)限,該權(quán)限會被目標 Activity 所在應用的其它組件繼承,會在所在的任務(wù)結(jié)束時自動撤銷授權(quán)


    2. 調(diào)用 Context.grantUriPermission(package, Uri, mode_flags) 方法也可以授予 FLAG_GRANT_READ_URI_PERMISSION 或 FLAG_GRANT_WRITE_URI_PERMISSION 權(quán)限,但只有在主動調(diào)用 revokeUriPermission() 方法后或者重啟系統(tǒng)后才會撤銷授權(quán)


    List<ResolveInfo>?activities?=?getPackageManager().queryIntentActivities(intent,????????PackageManager.MATCH_DEFAULT_ONLY);if?(activities.size()?>?0)?{????for?(ResolveInfo?resolveInfo?:?activities)?{????????grantUriPermission(resolveInfo.activityInfo.packageName,????????????????outputUri,?Intent.FLAG_GRANT_WRITE_URI_PERMISSION);????}}...revokeUriPermission(outputUri,?Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    ????????PackageManager.MATCH_DEFAULT_ONLY);
    if?(activities.size()?>?0)?{
    ????for?(ResolveInfo?resolveInfo?:?activities)?{
    ????????grantUriPermission(resolveInfo.activityInfo.packageName,
    ????????????????outputUri,?Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    ????}
    }
    ...
    revokeUriPermission(outputUri,?Intent.FLAG_GRANT_WRITE_URI_PERMISSION);


    ContentProvider


    1. ContentProvider 的數(shù)據(jù)形式和關(guān)系型數(shù)據(jù)庫的表格數(shù)據(jù)類似,因此 API 也像數(shù)據(jù)庫一樣包含增刪改查(CRUD)操作,但為了更好地組織管理一個或多個 ContentProvider,最好通過 ContentResolver 操作 ContentProvider


    2. 對于 ContentProvider 的增刪改查操作,不能直接在 UI 線程上執(zhí)行


    3. Uri 和 ContentUris 類的靜態(tài)方法可以方便地構(gòu)造 content URI


    SELECT?_ID,?word,?locale?FROM?words?WHERE?word?=?<userinput>?ORDER?BY?word?ASC;mCursor?=?getContentResolver().query(????????UserDictionary.Words.CONTENT_URI,????????mProjection,????????mSelectionClause,????????mSelectionArgs,????????mSortOrder);FROM?words?WHERE?word?=?<userinput>?ORDER?BY?word?ASC;

    mCursor?=?getContentResolver().query(
    ????????UserDictionary.Words.CONTENT_URI,
    ????????mProjection,
    ????????mSelectionClause,
    ????????mSelectionArgs,
    ????????mSortOrder);


    3. 為了防止 SQL 注入,禁止拼接 SQL 語句,如 mSelectionClause 不能直接包含 selectionArgs 參數(shù)值


    4. ContentProvider 所在應用本身的組件可以隨便訪問它,不需要授權(quán)


    5. 如果 ContentProvider 的應用不指定任何權(quán)限,那么其它應用就無法訪問這個 ContentProvider 的數(shù)據(jù)


    6. 使用者需要事先通過 <uses-permission> 標簽獲取訪問權(quán)限


    7. 創(chuàng)建 ContentProvider 需要繼承 ContentProvider 并實現(xiàn)增刪改查等一系列方法: onCreate() 在系統(tǒng)創(chuàng)建 provider 后馬上調(diào)用,可以在這里創(chuàng)建數(shù)據(jù)庫,但不要在這里做耗時操作。getType() 返回 content URI 的 MIME 類型。query()、insert()、update()、delete() 進行增刪改查。除了 onCreate() 方法其它方法必須要保證是線程安全的。


    8、Notification 相關(guān)


    1. Android 5.0 (API level 21) 開始通知可以出現(xiàn)在鎖屏頁面


    2. Android 7.0 (API level 24) 開始可以在通知中直接輸入文本或執(zhí)行一些自定義操作,如直接回復按鈕


    3. Android 8.0 (API level 26) 開始所有的通知必須屬于一個 channel,channel 被用戶看作是 categories,即通知類別,用戶通過通知類別來精確管理各個應用或一個應用內(nèi)的通知。


    一個應用可以有多個通知類別,如私信類別、好友請求類別、應用更新類別等等??梢越o每個通知類別指定通知的 importance,即重要程度,Urgent(緊急)會發(fā)出提示音并在屏幕上彈出通知,High(高)會發(fā)出提示音,Medium(中)不發(fā)出提示音,Low(低)不發(fā)出提示音并且不會出現(xiàn)在狀態(tài)欄中。


    在 Android 8.0 (API level 26) 以下的系統(tǒng)中通知的重要程度表現(xiàn)為 priority,即優(yōu)先級。


    對應關(guān)系分別為: IMPORTANCE_HIGH 對應 PRIORITY_HIGH 或 PRIORITY_MAX,IMPORTANCE_DEFAULT 對應 PRIORITY_DEFAULT,IMPORTANCE_LOW 對應 PRIORITY_LOW,IMPORTANCE_MIN 對應 PRIORITY_MIN。在應用啟動時可以執(zhí)行下面的代碼創(chuàng)建通知類別,可以無副作用地多次執(zhí)行


    private?void?createNotificationChannel()?{????if?(Build.VERSION.SDK_INT?>=?Build.VERSION_CODES.O)?{????????CharSequence?name?=?getString(R.string.channel_name);????????String?description?=?getString(R.string.channel_description);????????int?importance?=?NotificationManager.IMPORTANCE_DEFAULT;????????NotificationChannel?channel?=?new?NotificationChannel(CHANNEL_ID,?name,?importance);????????channel.setDescription(description);????????NotificationManager?notificationManager?=?getSystemService(NotificationManager.class);????????notificationManager.createNotificationChannel(channel);????}}
    ????if?(Build.VERSION.SDK_INT?>=?Build.VERSION_CODES.O)?{
    ????????CharSequence?name?=?getString(R.string.channel_name);
    ????????String?description?=?getString(R.string.channel_description);
    ????????int?importance?=?NotificationManager.IMPORTANCE_DEFAULT;
    ????????NotificationChannel?channel?=?new?NotificationChannel(CHANNEL_ID,?name,?importance);
    ????????channel.setDescription(description);
    ????????NotificationManager?notificationManager?=?getSystemService(NotificationManager.class);
    ????????notificationManager.createNotificationChannel(channel);
    ????}
    }


    4. 通過 NotificationChannel 的 enableLights(),setLightColor() 等方法可以指定該通知類別默認的通知行為,但是一旦創(chuàng)建了應用就不能再對它做任何更改了,只有用戶自己可以更改設(shè)置??梢酝ㄟ^ Intent 引導用戶跳轉(zhuǎn)至對應設(shè)置頁


    Intent?intent?=?new?Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);intent.putExtra(Settings.EXTRA_APP_PACKAGE,?getPackageName());intent.putExtra(Settings.EXTRA_CHANNEL_ID,?myNotificationChannel.getId());startActivity(intent);
    intent.putExtra(Settings.EXTRA_APP_PACKAGE,?getPackageName());
    intent.putExtra(Settings.EXTRA_CHANNEL_ID,?myNotificationChannel.getId());
    startActivity(intent);


    5. 查詢用戶當前的通知類別的設(shè)置可以通過 getNotificationChannel()、getNotificationChannels()、getVibrationPattern()、getImportance() 等方法獲取


    6. 使用 deleteNotificationChannel(id) 可以刪除通知類別,但是在開發(fā)模式下可能需要重裝應用或者清除數(shù)據(jù)才會完全刪除


    7. 通知類別也可以分組


    //?The?id?of?the?group.String?groupId?=?"my_group_01";//?The?user-visible?name?of?the?group.CharSequence?groupName?=?getString(R.string.group_name);NotificationManager?mNotificationManager?=????????(NotificationManager)?getSystemService(Context.NOTIFICATION_SERVICE);mNotificationManager.createNotificationChannelGroup(new?NotificationChannelGroup(groupId,?groupName));
    String?groupId?=?"my_group_01";
    //?The?user-visible?name?of?the?group.
    CharSequence?groupName?=?getString(R.string.group_name);
    NotificationManager?mNotificationManager?=
    ????????(NotificationManager)?getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.createNotificationChannelGroup(new?NotificationChannelGroup(groupId,?groupName));


    8. Android 5.0 (API level 21) 開始支持勿擾模式(Do Not Disturb)以禁止任何通知產(chǎn)生的聲音和震動。Total silence(完全阻止)會阻止包括鬧鐘視頻游戲在內(nèi)的所有聲音和震動,Alarms only(僅限鬧鐘)會阻止除了鬧鐘外的所有聲音和震動,Priority only(自訂)可以定制要屏蔽的信息通話等系統(tǒng)范圍內(nèi)的通知。setCategory() 方法可以設(shè)置所屬的系統(tǒng)范圍的勿擾類別


    9. 每個通知類別可以選擇是否覆蓋勿擾模式的設(shè)置,當勿擾模式設(shè)置為“僅限優(yōu)先事項”時,可以允許繼續(xù)接收此類通知


    10. Android 8.1 (API level 27) 開始每秒最多播放一次通知提示音,如果一秒內(nèi)有多個通知那么只播放一秒內(nèi)的第一個通知提示音,如果一秒內(nèi)多次頻繁更新一個通知,那么系統(tǒng)可能會丟棄一些通知更新


    11. 最好使用 NotificationCompat 和 NotificationManagerCompat 等兼容庫中的類以便方便地適配低版本系統(tǒng)


    12. setSmallIcon() 方法可以設(shè)置小圖標,應用名和時間是由系統(tǒng)設(shè)置的,setLargeIcon() 方法可以設(shè)置右邊大圖標,setContentTitle() 和 setContentText() 方法可以設(shè)置通知的標題和內(nèi)容,setPriority() 方法可以為 Android 8.0 (API level 26) 以下的系統(tǒng)設(shè)置通知優(yōu)先級。系統(tǒng)范圍的預定義通知類別包括 NotificationCompat.CATEGORY_ALARM,NotificationCompat.CATEGORY_REMINDER 等類別,這個類別在勿擾模式中有用,可以通過 setCategory() 方法指定所屬的系統(tǒng)范圍通知類別


    13. 默認的通知內(nèi)容會收縮成一行,可以通過 setStyle() 方法設(shè)置其他可展開的通知樣式,


    .setStyle(new?NotificationCompat.BigTextStyle().bigText(emailObject.getSubjectAndSnippet()))?new?NotificationCompat.BigTextStyle().bigText(emailObject.getSubjectAndSnippet()))?


    可以設(shè)置大文本塊樣式。


    .setStyle(new?NotificationCompat.InboxStyle().addLine(messageSnippet1)?new?NotificationCompat.InboxStyle().addLine(messageSnippet1)?


    可以設(shè)置多行的 inbox 樣式。


    .setStyle(new?NotificationCompat.MessagingStyle(resources.getString(R.string.reply_name)).addMessage(message1))?new?NotificationCompat.MessagingStyle(resources.getString(R.string.reply_name)).addMessage(message1))?


    可以設(shè)置消息樣式,但是此樣式會忽略 setContentTitle() 和 setContentText() 方法的設(shè)置,但可以通過 setConversationTitle() 方法設(shè)置該聊天所屬的群組名。


    setStyle(new?android.support.v4.media.app.Notification.MediaStyle().setShowActionsInCompactView(1).setMediaSession(mMediaSession.getSessionToken()))?new?android.support.v4.media.app.Notification.MediaStyle().setShowActionsInCompactView(1).setMediaSession(mMediaSession.getSessionToken()))?


    可以設(shè)置媒體樣式的通知,屬于 CATEGORY_TRANSPORT 類別。



    14. 通知的點擊事件可以通過 setContentIntent() 方法設(shè)置 PendingIntent 對象完成,setAutoCancel(true) 可以在點擊后自動移除通知


    Intent?intent?=?new?Intent(this,?AlertDetails.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK?|?Intent.FLAG_ACTIVITY_CLEAR_TASK);PendingIntent?pendingIntent?=?PendingIntent.getActivity(this,?0,?intent,?0);NotificationCompat.Builder?mBuilder?=?new?NotificationCompat.Builder(this,?CHANNEL_ID)????????.setSmallIcon(R.drawable.notification_icon)????????.setContentTitle("My?notification")????????.setContentText("Hello?World!")????????.setLargeIcon(myBitmap)????????.setStyle(new?NotificationCompat.BigPictureStyle()????????????????.bigPicture(myBitmap)????????????????.bigLargeIcon(null))????????.setPriority(NotificationCompat.PRIORITY_DEFAULT)????????.setContentIntent(pendingIntent)????????.setAutoCancel(true);this,?AlertDetails.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK?|?Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent?pendingIntent?=?PendingIntent.getActivity(this,?0,?intent,?0);
    NotificationCompat.Builder?mBuilder?=?new?NotificationCompat.Builder(this,?CHANNEL_ID)
    ????????.setSmallIcon(R.drawable.notification_icon)
    ????????.setContentTitle("My?notification")
    ????????.setContentText("Hello?World!")
    ????????.setLargeIcon(myBitmap)
    ????????.setStyle(new?NotificationCompat.BigPictureStyle()
    ????????????????.bigPicture(myBitmap)
    ????????????????.bigLargeIcon(null))
    ????????.setPriority(NotificationCompat.PRIORITY_DEFAULT)
    ????????.setContentIntent(pendingIntent)
    ????????.setAutoCancel(true);


    15. 通過 NotificationManagerCompat#notify() 方法可以顯示通知,你需要定義一個唯一的 int 值的 ID 作為這個通知的 ID,保存這個 ID 以便之后更新或移除這個通知:


    NotificationManagerCompat?notificationManager?=?NotificationManagerCompat.from(this);notificationManager.notify(notificationId,?mBuilder.build());this);
    notificationManager.notify(notificationId,?mBuilder.build());


    16. setVisibility() 方法可以設(shè)置鎖屏時的通知顯示策略,VISIBILITY_PUBLIC(顯示所有通知)表示完整地顯示通知內(nèi)容,VISIBILITY_SECRET(完全不顯示內(nèi)容)表示不顯示通知的任何信息,VISIBILITY_PRIVATE(隱藏敏感通知內(nèi)容)表示只顯示圖標標題等基本信息


    17. NotificationManagerCompat#notify() 方法傳遞之前的通知 ID 可以更新之前的通知,調(diào)用 setOnlyAlertOnce() 方法以便只在第一次出現(xiàn)通知時提示用戶


    18. 用戶可以主動清除通知,創(chuàng)建通知時調(diào)用 setAutoCancel() 方法可以在用戶點擊通知后清除通知,創(chuàng)建通知時調(diào)用 setTimeoutAfter() 方法可以在超時后由系統(tǒng)自動清除通知,可以隨時調(diào)用 cancel() 或 cancelAll() 方法清除之前的通知


    19. 點擊通知后啟動的 Activity 分為兩種,一種是應用的正常用戶體驗流中的常規(guī) Activity,擁有任務(wù)完整的返回棧。還有一種是僅僅用來展示通知的詳細內(nèi)容的特殊Activity,它不需要返回棧。


    對于常規(guī) Activity 需要先通過 android:parentActivityName 屬性或者 android.support.PARENT_ACTIVITY 的 <meta-data> 標簽指定層級關(guān)系,然后:


    Intent?resultIntent?=?new?Intent(this,?ResultActivity.class);TaskStackBuilder?stackBuilder?=?TaskStackBuilder.create(this);stackBuilder.addNextIntentWithParentStack(resultIntent);PendingIntent?resultPendingIntent?=????????stackBuilder.getPendingIntent(0,?PendingIntent.FLAG_UPDATE_CURRENT);class);
    TaskStackBuilder?stackBuilder?=?TaskStackBuilder.create(this);
    stackBuilder.addNextIntentWithParentStack(resultIntent);
    PendingIntent?resultPendingIntent?=
    ????????stackBuilder.getPendingIntent(0,?PendingIntent.FLAG_UPDATE_CURRENT);


    對于特殊 Activity 需要先指定 android:taskAffinity="" 和 android:excludeFromRecents="true" 以避免在之前的任務(wù)中啟動,然后:


    Intent?notifyIntent?=?new?Intent(this,?ResultActivity.class);notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK?|?Intent.FLAG_ACTIVITY_CLEAR_TASK);PendingIntent?notifyPendingIntent?=?PendingIntent.getActivity(????????this,?0,?notifyIntent,?PendingIntent.FLAG_UPDATE_CURRENT);class);
    notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK?|?Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent?notifyPendingIntent?=?PendingIntent.getActivity(
    ????????this,?0,?notifyIntent,?PendingIntent.FLAG_UPDATE_CURRENT
    );

    9、后臺任務(wù)


    1. 每個進程都有一個主線程用來完成任務(wù),一般主線程結(jié)束了那么意味著整個任務(wù)完成了,進程就會自動結(jié)束退出了


    2. Android 應用的主線程用來進行測量繪制 UI、協(xié)調(diào)用戶操作、接收生命周期事件等工作,是與用戶的感知直接關(guān)聯(lián)的,所以通常也被叫做 UI 線程,如果在這個線程中做太多工作,那么會導致這個線程掛起或者卡頓,導致糟糕的用戶體驗。所以像解碼 bitmap、讀寫磁盤、執(zhí)行網(wǎng)絡(luò)請求等需要長時間計算和處理的操作都應該放到單獨的后臺線程中去做


    3. 后臺線程雖然是用戶感覺不到的,但通常卻是最消耗系統(tǒng)資源的,有的線程大部分時間都在占用 CPU 完成復雜的計算,我們管這種稱為 CPU 密集型操作,有的線程大部分時間都在進行 I/O 的讀寫操作,我們管這種叫做 I/O 密集型操作。我們可以根據(jù)不同的操作類型選擇不同的策略來處理以便最大化系統(tǒng)的吞吐量同時最小化所需代價。同時長時間運行的后臺線程也加劇了電量的消耗,所以不管是操作系統(tǒng)還是開發(fā)者都需要 對這些后臺線程的行為進行限制


    4. 在創(chuàng)建一個后臺任務(wù)之前,我們需要先要對它分析一下,它是要馬上執(zhí)行還是可以延遲執(zhí)行?它需要系統(tǒng)滿足指定條件才能執(zhí)行嗎?它需要在精確的時間點執(zhí)行嗎?


    WorkManager


    1. 通過 WorkManager 可以優(yōu)雅地執(zhí)行 可延遲執(zhí)行的 異步任務(wù),當應用退出后仍然可以繼續(xù)執(zhí)行,當滿足系統(tǒng)條件(聯(lián)網(wǎng)、充電、重啟)時仍然可以觸發(fā)任務(wù)的執(zhí)行


    2. 特別適合用來向后臺發(fā)送日志或分析數(shù)據(jù),或者用來周期性的與服務(wù)器同步數(shù)據(jù)


    3. WorkManager 在 Android 6.0 (API level 23) 及以上系統(tǒng)上借助 JobScheduler 實現(xiàn),在之前的系統(tǒng)上借助 BroadcastReceiver 和 AlarmManager 實現(xiàn)


    4. WorkManager 可以對任務(wù)添加網(wǎng)絡(luò)條件和充電狀態(tài)等條件限制,可以調(diào)度一次性的或周期性的任務(wù),可以監(jiān)聽和管理被調(diào)度的任務(wù),可以將多個任務(wù)連在一起


    5. 一次性的任務(wù)可以使用 OneTimeWorkRequest,周期性的任務(wù)使用 PeriodicTimeWorkRequest


    6. 如果指定了多個限制,那么只有在所有限制都滿足的情況下任務(wù)才會執(zhí)行:


    Constraints?constraints?=?new?Constraints.Builder()????.setRequiresDeviceIdle(true)????.setRequiresCharging(true)?????.build();OneTimeWorkRequest?compressionWork?=????????????????new?OneTimeWorkRequest.Builder(CompressWorker.class)?????.setConstraints(constraints)?????.build();
    ????.setRequiresDeviceIdle(true)
    ????.setRequiresCharging(true)
    ?????.build();
    OneTimeWorkRequest?compressionWork?=
    ????????????????new?OneTimeWorkRequest.Builder(CompressWorker.class)
    ?????.setConstraints(constraints)
    ?????.build();


    7. 任務(wù)交給系統(tǒng)后可能會馬上被執(zhí)行,可以通過 setInitialDelay(10, TimeUnit.MINUTES) 設(shè)置一個最小延時


    8. 如果需要重試任務(wù)可以在 Worker 中使用 Result.retry() 完成,采用的補償策略默認是 EXPONENTIAL 指數(shù)級的,可以使用 setBackoffCriteria() 方法調(diào)整策略


    9. 可以通過 setInputData() 方法為任務(wù)設(shè)置輸入數(shù)據(jù),在 Worker 中可以通過 getInputData() 方法獲取到輸入數(shù)據(jù),Result.success() 和 Result.failure() 可以攜帶輸出數(shù)據(jù)。數(shù)據(jù)應該盡可能的簡單,不能超過 10KB


    10. addTag 方法可以給任務(wù)打 Tag,然后就可以使用 WorkManager.cancelAllWorkByTag(String) 和 WorkManager.getWorkInfosByTagLiveData(String) 等方法方便操作任務(wù)了


    11. 如果一個任務(wù)的先決任務(wù)沒有完成那么會被認為是 BLOCKED 態(tài)


    12. 如果任務(wù)的限制和定時滿足要求那么會被認為是 ENQUEUED 態(tài)


    13. 如果任務(wù)正在執(zhí)行那么會被認為是 RUNNING 態(tài)


    14. 如果任務(wù)返回了 Result.success() 那么會被認為是 SUCCEEDED 態(tài),這是最終態(tài),只有 OneTimeWorkRequest 可能進入這個狀態(tài)


    15. 如果任務(wù)返回了 Result.failure() 那么會被認為是 FAILED 態(tài),這是最終態(tài),只有 OneTimeWorkRequest 可能進入這個狀態(tài),所有相關(guān)的任務(wù)也會被標記為 FAILED 且不會被執(zhí)行


    16. 顯式取消一個沒終止的 WorkRequest 會被認為是 CANCELLED 態(tài),所有相關(guān)的任務(wù)也會被標記為 CANCELLED 且不會被執(zhí)行


    17. WorkManager.getWorkInfoById(UUID) 和 WorkManager.getWorkInfoByIdLiveData(UUID) 等方法可以定位想要的任務(wù)進行觀察


    18. 可以將任務(wù)連在一起:


    WorkManager.getInstance()????.beginWith(Arrays.asList(filter1,?filter2,?filter3))????.then(compress)????.then(upload)????.enqueue();.getInstance()
    ????.beginWith(Arrays.asList(filter1,?filter2,?filter3))
    ????.then(compress)
    ????.then(upload)
    ????.enqueue();


    Foreground service


    對于用戶觸發(fā)的必須馬上執(zhí)行且必須執(zhí)行完的后臺任務(wù),需要使用 Foreground services 實現(xiàn),它既告訴系統(tǒng)這個應用正在執(zhí)行重要的任務(wù)不能被殺掉,又通過通知欄告訴用戶有后臺工作正在執(zhí)行.


    AlarmManager


    如果任務(wù)需要在精確的時間點執(zhí)行,可以使用 AlarmManager


    DownloadManager


    如果需要執(zhí)行一個長時間的 HTTP 下載任務(wù),可以使用 DownloadManager。


    DownloadManager 獨立于應用之外,可以在下載失敗、更改網(wǎng)絡(luò)連接、系統(tǒng)重啟后進行重試


    public?static?long?downloadApk(String?url,?String?title,?String?desc)?{????DownloadManager.Request?request?=?new?DownloadManager.Request(Uri.parse(url));????request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE?|?DownloadManager.Request.NETWORK_WIFI)????????????.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)????????????.setTitle(title)????????????.setDescription(desc)????????????.setDestinationInExternalFilesDir(MyApplication.getInstance(),?null,?"apks")????????????.allowScanningByMediaScanner();????DownloadManager?downloadManager?=?(DownloadManager)?MyApplication.getInstance().getSystemService(Context.DOWNLOAD_SERVICE);????return?downloadManager.enqueue(request);}String?url,?String?title,?String?desc)?{
    ????DownloadManager.Request?request?=?new?DownloadManager.Request(Uri.parse(url));
    ????request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE?|?DownloadManager.Request.NETWORK_WIFI)
    ????????????.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
    ????????????.setTitle(title)
    ????????????.setDescription(desc)
    ????????????.setDestinationInExternalFilesDir(MyApplication.getInstance(),?null,?"apks")
    ????????????.allowScanningByMediaScanner();
    ????DownloadManager?downloadManager?=?(DownloadManager)?MyApplication.getInstance().getSystemService(Context.DOWNLOAD_SERVICE);
    ????return?downloadManager.enqueue(request);
    }

    更多學習和討論,歡迎加入我們的知識星球,這里有1000+小伙伴,讓你的學習不寂寞~·

    看完本文有收獲?請轉(zhuǎn)發(fā)分享給更多人


    我們的知識星球第三期開期了,已達到1100人了,能連續(xù)做三期已很不容易了,有很多老用戶續(xù)期,目前續(xù)期率達到50%,說明了大家對我們的知識星球還是很認可的,歡迎大家加入盡早我們的知識星球,更多星球信息參見:

    歡迎加入Java和Android架構(gòu)社群

    如何進階成為Java的Android版和架構(gòu)師?

    說兩件事

    微信掃描或者點擊上方二維碼領(lǐng)取的Android \ Python的\ AI \的Java等高級進階資源

    更多學習資料點擊下面的“閱讀原文?”獲取

    謝謝老板,點個好看↓

    總結(jié)

    以上是生活随笔為你收集整理的带你梳理一遍 Android 核心知识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    一级欧美黄 | 人人天天夜夜 | 精品国产片 | 制服丝袜在线 | 国产精品一区二区吃奶在线观看 | 97超碰人人澡 | 婷婷网站天天婷婷网站 | 岛国av在线 | 久草在线费播放视频 | 91精品免费在线视频 | 成人午夜电影久久影院 | 不卡av免费在线观看 | 蜜桃av观看| 99久久精品免费看国产一区二区三区 | 丁香六月综合网 | 久久综合中文字幕 | 日韩成片 | 成人av免费在线观看 | 不卡电影一区二区三区 | 国产在线久久久 | 久久久精品亚洲 | 久久一久久 | 婷婷深爱五月 | a级国产乱理伦片在线观看 亚洲3级 | 日韩福利在线观看 | 天天超碰 | 久草在线视频首页 | 日韩xxxx视频 | 欧美激情精品久久久久久免费印度 | 精品国产午夜 | 久久久国产精品亚洲一区 | 97国产超碰在线 | 久久躁日日躁aaaaxxxx | 午夜精品一区二区国产 | 99riav1国产精品视频 | 亚洲国产精品电影 | 99精品久久精品一区二区 | 国产午夜一区 | 欧洲亚洲国产视频 | 69精品| 香蕉影视| 国产无遮挡猛进猛出免费软件 | 亚洲一区日韩精品 | 亚洲成aⅴ人在线观看 | 欧美一级淫片videoshd | 999精品| 天天操天天怕 | 97视频在线观看网址 | 国产精品18videosex性欧美 | 国产区精品 | 毛片1000部免费看 | 日韩欧美一区二区三区黑寡妇 | 国产另类av | 国产区在线视频 | 韩国在线一区 | 在线看国产 | 国产中文字幕网 | 欧美日韩综合在线观看 | 天天操天天舔天天干 | 国产亚洲精品久久久久久无几年桃 | 亚洲视频在线播放 | 国产成人一区二区三区免费看 | 欧美日韩中文在线观看 | 天天干天天在线 | 欧美a级片免费看 | 午夜av在线播放 | 91女子私密保健养生少妇 | 免费福利在线观看 | 久久乱码卡一卡2卡三卡四 五月婷婷久 | 国产一区二区综合 | 免费美女久久99 | 婷婷色 亚洲| 久久不射电影院 | 干狠狠| 日韩久久久 | 中文字幕色婷婷在线视频 | 婷婷色资源 | 国产精品日韩久久久久 | 欧美a级免费视频 | 蜜臀av网站| 在线黄网站 | 在线亚洲高清视频 | 成人国产精品免费 | 国产成人三级三级三级97 | 五月婷婷久久综合 | 国产精品电影一区二区 | 国产系列在线观看 | 国产又粗又硬又爽视频 | 亚州精品成人 | 国产无吗一区二区三区在线欢 | 在线a人片免费观看视频 | 亚洲午夜精品久久久久久久久久久久 | 成人app在线播放 | 91成人精品 | 国产精品一区二区三区观看 | 精品美女久久久久 | 国产九九九九九 | 中文字幕成人一区 | 99re国产视频| 国产中年夫妇高潮精品视频 | 波多野结衣最新 | av线上免费看 | 在线 日韩 av | www.xxxx变态.com | 欧美成人日韩 | 日本视频不卡 | 国产啊v在线观看 | 久久精品日韩 | 在线免费观看国产视频 | 黄色软件视频大全免费下载 | 欧美人体xx | 色婷婷激情五月 | 日韩欧美精品在线观看 | 日韩欧美国产激情在线播放 | 国产免费激情久久 | 日韩精品视频在线观看免费 | av在线短片 | 国产做aⅴ在线视频播放 | 成人一区不卡 | 欧美一级性 | 中文字幕一区二区三区精华液 | 欧美一级xxxx | 青青啪| 精品在线免费观看 | 日韩精品视频在线观看免费 | 久久久九九| 久久久久国| 欧美一级欧美一级 | 婷久久| 国产精品一区二区三区在线播放 | 日韩午夜精品福利 | 午夜婷婷综合 | 99精品国产一区二区三区麻豆 | 欧美日韩超碰 | 亚洲影视九九影院在线观看 | 日韩在线视 | 国产91在线免费视频 | 在线你懂 | 制服丝袜在线 | 黄色在线观看网站 | 亚洲国产影院 | 在线观看免费黄色 | 亚洲免费在线视频 | 国产成人一区二区精品非洲 | 亚洲国产日韩欧美在线 | 中文字幕日本电影 | av在线进入| 久久精品欧美一 | 日本不卡久久 | 91黄色免费网站 | 成人在线视频网 | 九九久久免费 | 黄色大片免费播放 | 国产精品99久久久久久小说 | 视频在线99 | 黄色三级免费 | 色成人亚洲网 | 8x8x在线观看视频 | 一本之道乱码区 | 中文字幕欧美日韩va免费视频 | 国产视频丨精品|在线观看 国产精品久久久久久久久久久久午夜 | 久久久香蕉视频 | 日本在线视频一区二区三区 | 国产亚洲欧美日韩高清 | 97香蕉久久国产在线观看 | 永久中文字幕 | 麻豆精品国产传媒 | 97av超碰| 亚洲一区欧美精品 | 久久精品99久久久久久2456 | 在线国产一区二区三区 | 亚洲一区网 | 日韩有码在线观看视频 | 亚洲激情视频在线观看 | 欧日韩在线视频 | 超碰人人av | 国产视频在线一区二区 | 久久综合久久久 | 99视频在线免费观看 | 日韩婷婷 | 亚洲精选久久 | 欧美精品在线一区 | 亚洲伊人第一页 | 91精品久久香蕉国产线看观看 | 久久丁香网 | 精品亚洲二区 | 亚洲一区精品人人爽人人躁 | 亚洲1级片 | 91污视频在线| 激情五月色播五月 | 亚州精品在线视频 | 欧美成人xxxxxxxx| 久久精品国产精品亚洲精品 | 亚洲精品在线网站 | 国产精品爽爽久久久久久蜜臀 | 亚洲无吗天堂 | 欧美成a人片在线观看久 | 人人爽人人爽人人爽 | 亚洲国产成人精品电影在线观看 | 久久久久久久久久亚洲精品 | 摸bbb搡bbb搡bbbb | 日韩欧美视频一区二区 | 国产精品每日更新 | 国产99久久精品一区二区永久免费 | 高清色免费 | 日韩免费三区 | 久久99国产精品久久99 | 久久免费黄色大片 | 韩日三级在线 | www.在线观看视频 | 欧美孕交vivoestv另类 | 亚洲综合欧美精品电影 | 免费男女羞羞的视频网站中文字幕 | 精品欧美一区二区在线观看 | 高清视频一区二区三区 | 一区电影 | 中文字幕在线国产 | 五月婷婷丁香在线观看 | 精品日韩中文字幕 | 国产亚洲午夜高清国产拍精品 | 亚洲精品国产第一综合99久久 | 国产精品二区在线 | 久久天天躁狠狠躁夜夜不卡公司 | 亚洲精品在线观看免费 | 欧美日韩视频在线观看一区二区 | 99999精品 | 91av免费看 | www.97视频| 激情深爱.com | 黄色a级片在线观看 | 久久免费视频这里只有精品 | 狠狠地日 | 日韩在线国产精品 | 久久久久国产精品免费 | av网站手机在线观看 | 日本狠狠色| 免费男女羞羞的视频网站中文字幕 | 国内精品免费久久影院 | 成人资源网 | av一级二级| 国产高清在线免费观看 | 国产精品乱码久久久久 | 亚洲人成在线电影 | 91精品免费在线 | 极品久久久 | 日韩午夜电影 | 美女视频久久 | 精品国产一区二区三区四区vr | 国产资源网站 | 在线免费三级 | 国产一区二区视频在线 | 水蜜桃亚洲一二三四在线 | 最新av免费在线观看 | 亚洲欧美国产精品 | 成人免费观看大片 | 国产精品国产三级国产不产一地 | 国产亚洲欧美精品久久久久久 | 五月婷网站 | 麻豆精品在线 | 午夜精品一区二区三区可下载 | 日韩欧美一区二区三区免费观看 | 啪啪资源 | 美女免费视频网站 | 制服丝袜天堂 | 亚洲综合成人婷婷小说 | 97色综合| 97视频在线免费观看 | www夜夜操 | 午夜视频亚洲 | 中文免费观看 | 亚洲影视资源 | 一二区av| 最近高清中文在线字幕在线观看 | 欧美日韩综合在线观看 | 久久不卡日韩美女 | 国产又粗又猛又黄又爽视频 | 精品v亚洲v欧美v高清v | 久久免费激情视频 | 日韩成人精品一区二区 | 欧美精彩视频在线观看 | 国产福利在线免费 | 97免费在线观看视频 | 99免费在线视频观看 | 亚洲精品欧美专区 | 尤物九九久久国产精品的分类 | 国产精品综合久久久久 | 2021av在线 | 国产成人在线免费观看 | 91私密视频 | 欧美aaa大片 | 天天操天天操天天操 | 亚洲少妇xxxx | 超碰97中文 | 成年人天堂com | 久久综合中文字幕 | 99人成在线观看视频 | 亚洲视频大全 | 久久久国产精品人人片99精片欧美一 | 最近中文字幕在线中文高清版 | 国产精品99久久99久久久二8 | 欧美日本高清视频 | 激情影音 | 超碰97人人干 | 久久精品99国产精品亚洲最刺激 | 天天做天天爱夜夜爽 | 91精品国产综合久久福利 | 精品视频专区 | 中文字幕在线视频精品 | www.福利 | 色窝资源| 色多多视频在线观看 | 国产区网址 | 亚洲国产片 | 亚洲91精品 | 四虎精品成人免费网站 | 92国产精品久久久久首页 | 中文字幕av专区 | 欧美一级性生活视频 | 亚洲精品免费观看视频 | 91原创在线观看 | 国产在线精品福利 | 日韩国产欧美在线视频 | 婷婷激情欧美 | 五月婷色| 亚洲国产无 | 九九久久国产精品 | 午夜av在线免费 | 欧美日韩精品电影 | 日韩一区二区三区不卡 | 久久久久99精品成人片三人毛片 | 国产精品k频道 | 国产一区二区不卡视频 | 久草在线视频在线 | 国产一区二区网址 | 久久久久久久免费 | 黄色成人小视频 | 久久久久网站 | 久久av在线播放 | 91在线精品一区二区 | 成年人av在线播放 | 国产精品久久久久久久久久久久冷 | 国产区精品在线观看 | 亚洲视频在线观看免费 | 免费视频91蜜桃 | 日日夜夜精品视频天天综合网 | 黄色一级性片 | 国内精品久久久久久久久久 | 国产在线久草 | 91成人网页版 | 美女网站在线 | 2019中文字幕网站 | www.色午夜| 中文一区二区三区在线观看 | 精品久久久久一区二区国产 | 天天综合成人 | 综合天天色 | 五月天亚洲婷婷 | 国内视频在线观看 | 日本在线观看中文字幕无线观看 | 国产精品成人一区二区三区吃奶 | 国产91精品欧美 | 一区久久久 | 在线黄av| 天天爱天天射天天干天天 | 久久精品成人欧美大片古装 | 日日躁夜夜躁xxxxaaaa | 中文字幕高清 | 欧美日韩国产精品一区二区三区 | 综合久久精品 | 久在线 | 超碰在线人人艹 | 成人欧美亚洲 | 一本一本久久aa综合精品 | 久久精品欧美 | 久久在视频 | 99久久精品网 | 天天综合导航 | 91最新网址在线观看 | 福利网在线 | 国产91大片| 韩国一区视频 | 欧美一级视频免费看 | 国产精品女人久久久 | 99久久精品免费看国产 | 99久久精品久久久久久清纯 | 99免费| 久久99热久久99精品 | 三级av小说 | 国语麻豆 | 亚洲闷骚少妇在线观看网站 | 亚洲综合视频在线播放 | 99国产精品 | 亚洲欧洲精品一区二区精品久久久 | 国产精品美女久久久久aⅴ 干干夜夜 | 黄色a在线| av大片网站 | 国产精品理论在线观看 | 成x99人av在线www | 黄污网| 日韩视频免费 | 国产在线中文字幕 | 欧美日韩视频在线一区 | 国产精品久久久久久久电影 | 精品国模一区二区三区 | 国产精品视频地址 | 丁香婷婷深情五月亚洲 | 成人资源网 | 99精品免费久久久久久久久日本 | 日韩精品极品视频 | 免费国产一区二区 | 成人免费视频在线观看 | 色多多污污在线观看 | 久爱综合| 日本精品久久久久 | 特级西西444www高清大视频 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 国产最顶级的黄色片在线免费观看 | 成年人免费在线播放 | 免费看的毛片 | 久久九九影视网 | 国产精品日韩高清 | 国产成人99av超碰超爽 | 亚洲人视频在线 | 日韩精品1区2区 | 亚洲一级久久 | 欧美日韩免费在线视频 | 在线 你懂| 四虎在线观看网址 | 婷婷资源站 | 国产在线高清视频 | 亚洲精品男人天堂 | 成年一级片 | 视频1区2区 | 欧美日韩一区二区三区在线观看视频 | 成年人视频在线免费播放 | www.夜夜操.com | 国产美女视频网站 | 婷婷国产视频 | 欧美久久久久久 | 日本精品中文字幕 | 免费视频你懂的 | 国产精品久久久久久久久毛片 | 国产美腿白丝袜足在线av | 久久人人爽人人人人片 | 久久黄色网页 | 欧美成人中文字幕 | 97理论片| 久久婷婷一区二区三区 | 永久av免费在线观看 | 波多野结衣精品在线 | 一本一道久久a久久精品 | 国产成人性色生活片 | 国产伦精品一区二区三区免费 | 伊人永久| 成人午夜剧场在线观看 | 日韩在线小视频 | 黄色大片入口 | 99视频精品免费观看, | 成人久久18免费网站麻豆 | 日韩视频专区 | 国产精品ssss在线亚洲 | 亚洲天天做 | 国产精品 欧美 日韩 | 99精品热视频 | 五月婷婷一区二区三区 | 亚洲欧美偷拍另类 | 亚洲精品中文字幕视频 | 麻豆91在线 | 一级a性色生活片久久毛片波多野 | 久久在线精品 | 91人人在线| 91麻豆精品国产91久久久无需广告 | 欧美日韩亚洲在线观看 | 日本少妇高清做爰视频 | 久久婷婷一区二区三区 | 伊人夜夜| 天堂中文在线播放 | 成人污视频在线观看 | 久久免费在线观看 | 青青草国产免费 | 亚州精品天堂中文字幕 | 狠狠干网 | 欧美另类z0zx | 欧美色图30p | 亚洲成人蜜桃 | 五月天综合| 久久精品一二三区 | 91九色成人蝌蚪首页 | 超碰在线天天 | 9在线观看免费 | 在线观看中文字幕av | 国产最新在线视频 | 亚洲国产精品第一区二区 | 久草久草视频 | 欧美成年人在线观看 | 亚洲高清视频一区二区三区 | 日韩精品一区二区在线 | 国产精品综合久久 | 欧美视频一区二 | 超碰97在线资源 | 国产欧美精品在线观看 | 一区二区三区www | 一二三精品视频 | 久久都是精品 | 中文字幕免费在线 | 久精品视频在线观看 | 久久久精品日本 | 天天操天天操天天操天天操 | 五月丁婷婷 | 免费中文字幕在线观看 | 免费高清男女打扑克视频 | 国产永久免费 | 少妇bbb好爽| 伊人色综合久久天天 | 99精品视频在线观看免费 | 亚洲电影久久久 | 在线免费三级 | 日韩国产精品毛片 | 国产精品成人一区二区三区 | 日韩在线观看你懂的 | 91精品啪在线观看国产 | 日韩免费视频一区二区 | 欧美韩国日本在线 | 97日日碰人人模人人澡分享吧 | 国产涩图 | 波多野结衣动态图 | www久| 国产精品一码二码三码在线 | 欧美一级欧美一级 | 天堂av官网 | 免费观看完整版无人区 | 亚洲黑丝少妇 | 日韩视频一区二区 | 成人97人人超碰人人99 | 天堂视频中文在线 | 国产无遮挡又黄又爽在线观看 | 国产精品毛片久久 | 成人亚洲精品久久久久 | 亚洲国产欧美一区二区三区丁香婷 | 福利一区二区在线 | 精品久久久久久久久中文字幕 | 黄色av网站在线免费观看 | 日韩电影中文字幕在线 | 五月天婷亚洲天综合网鲁鲁鲁 | 欧美日韩在线观看不卡 | 一级成人网| 韩国视频一区二区三区 | 丁香六月五月婷婷 | 美女网色 | 久久精品一级片 | 四虎在线视频免费观看 | 伊人亚洲精品 | 91插插视频 | 久久人人爽人人爽人人片 | va视频在线观看 | 午夜视频在线观看欧美 | 丰满少妇高潮在线观看 | 激情综合中文娱乐网 | 成人在线你懂得 | 黄色1级毛片 | 亚洲成人免费 | 一级成人免费视频 | 天堂久色| 九九精品视频在线看 | 久久久伦理| 97品白浆高清久久久久久 | 欧美十八| 国产精品久久久久久a | 美女视频黄的免费的 | 蜜臀av夜夜澡人人爽人人 | 99免费精品 | 黄色影院在线免费观看 | 97av色 | 免费在线视频一区二区 | av中文天堂 | 亚洲极色 | 国产乱码精品一区二区三区介绍 | 欧美激精品 | 精品在线视频一区 | 伊人中文字幕在线 | 91黄色影视 | 久久亚洲精品国产亚洲老地址 | 69av网| 久久激情电影 | 777xxx欧美| 久久久久久免费网 | 国产一区二区高清 | 亚洲精品国 | 国内精品久久久久久久久久久久 | 免费h视频| 日日夜夜精品免费 | 久久久久在线视频 | 精品久久久久国产免费第一页 | 亚洲国产福利视频 | 亚洲视频在线视频 | 日本久久高清视频 | 色丁香色婷婷 | 国产黄色片免费看 | 九九九九热精品免费视频点播观看 | 久久国产高清视频 | 亚洲国产欧美在线看片xxoo | 国产精品第 | 成人免费一级片 | 一区在线观看 | 日韩视频免费观看高清完整版在线 | 精品国产精品国产偷麻豆 | 激情欧美国产 | 日本一区二区三区免费看 | 五月婷婷黄色 | 亚洲欧美偷拍另类 | 日韩一级网站 | 久久精品9| 91传媒在线播放 | 国产又粗又硬又长又爽的视频 | 久精品视频在线观看 | 狠狠色丁香 | 狠日日| 91在线中文| 伊人av综合 | 国产视频一区在线 | 日韩精品一区二区三区丰满 | 永久免费观看视频 | 97在线视频免费看 | 日本精品在线看 | 91视频 - v11av | 亚洲精品高清一区二区三区四区 | 亚洲理论在线观看 | 人人精久| 在线观看免费色 | 97精品视频在线播放 | 日本中文不卡 | 久久好看免费视频 | 国产午夜不卡 | 黄色片视频在线观看 | 亚洲精品国产精品久久99热 | 欧美精品成人在线 | 国产精品中文字幕在线播放 | 天天色 天天 | 久久久久久久久免费 | 九色91在线 | 天天曰天天曰 | 九九久久免费 | 国产在线精品一区二区 | 成人免费网视频 | 免费黄色小网站 | 日韩中文字幕a | 中文字幕888 | 国产 色 | 亚洲最新av网址 | 免费看一级黄色大全 | 国产精品久久在线 | 久久精品视频网站 | 五月婷婷丁香综合 | 中文字幕超清在线免费 | 丁香激情综合国产 | 国内免费久久久久久久久久久 | 久久久久久久久久久网站 | 国产精品大片在线观看 | 亚洲v欧美v国产v在线观看 | 在线免费观看黄色 | 亚洲欧美日本A∨在线观看 青青河边草观看完整版高清 | 成人禁用看黄a在线 | 成人av免费网站 | 久久国产成人午夜av影院宅 | 日日躁夜夜躁aaaaxxxx | 成人午夜在线电影 | 五月激情天 | 国产又粗又长又硬免费视频 | 欧美性大战 | 婷婷国产精品 | 色综合天天综合在线视频 | 国产一区在线免费观看 | 日韩黄色免费电影 | 国产视频69 | 亚洲黄色片一级 | 免费黄色在线网站 | 日韩欧美大片免费观看 | 看av免费网站 | 91男人影院| 日本中文字幕电影在线免费观看 | 黄色片网站大全 | 81国产精品久久久久久久久久 | 干干夜夜 | av一级网站 | 在线免费黄 | 欧美日韩亚洲国产一区 | 国产精品久久久久毛片大屁完整版 | 特级毛片爽www免费版 | 国产精品久久电影网 | 国产99黄| 美女网站久久 | 在线超碰av | 国产99久久精品一区二区永久免费 | 亚洲欧洲精品久久 | 午夜三级理论 | 国产黄大片在线观看 | 亚洲资源在线观看 | 91视频在线免费 | 天天干天天拍天天操天天拍 | 国产一区欧美二区 | 欧美大片在线看免费观看 | 在线播放 日韩专区 | 欧美日韩视频在线观看一区二区 | 亚洲一区二区精品在线 | 成人免费xxxxxx视频 | 国产一区二区观看 | 精品国产一区二区三区久久 | 人人搞人人干 | 久久国产亚洲 | 国产九九精品视频 | 久久久久久久久久久久久9999 | 黄色高清视频在线观看 | 超碰97.com| 久久激情久久 | 草草草影院 | 免费高清av在线看 | 久久久国产精品久久久 | 久久精品视频网 | 国产日产精品久久久久快鸭 | 免费在线观看亚洲视频 | 91精品国产麻豆国产自产影视 | 一本一本久久aa综合精品 | 久久久久久久久艹 | 西西www4444大胆在线 | 日韩欧美大片免费观看 | 人操人 | 99久久精品久久久久久清纯 | 不卡的av中文字幕 | 国产91精品看黄网站在线观看动漫 | 久久久久免费精品视频 | 久久久国产精品人人片99精片欧美一 | 91免费的视频在线播放 | 成人在线视频免费看 | 九色自拍视频 | 国产又粗又硬又爽的视频 | 国产精品久久久久久久久久尿 | 五月天丁香视频 | 在线看片中文字幕 | 久久久免费精品国产一区二区 | 97视频免费在线 | 日韩欧美高清一区二区 | 好看av在线| 久久久久五月天 | 成人中心免费视频 | 久久草av | 国产午夜三级一二三区 | 91视频一8mav | 97在线超碰 | 国产在线观看免费av | 日韩av影片在线观看 | 免费观看91| 98久9在线 | 免费 | 一区二区中文字幕在线 | 亚洲自拍偷拍色图 | 中文字幕在线一区二区三区 | 在线 视频 亚洲 | 国产成人精品一区二区三区福利 | 91丨九色丨蝌蚪丨对白 | 国内精品视频久久 | 亚洲aⅴ免费在线观看 | 日韩免费视频网站 | 国产一区福利在线 | 免费看黄色大全 | 在线va网站 | 狠狠色丁香久久婷婷综 | 天天色中文 | 久久久国产电影 | 久久电影色 | 成年人视频在线免费 | 91在线小视频 | 亚洲一区二区视频在线播放 | 婷婷深爱网 | 国产精品美女网站 | 有没有在线观看av | 婷婷免费在线视频 | 精品一区二区三区香蕉蜜桃 | 中文字幕乱码在线播放 | 中文字幕在线日亚洲9 | 91久久在线观看 | 91看片麻豆 | 国产一线二线三线性视频 | 99久久久国产精品 | 精品视频免费久久久看 | 免费视频一区 | 最近中文字幕 | 国产一级做a | 超碰97网站 | 国产亚州精品视频 | 日韩一区二区三区高清在线观看 | 缴情综合网五月天 | 久久久久久国产精品久久 | 色国产精品一区在线观看 | 97视频亚洲 | 亚洲自拍偷拍色图 | 色偷偷中文字幕 | 亚洲夜夜网 | 欧洲av不卡 | 五月天婷婷视频 | 97超碰香蕉 | 亚洲国产资源 | 精品国产欧美一区二区 | 在线免费观看成人 | 日本公妇色中文字幕 | 91精品啪在线观看国产线免费 | 狠狠ri| 久久久久色 | 99久久精品日本一区二区免费 | 黄色a大片 | 在线观看激情av | 操操碰| 三级毛片视频 | 婷婷色在线视频 | 久久久久视 | 成人在线观看网址 | 国产成人精品av在线 | 500部大龄熟乱视频使用方法 | www.xxx.性狂虐| 欧美男同网站 | 日本久草电影 | 不卡中文字幕在线 | 天天射天天干天天插 | 婷婷在线色 | 精品国产乱码一区二 | 高清一区二区三区av | 另类老妇性bbwbbw高清 | 日韩免费高清在线 | 国产成人精品一区二区在线观看 | 色偷偷av男人天堂 | 草免费视频| 久久蜜臀一区二区三区av | av一级在线 | 日本视频网 | 成人丝袜 | 精品久久久久久一区二区里番 | 欧美极度另类性三渗透 | 狠狠狠色丁香综合久久天下网 | 久久精品视 | 日韩精品一区二区三区丰满 | 狠狠干综合网 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 国产成人精品一区二区在线 | 色婷婷精品大在线视频 | 91在线免费播放 | 久草在线这里只有精品 | 成人在线免费观看视视频 | 久久r精品 | 日韩欧美国产精品 | www.eeuss影院av撸 | 欧美日韩免费观看一区=区三区 | 九九视频免费观看视频精品 | 欧美成人91| 国产网站av | 亚洲一区久久久 | 久久人人爽人人爽人人 | 永久免费的啪啪网站免费观看浪潮 | av中文字幕不卡 | 久久天天躁 | 黄色成人av| 亚洲爱视频 | 在线 影视 一区 | 欧美91精品 | 中文字幕在线视频一区二区三区 | 久久看毛片 | 久久天天操 | 东方av在线免费观看 | 69av视频在线观看 | 欧美亚洲成人xxx | 国内一区二区视频 | 一级黄色片在线 | 免费在线观看av电影 | 国产传媒一区在线 | 日韩电影在线一区二区 | 国产又粗又硬又爽视频 | 手机成人av | 特级西西人体444是什么意思 | 91精品欧美一区二区三区 | 久草在线这里只有精品 | 成人在线免费视频观看 | 国产精品久久久久久久久久久久午夜片 | 国产精品一区专区欧美日韩 | 一级做a爱片性色毛片www | 久久美女高清视频 | 久久蜜臀一区二区三区av | 成人国产综合 | 99精品网站 | 日本三级全黄少妇三2023 | 99精品国产99久久久久久福利 | 91网免费观看 | 久久久999精品视频 国产美女免费观看 | 成人av一区二区在线观看 | 久久成人午夜 | 久久毛片视频 | 欧美日韩视频在线观看一区二区 | 天天操天天操天天操天天操天天操天天操 | 伊人五月综合 | 色在线免费 | 精品女同一区二区三区在线观看 | 精品免费一区二区三区 | av免费看在线 | 欧美性精品 | 国产福利精品一区二区 | 蜜臀久久99精品久久久无需会员 | 91福利区一区二区三区 | 欧美a视频在线观看 | 日韩免费高清在线观看 | 婷婷丁香激情网 | 91色蜜桃 | 日韩欧美高清不卡 | 中文字幕在线观看资源 | 日韩在线视频线视频免费网站 | 天天射网站 | 午夜精品福利在线 | 国产精品久久久久久欧美 | 91麻豆国产 | 毛片1000部免费看 | 欧美一级免费在线 | 久久综合九色综合久99 | 久久精品欧美一区二区三区麻豆 | 国产99久久久欧美黑人 | 久久国产精品99久久人人澡 | 精品在线播放 | 国产精品成人一区 | 久草久热 | 伊人宗合| 国产伦理久久精品久久久久_ | 极品久久久久久久 | 国产精品一区二区久久精品 | 日韩中文字幕视频在线观看 | 深爱激情综合网 | 亚洲精品在线观看免费 | 日韩影视大全 | 国产三级午夜理伦三级 | 丁香六月伊人 | 亚洲精品一区二区三区四区高清 | 久久人人爽人人爽 | 久久成人视屏 | 天天曰视频 | 特黄特黄的视频 | 国产一区二区在线观看免费 | 在线免费av网站 | 日韩乱码中文字幕 | 亚洲精品色视频 | 国产精品成人av在线 | 国产视频 亚洲精品 | 综合激情av| 国内精品久久久久久久久久久 | 人人干在线观看 | 欧美一区二区三区在线视频观看 | 久久综合激情 | www.亚洲黄色 | 91色在线观看 | 992tv在线观看 | 免费看一级特黄a大片 | 中文字幕免费一区 | 亚洲成人资源网 | 欧美国产日韩一区 | 久久综合射 | 99精品欧美一区二区三区 | 精品国产乱码久久久久久1区二区 | 99成人免费视频 | 亚洲成a人片在线www | 婷婷六月中文字幕 | 久综合网| 久久一久久| 成人三级黄色 | 婷婷丁香色综合狠狠色 | 亚洲人xxx| 香蕉免费在线 | 久久免费国产电影 | 婷婷久久一区二区三区 | 国产精品破处视频 | 麻豆成人小视频 | 亚洲精品久久激情国产片 | 在线之家官网 | 黄色软件视频大全免费下载 | 成人在线观看影院 | 99c视频高清免费观看 | 国产黄色av | 欧美a级一区二区 | 免费看毛片在线 | 91精品视频导航 | 欧美日韩免费观看一区二区三区 | 日韩天天操 | 伊人中文字幕在线 | 成人av资源网 | 玖玖玖在线观看 | 日韩在线电影一区二区 | 91精品在线免费视频 | 久久久久 免费视频 | 久99久在线 | 人人干免费| 日黄网站 | 日韩精品专区在线影院重磅 | 在线一二三区 | 伊人春色电影网 | 夜夜操狠狠干 | 久久综合狠狠综合久久激情 | 色综合国产 |