




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android10適配的示例分析
這篇文章主要介紹了Android10適配的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓在下帶著大家一起了解一下。準(zhǔn)備工作老規(guī)矩,首先將我們項(xiàng)目中的targetSdkVersion改為29。1.ScopedStorage(分區(qū)存儲(chǔ))說(shuō)明在Android10之前的版本上,我們?cè)谧鑫募牟僮鲿r(shí)都會(huì)申請(qǐng)存儲(chǔ)空間的讀寫(xiě)權(quán)限。但是這些權(quán)限完全被濫用,造成的問(wèn)題就是手機(jī)的存儲(chǔ)空間中充斥著大量不明作用的文件,并且應(yīng)用卸載后它也沒(méi)有刪除掉。為了解決這個(gè)問(wèn)題,Android10中引入了ScopedStorage的概念,通過(guò)添加外部存儲(chǔ)訪問(wèn)限制來(lái)實(shí)現(xiàn)更好的文件管理。首先明確一個(gè)概念,外部?jī)?chǔ)存和內(nèi)部?jī)?chǔ)存。內(nèi)部?jī)?chǔ)存:/data目錄。一般我們使用getFilesDir()或getCacheDir()方法獲取本應(yīng)用的內(nèi)部?jī)?chǔ)存路徑,讀寫(xiě)該路徑下的文件不需要申請(qǐng)儲(chǔ)存空間讀寫(xiě)權(quán)限,且卸載應(yīng)用時(shí)會(huì)自動(dòng)刪除。外部?jī)?chǔ)存:/storage或/mnt目錄。一般我們使用getExternalStorageDirectory()方法獲取的路徑來(lái)存取文件。因?yàn)椴煌瑥S商、系統(tǒng)版本的原因,所以上述的方法并沒(méi)有一個(gè)固定的文件路徑。了解了上面的概念,那我們所說(shuō)的外部?jī)?chǔ)存訪問(wèn)限制,可以認(rèn)為是針對(duì)getExternalStorageDirectory()路徑下的文件。具體的規(guī)則如下表:上圖將外部存儲(chǔ)空間分為了三部分:特定目錄(App-specific),使用getExternalFilesDir()或getExternalCacheDir()方法訪問(wèn)。無(wú)需權(quán)限,且卸載應(yīng)用時(shí)會(huì)自動(dòng)刪除。照片、視頻、音頻這類媒體文件。使用MediaStore訪問(wèn),訪問(wèn)其他應(yīng)用的媒體文件時(shí)需要READ_EXTERNAL_STORAGE權(quán)限。其他目錄,使用存儲(chǔ)訪問(wèn)框架SAF(StorageAccessFramwork)所以在Android10上即使你擁有了儲(chǔ)存空間的讀寫(xiě)權(quán)限,也無(wú)法保證可以正常的進(jìn)行文件的讀寫(xiě)操作。適配最簡(jiǎn)單粗暴的方法就是在AndroidManifest.xml中添加android:requestLegacyExternalStorage="true"來(lái)請(qǐng)求使用舊的存儲(chǔ)模式。但是我不推薦此方法。因?yàn)樵谙乱粋€(gè)版本的Android中,此條配置將會(huì)失效,將強(qiáng)制采用外部?jī)?chǔ)存限制。其實(shí)早在AndroidQBeta3之前都是強(qiáng)制的,但為了給開(kāi)發(fā)者適配的時(shí)間才沒(méi)有強(qiáng)制執(zhí)行。所以如果你不抓住這段時(shí)間去適配,那么今年下半年出了Android11。。。直接開(kāi)花~~如果你已經(jīng)適配Android10,這里有個(gè)現(xiàn)象要注意一下:如果應(yīng)用通過(guò)升級(jí)安裝,那么還會(huì)使用以前的儲(chǔ)存模式(LegacyView)。只有通過(guò)首次安裝或是卸載重新安裝才能啟用新模式(FilteredView)。所以在適配時(shí),我們的判斷代碼如下:
//
使用Environment.isExternalStorageLegacy()來(lái)檢查APP的運(yùn)行模式
if
(Build.VERSION.SDK_INT
>=
Build.VERSION_CODES.Q
&&
!Environment.isExternalStorageLegacy())
{
}這樣的好處是你可以在用戶升級(jí)后,能方便的將用戶的數(shù)據(jù)移動(dòng)至應(yīng)用的特定目錄。否則你只能通過(guò)SAF去移動(dòng),這樣會(huì)非常麻煩。如果你要移動(dòng)數(shù)據(jù)注意只適用于Android10下,所以現(xiàn)在適配反而是一個(gè)好時(shí)機(jī)。當(dāng)然如果你不需要遷移數(shù)據(jù),那適配會(huì)更省事。下面就說(shuō)說(shuō)推薦適配方案:對(duì)于應(yīng)用中涉及的文件操作,修改一下你的文件路徑。以前我們習(xí)慣使用Environment.getExternalStorageDirectory()方法,那么現(xiàn)在可以使用getExternalFilesDir()方法(包括下載的安裝包這類的文件)。如果是緩存類型文件,可以放到getExternalCacheDir()路徑下?;蛘呤褂肕ediaStore,將文件存至對(duì)應(yīng)的媒體類型中(圖片:MediaStore.Images,視頻:MediaStore.Video,音頻:MediaStore.Audio),不過(guò)僅限于多媒體文件。下面代碼將圖片保存到公共目錄下,返回Uri:public
static
Uri
createImageUri(Context
context)
{
ContentValues
values
=
new
ContentValues();
//
需要指定文件信息時(shí),非必須
values.put(MediaStore.Images.Media.DESCRIPTION,
"This
is
an
image");
values.put(MediaStore.Images.Media.DISPLAY_NAME,
"Image.png");
values.put(MediaStore.Images.Media.MIME_TYPE,
"image/png");
values.put(MediaStore.Images.Media.TITLE,
"Image.png");
values.put(MediaStore.Images.Media.RELATIVE_PATH,
"Pictures/test");
return
context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values);
}對(duì)于媒體資源的訪問(wèn):比如圖片選擇器這類的場(chǎng)景。無(wú)法直接使用File,而應(yīng)使用Uri。否則報(bào)錯(cuò)如下:java.io.FileNotFoundException:
open
failed:
EACCES
(Permission
denied)比如我在適配項(xiàng)目中使用的圖片選擇器時(shí),首先修改了Glide通過(guò)加載File的方式顯示圖片。改為加載Uri的方式,否則圖片無(wú)法顯示出來(lái)。Uri的獲取方式還是使用MediaStore:String
id
=
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
Uri
uri
=
Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id);其次為了便于不影響之前選擇圖片返回File的邏輯(因?yàn)橐话愣际巧蟼鱂ile,沒(méi)有直接上傳Uri的操作),所以我將最終選擇的文件又轉(zhuǎn)存進(jìn)了getExternalFilesDir(),主要代碼如下:
File
imgFile
=
this.getExternalFilesDir("image");
if
(!imgFile.exists()){
imgFile.mkdir();
}
try
{
File
file
=
new
File(imgFile.getAbsolutePath()
+
File.separator
+
System.currentTimeMillis()
+
".jpg");
//
使用openInputStream(uri)方法獲取字節(jié)輸入流
InputStream
fileInputStream
=
getContentResolver().openInputStream(uri);
FileOutputStream
fileOutputStream
=
new
FileOutputStream(file);
byte[]
buffer
=
new
byte[1024];
int
byteRead;
while
(-1
!=
(byteRead
=
fileInputStream.read(buffer)))
{
fileOutputStream.write(buffer,
0,
byteRead);
}
fileInputStream.close();
fileOutputStream.flush();
fileOutputStream.close();
//
文件可用新路徑
file.getAbsolutePath()
}
catch
(Exception
e)
{
e.printStackTrace();
}如果你要獲取圖片中的地理位置信息,需要申請(qǐng)ACCESS_MEDIA_LOCATION權(quán)限,并使用MediaStore.setRequireOriginal()獲取。下面是官方的示例代碼:
Uri
photoUri
=
Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
cursor.getString(idColumnIndex));
final
double[]
latLong;
//
從ExifInterface類獲取位置信息
photoUri
=
MediaStore.setRequireOriginal(photoUri);
InputStream
stream
=
getContentResolver().openInputStream(photoUri);
if
(stream
!=
null)
{
ExifInterface
exifInterface
=
new
ExifInterface(stream);
double[]
returnedLatLong
=
exifInterface.getLatLong();
//
If
lat/long
is
null,
fall
back
to
the
coordinates
(0,
0).
latLong
=
returnedLatLong
!=
null
?
returnedLatLong
:
new
double[2];
//
Don't
reuse
the
stream
associated
with
the
instance
of
"ExifInterface".
stream.close();
}
else
{
//
Failed
to
load
the
stream,
so
return
the
coordinates
(0,
0).
latLong
=
new
double[2];
}這樣下來(lái),一個(gè)圖片選擇器就基本適配完了。補(bǔ)充應(yīng)用在卸載后,會(huì)將App-specific目錄下的數(shù)據(jù)刪除,如果在AndroidManifest.xml中聲明:android:hasFragileUserData="true"用戶可以選擇是否保留。對(duì)于SAF的使用,可以查看我之前寫(xiě)的SAF使用攻略,這里就不展開(kāi)說(shuō)了。最后這里有一個(gè)介紹ScopedStorage的視頻,推薦觀看:2.權(quán)限變化從6.0開(kāi)始,基本每次都會(huì)有權(quán)限方面變動(dòng),這次也不例外。(前幾天發(fā)布了Android11的預(yù)覽版,看來(lái)也有權(quán)限方面的變化。。。單次權(quán)限即將到來(lái))1.在后臺(tái)運(yùn)行時(shí)訪問(wèn)設(shè)備位置信息需要權(quán)限Android10引入了ACCESS_BACKGROUND_LOCATION權(quán)限(危險(xiǎn)權(quán)限)。<uses-permission
android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>該權(quán)限允許應(yīng)用程序在后臺(tái)訪問(wèn)位置。如果請(qǐng)求此權(quán)限,則還必須請(qǐng)求ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION權(quán)限。只請(qǐng)求此權(quán)限無(wú)效果。在Android10的設(shè)備上,如果你的應(yīng)用的targetSdkVersion<29,則在請(qǐng)求ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION權(quán)限時(shí),系統(tǒng)會(huì)自動(dòng)同時(shí)請(qǐng)求ACCESS_BACKGROUND_LOCATION。在請(qǐng)求彈框中,選擇“始終允許”表示同意后臺(tái)獲取位置信息,選擇“僅在應(yīng)用使用過(guò)程中允許”或"拒絕"選項(xiàng)表示拒絕授權(quán)。如果你的應(yīng)用的targetSdkVersion>=29,則請(qǐng)求ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION權(quán)限表示在前臺(tái)時(shí)擁有訪問(wèn)設(shè)備位置信息的權(quán)。在請(qǐng)求彈框中,選擇“始終允許”表示前后臺(tái)都可以獲取位置信息,選擇“僅在應(yīng)用使用過(guò)程中允許”只表示擁有前臺(tái)的權(quán)限??偨Y(jié)一下就是下圖:
其實(shí)官方不推薦你使用申請(qǐng)后臺(tái)訪問(wèn)權(quán)的方式,因?yàn)檫@樣的結(jié)果無(wú)非就是多請(qǐng)求一個(gè)權(quán)限,那么這像變更還有什么意義?申請(qǐng)過(guò)多的權(quán)限,也會(huì)造成用戶的反感。所以官方推薦使用前臺(tái)服務(wù)來(lái)實(shí)現(xiàn),在前臺(tái)服務(wù)中獲取位置信息。首先在清單中對(duì)應(yīng)的service中添加android:foregroundServiceType="location":
<service
android:name="MyNavigationService"
android:foregroundServiceType="location"
...
>
...
</service>啟動(dòng)前臺(tái)服務(wù)前檢查是否具有前臺(tái)的訪問(wèn)權(quán)限:
boolean
permissionApproved
=
ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION)
==
PackageManager.PERMISSION_GRANTED;
if
(permissionApproved)
{
//
啟動(dòng)前臺(tái)服務(wù)
}
else
{
//
請(qǐng)求前臺(tái)訪問(wèn)位置權(quán)限
}如此一來(lái)就可以在Service中獲取位置信息。2.一些電話、藍(lán)牙和WLAN的API需要精確位置權(quán)限下面列舉了Android10中必須具有ACCESS_FINE_LOCATION權(quán)限才能使用類和方法:電話
TelephonyManagergetCellLocation()getAllCellInfo()requestNetworkScan()requestCellInfoUpdate()getAvailableNetworks()getServiceState()TelephonyScanManagerrequestNetworkScan()TelephonyScanManager.NetworkScanCallbackonResults()PhoneStateListeneronCellLocationChanged()onCellInfoChanged()onServiceStateChanged()WLAN
WifiManagerstartScan()getScanResults()getConnectionInfo()getConfiguredNetworks()WifiAwareManagerWifiP2pManagerWifiRttManager藍(lán)牙
BluetoothAdapterstartDiscovery()startLeScan()BluetoothAdapter.LeScanCallbackBluetoothLeScannerstartScan()我們可以根據(jù)上面提供的具體類和方法,在適配項(xiàng)目中檢查是否有使用到并及時(shí)處理。3.ACCESS_MEDIA_LOCATIONAndroid10新增權(quán)限,上面有提到,不贅述了。4.PROCESS_OUTGOING_CALLSAndroid10上該權(quán)限已廢棄。3.后臺(tái)啟動(dòng)Activity的限制簡(jiǎn)單解釋就是應(yīng)用處于后臺(tái)時(shí),無(wú)法啟動(dòng)Activity。比如點(diǎn)開(kāi)一個(gè)應(yīng)用會(huì)進(jìn)入啟動(dòng)頁(yè)或者廣告頁(yè),一般會(huì)有幾秒的延時(shí)再跳轉(zhuǎn)至首頁(yè)。如果這期間你退到后臺(tái),那么你將無(wú)法看到跳轉(zhuǎn)過(guò)程。而在之前的版本中,會(huì)強(qiáng)制彈出頁(yè)面至前臺(tái)。既然是限制,那么肯定有不受限的情況,主要有以下幾點(diǎn):應(yīng)用具有可見(jiàn)窗口,例如前臺(tái)Activity。應(yīng)用在前臺(tái)任務(wù)的返回棧中已有的Activity。應(yīng)用在Recents上現(xiàn)有任務(wù)的返回棧中已有的Activity。Recents就是我們的任務(wù)管理列表。應(yīng)用收到系統(tǒng)的PendingIntent通知。應(yīng)用收到它應(yīng)該在其中啟動(dòng)界面的系統(tǒng)廣播。示例包括ACTION_NEW_OUTGOING_CALL和SECRET_CODE_ACTION。應(yīng)用可在廣播發(fā)送幾秒鐘后啟動(dòng)Activity。用戶已向應(yīng)用授予SYSTEM_ALERT_WINDOW權(quán)限,或是在應(yīng)用權(quán)限頁(yè)開(kāi)啟后臺(tái)彈出頁(yè)面的開(kāi)關(guān)。因?yàn)榇隧?xiàng)行為變更適用于在Android10上運(yùn)行的所有應(yīng)用,所以這一限制導(dǎo)致最明顯的問(wèn)題就是點(diǎn)擊推送信息時(shí),有些應(yīng)用無(wú)法進(jìn)行正常的跳轉(zhuǎn)(具體的實(shí)現(xiàn)問(wèn)題導(dǎo)致)。所以針對(duì)這類問(wèn)題,可以采取PendingIntent的方式,發(fā)送通知時(shí)使用setContentIntent方法。當(dāng)然你也可以申請(qǐng)相應(yīng)權(quán)限或者白名單:不過(guò)申請(qǐng)白名單這種方法受各種手機(jī)廠商所限,很麻煩。感覺(jué)還不如引導(dǎo)用戶手動(dòng)開(kāi)啟權(quán)限。。。對(duì)于全屏intent,注意設(shè)置最高優(yōu)先級(jí)和添加USE_FULL_SCREEN_INTENT權(quán)限,這是一個(gè)普通權(quán)限。比如微信來(lái)語(yǔ)音或者視頻通話時(shí),彈出的接聽(tīng)頁(yè)面就是使用這一功能。
<uses-permission
android:name="android.permission.USE_FULL_SCREEN_INTENT"/>Intent
fullScreenIntent
=
new
Intent(this,
CallActivity.class);
PendingIntent
fullScreenPendingIntent
=
PendingIntent.getActivity(this,
0,
fullScreenIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder
notificationBuilder
=
new
NotificationCompat.Builder(this,
CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Incoming
call")
.setContentText("(919)
555-1234")
.setPriority(NotificationCompat.PRIORITY_HIGH)
//
<
高優(yōu)先級(jí)
.setCategory(NotificationCompat.CATEGORY_CALL)
//
Use
a
full-screen
intent
only
for
the
highest-priority
alerts
where
you
//
have
an
associated
activity
that
you
would
like
to
launch
after
the
user
//
interacts
with
the
notification.
Also,
if
your
app
targets
Android
10
//
or
higher,
you
need
to
request
the
USE_FULL_SCREEN_INTENT
permission
in
//
order
for
the
platform
to
invoke
this
notification.
.setFullScreenIntent(fullScreenPendingIntent,
true);
//
<
全屏
intent
Notification
incomingCallNotification
=
notificationBuilder.build();注意:在部分手機(jī)上,直接設(shè)置setPriority無(wú)效(或者說(shuō)以渠道優(yōu)先級(jí)為準(zhǔn))。所以需要?jiǎng)?chuàng)建通知渠道時(shí)將重要性設(shè)置為IMPORTANCE_HIGH。NotificationChannel
channel
=
new
NotificationChannel(channelId,
"xxx",
NotificationManager.IMPORTANCE_HIGH);后臺(tái)啟動(dòng)Activity的限制的目的是為了減少對(duì)用戶操作的中斷。如果你有要彈出的頁(yè)面,推薦你先彈出通知,讓用戶自己選擇接下來(lái)的操作,而不是一股腦的強(qiáng)制彈出。(如果你的全屏intent都讓用戶反感,那他也可以關(guān)掉你的通知,不至于任你擺布。)4.深色主題Android10新增了一個(gè)系統(tǒng)級(jí)的深色主題(在系統(tǒng)設(shè)置中開(kāi)啟)。雖然深色主題并不是強(qiáng)制適配項(xiàng),但是它可以帶給用戶更好的體驗(yàn):可大幅減少耗電量。OLED屏幕中每個(gè)像素都是自主發(fā)光,所以在顯示深色元素時(shí)像素所消耗的電流更低,尤其在純黑顏色時(shí)像素點(diǎn)可以完全關(guān)閉來(lái)達(dá)到省電的效果。為弱視以及對(duì)強(qiáng)光敏感的用戶提高可視性。深色可以降低屏幕的整體視覺(jué)亮度,減少對(duì)眼睛的視覺(jué)壓力。讓所有人都可以在光線較暗的環(huán)境中更輕松地使用設(shè)備。適配方法有兩種:1.手動(dòng)適配(資源替換)官方文檔中提到的繼承Theme.AppCompat.DayNight或者Theme.MaterialComponents.DayNight的方法,但這只是將我們使用的各種View的默認(rèn)樣式進(jìn)行了適配,并不太適用于實(shí)際項(xiàng)目的適配。因?yàn)榫唧w的項(xiàng)目中的View都按照設(shè)計(jì)的風(fēng)格進(jìn)行了重定義。其實(shí)適配的方法很簡(jiǎn)單,類似屏幕適配、國(guó)際化的操作,并不需要繼承上面的主題。比如你要修改顏色,就在res下新建values-night目錄,創(chuàng)建對(duì)應(yīng)的colors.xml文件。將具體要修改的色值定義在里面。圖標(biāo)之類的也是一個(gè)思路,創(chuàng)建對(duì)應(yīng)的drawable-night目錄。只要你之前的代碼不是硬編碼且代碼規(guī)范,那么適配起來(lái)還是很輕松。2.自動(dòng)適配(ForceDark)Android10提供ForceDark功能。一如其名,此功能可讓開(kāi)發(fā)者快速實(shí)現(xiàn)深色主題背景,而無(wú)需明確設(shè)置DayNight主題背景。如果您的應(yīng)用采用淺色主題背景,則ForceDark會(huì)分析應(yīng)用的每個(gè)視圖,并在相應(yīng)視圖在屏幕上顯示之前,自動(dòng)應(yīng)用深色主題背景。有些開(kāi)發(fā)者會(huì)混合使用ForceDark和本機(jī)實(shí)現(xiàn),以縮短實(shí)現(xiàn)深色主題背景所需的時(shí)間。應(yīng)用必須選擇啟用ForceDark,方法是在其主題背景中設(shè)置android:forceDarkAllowed="true"。此屬性會(huì)在所有系統(tǒng)及AndroidX提供的淺色主題背景(例如Theme.Material.Light)上設(shè)置。使用ForceDark時(shí),您應(yīng)確保全面測(cè)試應(yīng)用,并根據(jù)需要排除視圖。如果您的應(yīng)用使用DarkTheme主題(例如Theme.Material),則系統(tǒng)不會(huì)應(yīng)用ForceDark。同樣,如果應(yīng)用的主題背景繼承自DayNight主題(例如Theme.AppCompat.DayNight),則系統(tǒng)不會(huì)應(yīng)用ForceDark,因?yàn)闀?huì)自動(dòng)切換主題背景。您可以通過(guò)android:forceDarkAllowed布局屬性或setForceDarkAllowed(boolean)在特定視圖上控制ForceDark。上述內(nèi)容我直接照搬文檔的說(shuō)明??偨Y(jié)一下,使用ForceDark需要注意幾點(diǎn):如果使用的是DayNight或DarkTheme主題,則設(shè)置forceDarkAllowed不生效。如果有需要排除適配的部分,可以在對(duì)應(yīng)的View上設(shè)置forceDarkAllowed為false。這里說(shuō)說(shuō)我實(shí)際使用此方法的感受:整體還是不錯(cuò)的,設(shè)置的色值會(huì)自動(dòng)取反。但也因此顏色不受控制,能否達(dá)到預(yù)期效果是個(gè)需要注意的問(wèn)題。追求快速適配可以采取此方案。手動(dòng)切換主題使用AppCompatDelegate.setDefaultNightMode(@NightModeintmode)方法,其中參數(shù)mode有以下幾種:淺色-MODE_NIGHT_NO深色-MODE_NIGHT_YES由省電模式設(shè)置-MODE_NIGHT_AUTO_BATTERY系統(tǒng)默認(rèn)-MODE_NIGHT_FOLLOW_SYSTEM下面的代碼是官方Demo中的使用示例:public
class
ThemeHelper
{
public
static
final
String
LIGHT_MODE
=
"light";
public
static
final
String
DARK_MODE
=
"dark";
public
static
final
String
DEFAULT_MODE
=
"default";
public
static
void
applyTheme(@NonNull
String
themePref)
{
switch
(themePref)
{
case
LIGHT_MODE:
{
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
break;
}
case
DARK_MODE:
{
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
break;
}
default:
{
if
(Build.VERSION.SDK_INT
>=
Build.VERSION_CODES.Q)
{
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
else
{
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
}
break;
}
}
}
}通過(guò)AppCompatDelegate.getDefaultNightMode()方法,可以獲取到當(dāng)前的模式,這樣便于代碼中去適配。監(jiān)聽(tīng)深色主題是否開(kāi)啟首先在清單文件中給對(duì)應(yīng)的Activity配置android:configChanges="uiMode":
<activity
android:name=".MyActivity"
android:configChanges="uiMode"
/>這樣在onConfigurationChanged方法中就可以獲?。?@Override
public
void
onConfigurationChanged(@NonNull
Configuration
newConfig)
{
super.onConfigurationChanged(newConfig);
int
currentNightMode
=
newConfig.uiMode
&
Configuration.UI_MODE_NIGHT_MASK;
switch
(currentNightMode)
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 分布式光伏發(fā)電項(xiàng)目前景與可行性分析
- 防拐賣(mài)防性侵課件
- 江蘇省常州一中2025屆高三5月測(cè)試(一卷)語(yǔ)文試題試卷含解析
- 建東職業(yè)技術(shù)學(xué)院《物理治療基礎(chǔ)(含評(píng)定、理療)》2023-2024學(xué)年第二學(xué)期期末試卷
- 湖南都市職業(yè)學(xué)院《皮膚生理學(xué)》2023-2024學(xué)年第二學(xué)期期末試卷
- 長(zhǎng)三角體育節(jié)項(xiàng)目招標(biāo)文件
- 南京理工大學(xué)紫金學(xué)院《心理咨詢倫理》2023-2024學(xué)年第一學(xué)期期末試卷
- 贛州師范高等??茖W(xué)?!督逃虒W(xué)知識(shí)與能力》2023-2024學(xué)年第二學(xué)期期末試卷
- 上海中華職業(yè)技術(shù)學(xué)院《設(shè)計(jì)制圖基礎(chǔ)》2023-2024學(xué)年第二學(xué)期期末試卷
- 安徽省示范高中皖北協(xié)作區(qū)2025屆高三下學(xué)期3月第27屆聯(lián)考試題 語(yǔ)文 含解析
- YS/T 555.1-2009鉬精礦化學(xué)分析方法鉬量的測(cè)定鉬酸鉛重量法
- 水利工程(水電站)全套安全生產(chǎn)操作規(guī)程
- 學(xué)生宿舍宿管人員查寢記錄表
- 配電間巡檢記錄表
- ISO 31000-2018 風(fēng)險(xiǎn)管理標(biāo)準(zhǔn)-中文版
- 雙人法成生命支持評(píng)分表
- DBJ61_T 179-2021 房屋建筑與市政基礎(chǔ)設(shè)施工程專業(yè)人員配備標(biāo)準(zhǔn)
- 畢業(yè)設(shè)計(jì)三交河煤礦2煤層開(kāi)采初步設(shè)計(jì)
- 預(yù)應(yīng)力錨索施工全套表格模板
- 食品流通許可證食品經(jīng)營(yíng)操作流程圖
- 風(fēng)電場(chǎng)工作安全培訓(xùn)
評(píng)論
0/150
提交評(píng)論