android JeckPack官方文档学习
1.簡介
androidx?命名空間包含?Android Jetpack?庫
android.support?:版本 28.0.0最后一個版本
Jetpack 庫在?androidx?命名空間中發布
1.1 使用:
在項目中使用 androidx 庫:
gradle.properties中
android.useAndroidX true
android.enableJetifier true 通過重寫其二進制文件來自動遷移現有的第三方庫
1.2 在項目中使用Jetpack 庫:
settings.gradle:
dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()jcenter()} }build.gradle?
dependencies {val lifecycle_version = "2.2.0"implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")... }1.3 JetPack庫:
activity ads annotation appcompat appsearch arch.core asynclayoutinflater autofill
benchmark biometric browser
car-app camera(*) cardview collection compose compose.animation compose.material ?compose.material3 compose.runtime compose.ui
concurrent constrainlayout contentpaper coordinatorlayout core cursoradapter customview databinding datastore
documentfile draganddrop drawerlayout dynamicanimation
emoji emoji2 enterprise exifinterface?
fragment
games glance gridlayout health heifwriter hilt
interpolator
jetifier
leanback legacy lifecycle loader localbroadcastmanager
media media2 media3 mediarouter multidex metrics
navigation
paging palette percentlayout preference print profileinstaller
recylerview remotecallback resourceinspection room
savestate security sharetarget slice slidingpanelayout startup sqlite swiperefreshlayout
test textclassifier
tracing transition tvprovider?
vectordrawable viewpager viewpager2 wear wear.compose wear.tiles wear.watchface webkit window work
material Design
數據綁定(Data Binding)
Lifecycles(關于 activity 以及 fragment 的生命周期)
LiveData(用于更新界面的數據,跟大家之前理解的 model 不一樣,它可以感應生命周期)
Navigation(關于 APP 內的導航跳轉)
Paging(可以理解為分頁加載)
Room(原來有很多第三方的數據庫 ormlite 之類的,現在 Google 出手了,這是對 sqlite 數據庫的進一步封裝)
ViewModel(前面說了 LiveData,而 ViewModel 就是用來管理 LiveData 的,用于連接 view 視圖層和 LiveData 數據層,更重要的是它可以感應聲明周期)
WorkManager(用于管理后臺任務)。
2.Activity
2.1 生命周期:
onCreate
OnStart
onResume
onPause
onStop:
????????????????????????應用應釋放或調整在應用對用戶不可見時的無用資源。
????????????????????????例如,應用可以暫停動畫效果,或從精確位置更新切換到粗略位置更新。執行 CPU 相對密集的關閉操作
onDestory:應釋放先前的回調(例如?onStop())尚未釋放的所有資源。
onSaveInstanceState:保存有關 Activity 視圖層次結構狀態的瞬時信息,例如?EditText?微件中的文本或?ListView?微件的滾動位置。--onCreate中恢復
2.2 Activity的任務棧
使用清單文件
launchMode :standard singleTop singleTask singleInstance
FLAG_ACTIVITY_NEW_TASK(singleTask)
FLAG_ACTIVITY_SINGLE_TOP(singleTop)
FLAG_ACTIVITY_CLEAR_TOP:會銷毀位于它之上的所有其他 Activity,并通過 onNewIntent() 將此 intent 傳送給它的已恢復實例
taskAffinity:同一應用中的所有 Activity 彼此具有親和性
FLAG_ACTIVITY_NEW_TASK allowTaskReparenting起作用
2.3 清除返回堆棧
alwaysRetainTaskState(根Activity設置-不會清除)
clearTaskOnLaunch(根Activity設置-會清除)
finishOnTaskLaunch(單個Activity-會清楚,包括根)
public class CameraComponent implements LifecycleObserver {...@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)public void initializeCamera() {if (camera == null) {getCamera();}}}3.Fragment
3.1 帶參數創建fragment
getSupportFragmentManager().beginTransaction().setReorderingAllowed(true).add(R.id.fragment_container_view, ExampleFragment.class, bundle).commit();--對應@Overridepublic void onViewCreated(@NonNull View view, Bundle savedInstanceState) {int someInt = requireArguments().getInt("some_int");...}3.2 FragmentManager
Activity訪問:
管理 Fragment 子級的 FragmentManager 的引用?getChildFragmentManager()?
訪問其宿主 FragmentManager,可以使用 getParentFragmentManager()。
3.3 任務棧
addToBackStack--popBackStack
如果您在執行移除 Fragment 的事務時未調用?addToBackStack(),則提交事務時會銷毀已移除的 Fragment,用戶無法返回到該 Fragment。
如果您在移除某個 Fragment 時調用了?addToBackStack(),則該 Fragment 只會?STOPPED,稍后當用戶返回時它會?RESUMED
saveBackStack()保存?和?restoreBackStack()彈出
3.4FragmentFactory
FragmentFactory的作用很簡單:就是幫助開發者自定義并使用帶參數的Fragment構造器。這對于dagger、koin等某些DI框架的使用場景中會非常有幫助
通過注解的方式來管理整個應用中的自定義的Fragment
自定義FragmentFactory public class MyFragmentFactory extends FragmentFactory {private DessertsRepository repository;public MyFragmentFactory(DessertsRepository repository) {super();this.repository = repository;}@NonNull@Overridepublic Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {Class<? extends Fragment> fragmentClass = loadFragmentClass(classLoader, className);if (fragmentClass == DessertsFragment.class) {return new DessertsFragment(repository);//這邊newFragment} else {return super.instantiate(classLoader, className);}} }getSupportFragmentManager().setFragmentFactory(new MyFragmentFactory(repository));1.注解指定fragment @TargetFragmentTag("fragment1")2.使用 mFactory=FragmentFactory.getInstance().init(this, R.id.mContentFl); mFactory.showFragment(FragmentTag.FRAGMENT1)3.5動畫
setCustomAnimations3.6Fragment狀態
- INITIALIZED
- CREATED
- STARTED
- RESUMED
- DESTROYED
3.7Fragment通信
類型
? ? ? ? Activity之間的通信
? ? ? ? Fragment之間的通信
? ? ? ? 與子Fragment之間的通信
方法:
? ? ? ? ?使用ViewModel共享數據
? ? ? ? 使用接口共享數據
Fragment自己的toolbar
onCreate-- setHasOptionsMenu(true);onCreateOptionsMenu -- inflater.inflate(R.menu.sample_menu, menu); onOptionsItemSelected--點擊事件 onPrepareOptionsMenu--修改菜單 requireActivity().invalidateOptionsMenu()---更新菜單xml中使用 <androidx.appcompat.widget.Toolbarandroid:id="@+id/myToolbar"... /> java中 onViewCreated--viewBinding.myToolbar.inflateMenu viewBinding.myToolbar.setOnMenuItemClickListener--點擊事件 viewBinding.myToolbar.setNavigationIcon(R.drawable.ic_back)--返回 viewBinding.myToolbar.setNavigationOnClickListener3.8 ? DialogFragment
? ? ? ? ?onCreateDialog()onDismiss()?onCancel()
3.9 調試fragment
adb shell setprop log.tag.FragmentManager DEBUG 代碼捕獲: addOnContextAvailableListener((context) -> {if(context.getResources().getBoolean(R.bool.enable_strict_mode)) {getSupportFragmentManager().setStrictModePolicy(new FragmentStrictMode.Policy.Builder().penaltyDeath().detectFragmentReuse().allowViolation(FirstFragment.class, FragmentReuseViolation.class).build());}}4.lifeCycle
4.1 android觀察者模式
4.2?lifeCycle主要類
LifecycleOwner:生命周期的擁有者,一般是Activity和Fragment實現這個接口,只有一個方法getLifecycle():Lifecycle
Lifecycle:表示一個生命周期過程對象,可以添加生命周期觀察者
Lifecycle.State:生命周期枚舉,有DESTROYED、INITIALIZED、CREATED、STARTED、RESUMED
LifecycleRegistry:Lifecycle的子類,對Lifecycle中的抽象方法進行了實現
LifecycleObserver:生命周期觀察者,雖是個空接口,但可以通過Lifecycle的注解定義所有的生命周期方法
Lifecycle.Event:生命周期事件,和Activity/Fragment的相應生命周期回調一一對應,有ON_CREATE、ON_START、ON_RESUME、ON_PAUSE、ON_STOP、ON_DESTROY、ON_ANY七種取值,一般和OnLifecycleEvent注解一起使用,用來在LifecycleObserver中標注方法屬于哪個生命周期
lifecycle(LifecycleRegistry)相當于被觀察者,可以注冊,移除通知觀察者DefaultLifecycleObserver
-----------------------DefaultLifecycleObserver class MyLocationListener implements DefaultLifecycleObserver {private boolean enabled = false;public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {...}@Overridepublic void onStart(LifecycleOwner owner) {//LifecycleOwnerif (enabled) {// connect}}public void enable() {enabled = true;if (lifecycle.getCurrentState().isAtLeast(STARTED)) {// connect if not connected}}@Overridepublic void onStop(LifecycleOwner owner) {//LifecycleOwner// disconnect if connected} }------------------------Activity class MyActivity extends AppCompatActivity {private MyLocationListener myLocationListener;public void onCreate(...) {myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {// update UI});Util.checkUserStatus(result -> {if (result) {myLocationListener.enable();}});} }---------------------------自定義LifecycleOwner 1、實現LifecycleOwner 接口的方法:getLifecycle() 2、注冊Lifecycle new LifecycleRegistry(this) 3、在Activity生命周期函數中分發事件public class MyActivity extends Activity implements LifecycleOwner {//private LifecycleRegistry lifecycleRegistry;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//初始化lifecycleRegistrylifecycleRegistry = new LifecycleRegistry(this);lifecycleRegistry.markState(Lifecycle.State.CREATED);}@Overridepublic void onStart() {super.onStart();lifecycleRegistry.markState(Lifecycle.State.STARTED);}@NonNull@Overridepublic Lifecycle getLifecycle() {return lifecycleRegistry;} }5.ViewModel
1.數據綁定
以上布局文件名為?activity_main.xml,因此生成的對應類為?ActivityMainBinding
android:paddingLeft-----@BindingAdapter("android:paddingLeft")可觀察的字段
* ObservableBoolean* ObservableByte* ObservableChar* ObservableShort
* ObservableInt* ObservableLong* ObservableFloat* ObservableDouble
* ObservableParcelable
可觀察的集合
ObservableArrayMap?ObservableArrayList
可觀察的對象
BaseObservable
將布局綁定在構架組件
-------------------- activity(ViewModel)class ViewModelActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);//把viewModel設置到databinding上UserModel userModel = new ViewModelProvider(this).get(UserModel.class);binding.viewmodel = userModel;}}---------------------ViewModel1 class ScheduleViewModel extends ViewModel {LiveData username;public ScheduleViewModel() {String result = Repository.userName;userName = Transformations.map(result, result -> result.value);}} ---------------------ViewModel2--Observable class ObservableViewModel extends ViewModel implements Observable {private PropertyChangeRegistry callbacks = new PropertyChangeRegistry();@Overrideprotected void addOnPropertyChangedCallback(Observable.OnPropertyChangedCallback callback) {callbacks.add(callback);}@Overrideprotected void removeOnPropertyChangedCallback(Observable.OnPropertyChangedCallback callback) {callbacks.remove(callback);}void notifyChange() {callbacks.notifyCallbacks(this, 0, null);}void notifyPropertyChanged(int fieldId) {callbacks.notifyCallbacks(this, fieldId, null);}}---------------------xml <CheckBoxandroid:id="@+id/rememberMeCheckBox"android:checked="@{viewmodel.rememberMe}"android:onCheckedChanged="@{() -> viewmodel.rememberMeChanged()}" />----------------------雙向數據綁定@=<CheckBoxandroid:id="@+id/rememberMeCheckBox"android:checked="@={viewmodel.rememberMe}"/>-----------------實體類 @InverseBindingAdapter("time")public static Time getTime(MyView view) {return view.getTime();}2.MVVM的概念
View發生改變時,ViewModel會通知Model進行更新數據
Model數據更新后,ViewModel會通知View更新顯示
谷歌發布MVVM支持DataBinding:能將數據綁定到xml中
現在谷歌又推出ViewModel和LiveData組件更方便實現MVVM
MVC MVP MVVM的區別
MVC:缺點 Activity 責任過重,Activity充當了V和C,TextView.setTextView()這種邏輯應該放在view
V(SetText)C (Activity中獲取數據并顯示V上)M(數據)
MVP:MVP把Activity作為view,View并不直接去請求Model,由P去請求
V/A(Activity中通過回調顯示V上)P(獲取數據)M(數據)
MVVM:省略了findViewbyId,setText的過程
V(xml activity) VM (實體類)M ? 省略了
6.LiveData
6.1優勢
- UI和實時數據保持一致
因為LiveData采用的是觀察者模式,這樣一來就可以在數據發生改變時獲得通知,更新UI。
- 不會發生內存泄露
觀察者被綁定到組件的生命周期上,當被綁定的組件銷毀(onDestroy)時,觀察者會立刻自動清理自身的數據。
- 不會再產生由于Activity處于stop狀態而引起的崩潰
例如:當Activity處于后臺狀態時,是不會收到LiveData的任何事件的。
- 不需要再解決生命周期帶來的問題
LiveData可以感知被綁定的組件的生命周期,只有在活躍狀態才會通知數據變化。
- 實時數據刷新
當組件處于活躍狀態或者從不活躍狀態到活躍狀態時總是能收到最新的數據
- 解決Configuration Change問題
在屏幕發生旋轉或者被回收再次啟動,立刻就能收到最新的數據。
- 數據共享
如果對應的LiveData是單例的話,就能在app的組件間分享數據。這部分詳細的信息可以參考繼承LiveData
//----------------------創建LiveData public class NameViewModel extends ViewModel {private MutableLiveData<String> currentName;public MutableLiveData<String> getCurrentName() {if (currentName == null) {currentName = new MutableLiveData<String>();}return currentName;} } //---------------------觀察LiveData(UI發生改變的時候通知) public class NameActivity extends AppCompatActivity {private NameViewModel model;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);model = new ViewModelProvider(this).get(NameViewModel.class);final Observer<String> nameObserver = new Observer<String>() {@Overridepublic void onChanged(@Nullable final String newName) {nameTextView.setText(newName);}}; //觀察Livedatamodel.getCurrentName().observe(this, nameObserver);} } //---------------------更新LiveData,(更新UI) button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {String anotherName = "John Doe";model.getCurrentName().setValue(anotherName);} }); //LiveData轉換 Transformations.map() Transformations.switchMap()?6.2數據狀態
???????
class SearchManager implements SavedStateRegistry.SavedStateProvider {private static String PROVIDER = "search_manager";private static String QUERY = "query";private String query = null;public SearchManager(SavedStateRegistryOwner registryOwner) {registryOwner.getLifecycle().addObserver((LifecycleEventObserver) (source, event) -> {if (event == Lifecycle.Event.ON_CREATE) {SavedStateRegistry registry = registryOwner.getSavedStateRegistry();// Register this object for future calls to saveState()registry.registerSavedStateProvider(PROVIDER, this);// Get the previously saved state and restore itBundle state = registry.consumeRestoredStateForKey(PROVIDER);// Apply the previously saved stateif (state != null) {query = state.getString(QUERY);}}});}@NonNull@Overridepublic Bundle saveState() {Bundle bundle = new Bundle();bundle.putString(QUERY, query);return bundle;}... }class SearchFragment extends Fragment {private SearchManager searchManager = new SearchManager(this);... }7.Work
原理:用來執行后臺任務的
優點:
- 版本兼容性強,向后兼容至API 14。
- 可以指定約束條件,比如可以選擇必須在有網絡的條件下執行。
- 可定時執行也可單次執行。
- 監聽和管理任務狀態。
- 多個任務可使用任務鏈。
- 保證任務執行,如當前執行條件不滿足或者App進程被殺死,它會等到下次條件滿足或者App進程打開后執行。
- 支持省電模式。
替換:
WorkManager API 是一個適合用來替換先前的 Android 后臺調度 API(包括?FirebaseJobDispatcher、GcmNetworkManager??和?JobScheduler)的推薦組件。
應用:
- 向后端服務發送日志或分析數據。
- 定期將應用數據與服務器同步。
AS中引用build.gradle
dependencies {def work_version = "2.7.1"// (Java only)implementation "androidx.work:work-runtime:$work_version"// Kotlin + coroutinesimplementation "androidx.work:work-runtime-ktx:$work_version"// optional - RxJava2 supportimplementation "androidx.work:work-rxjava2:$work_version"// optional - GCMNetworkManager supportimplementation "androidx.work:work-gcm:$work_version"// optional - Test helpersandroidTestImplementation "androidx.work:work-testing:$work_version"// optional - Multiprocess supportimplementation "androidx.work:work-multiprocess:$work_version" }WorkManager 可處理三種類型的永久性工作:
- 立即執行:必須立即開始且很快就完成的任務,可以加急。
- 長時間運行:運行時間可能較長(有可能超過 10 分鐘)的任務。
- 可延期執行:延期開始并且可以定期運行的預定任務。
| 立即 | 一次性 | OneTimeWorkRequest?和?Worker 如需處理加急工作-?調用?setExpedited() |
| 長期運行 | 一次性或定期 | 任意?WorkRequest?或?Worker 在工作器中調用?setForeground()?來處理通知 |
| 可延期 | 一次性或定期 | PeriodicWorkRequest?和?Worker |
基礎使用:
1.定義worker ,實現dowork
public class UploadWorker extends Worker {2.利用建造者創建workRequest
WorkRequest uploadWorkRequest =new OneTimeWorkRequest.Builder(UploadWorker.class).build();3.將 WorkRequest 提交給系統
WorkManager.getInstance(myContext).enqueue(uploadWorkRequest);具體用法:
常見的Worker
1.自動運行在后臺線程的Worker
2.結合協程的CoroutineWorker
???????3.結合RxJava2的RxWorker和以上三個類的基類的ListenableWorker
4.RemoteListenableWorker和RemoteCoroutineWorker
從 WorkManager 2.6 開始,借助?RemoteListenableWorker?或者?RemoteCoroutineWorker可以將任務運行在任意指定進程,實現跨進程的監聽
//------------------------work用法(中間進度)public class ProgressWorker extends Worker {private static final String PROGRESS = "PROGRESS";private static final long DELAY = 1000L;public ProgressWorker(@NonNull Context context,@NonNull WorkerParameters parameters) {super(context, parameters);// Set initial progress to 0setProgressAsync(new Data.Builder().putInt(PROGRESS, 0).build());}@NonNull@Overridepublic Result doWork() {try {Thread.sleep(DELAY);} catch (InterruptedException exception) {}// Set progress to 100 after you are done doing your work.setProgressAsync(new Data.Builder().putInt(PROGRESS, 100).build());return Result.success();} }創建workRequest
- //--------------------一次性任務 WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);//-----------------------加急任務 OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>().setInputData(inputData).setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)//加急工作.build(); //-----------------------延遲任務 WorkRequest myWorkRequest =new OneTimeWorkRequest.Builder(MyWork.class).setInitialDelay(10, TimeUnit.MINUTES).build(); -------------------------重試任務 WorkRequest myWorkRequest =new OneTimeWorkRequest.Builder(MyWork.class).setBackoffCriteria(BackoffPolicy.LINEAR,//重試間隔都會增加約 10 秒OneTimeWorkRequest.MIN_BACKOFF_MILLIS,//此值不能超過 10 秒TimeUnit.MILLISECONDS).build();// ------------------------構建約束條件 約束條件(NetworkType BatteryNotLow RequiresCharging DeviceIdle StorageNotLow)val constraints = Constraints.Builder().setRequiresBatteryNotLow(true) // 非電池低電量.setRequiredNetworkType(NetworkType.CONNECTED) // 網絡連接的情況.setRequiresStorageNotLow(true) // 存儲空間足.build()// 儲存照片val save = OneTimeWorkRequestBuilder<SaveImageToFileWorker>().setConstraints(constraints).addTag(TAG_OUTPUT).build()continuation = continuation.then(save) //-------------------------標記---tag WorkRequest myWorkRequest =new OneTimeWorkRequest.Builder(MyWork.class).addTag("cleanup").build();//-----------------------data WorkRequest myUploadWork =new OneTimeWorkRequest.Builder(UploadWork.class).setInputData(new Data.Builder().putString("IMAGE_URI", "http://...").build()).build();//-------協程--getForegroundInfo可讓 WorkManager 在您調用 setExpedited() 時顯示通知。 class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):CoroutineWorker(appContext, workerParams) {override suspend fun getForegroundInfo(): ForegroundInfo {return ForegroundInfo(NOTIFICATION_ID, createNotification())}override suspend fun doWork(): Result {TODO()}private fun createNotification() : Notification {TODO()}}//----------------------定期任務 PeriodicWorkRequest saveRequest =new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS)// Constraints.build(); //-----------------------定時任務,每小時的15分鐘執行的任務 WorkRequest saveRequest =new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class,1, TimeUnit.HOURS,15, TimeUnit.MINUTES).build();
WorkManager使用
//---------------------多任務執行(連接) workManager.beginWith(mutableListOf(OneTimeWorkRequest.from(CleanUpWorker::class.java))).then(OneTimeWorkRequestBuilder<BlurWorker>().setInputData(createInputDataForUri()).build()).then(OneTimeWorkRequestBuilder<SaveImageToFileWorker>().build()).enqueue()// -----------------------多任務按順序執行 workManager.beginUniqueWork(//beginUniqueWorkIMAGE_MANIPULATION_WORK_NAME, // 任務名稱ExistingWorkPolicy.REPLACE, // 任務相同的執行策略 分為REPLACE,KEEP,APPENDmutableListOf(OneTimeWorkRequest.from(CleanUpWorker::class.java) )).then(OneTimeWorkRequestBuilder<BlurWorker>().setInputData(createInputDataForUri()).build()).then(OneTimeWorkRequestBuilder<SaveImageToFileWorker>().build()).enqueue()//-------------------------唯一工作執行 PeriodicWorkRequest sendLogsWorkRequest = newPeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS).setConstraints(new Constraints.Builder().setRequiresCharging(true).build()).build(); WorkManager.getInstance(this).enqueueUniquePeriodicWork(//唯一"sendLogs",ExistingPeriodicWorkPolicy.KEEP,sendLogsWorkRequest); //---------------------合并器,父輸出傳入子輸入 OneTimeWorkRequest cache = new OneTimeWorkRequest.Builder(PlantWorker.class).setInputMerger(ArrayCreatingInputMerger.class).setConstraints(constraints).build();//----------------------------取消任務 // by id workManager.cancelWorkById(syncWorker.id);// by name workManager.cancelUniqueWork("sync");// by tag workManager.cancelAllWorkByTag("syncTag");//--------------------------復雜工作查詢Workquery,從上面tag中查找,檢測狀態workManager.getWorkInfoByIdLiveData(syncWorker.id).observe(getViewLifecycleOwner(), workInfo -> {if (workInfo.getState() != null &&workInfo.getState() == WorkInfo.State.SUCCEEDED) {Snackbar.make(requireView(),R.string.work_completed, Snackbar.LENGTH_SHORT).show();} });WorkQuery workQuery = WorkQuery.Builder.fromTags(Arrays.asList("syncTag")).addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)).addUniqueWorkNames(Arrays.asList("preProcess", "sync")).build();ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);//--------------------------------觀察進度 WorkManager.getInstance(getApplicationContext())// requestId is the WorkRequest id.getWorkInfoByIdLiveData(requestId).observe(lifecycleOwner, new Observer<WorkInfo>() {@Overridepublic void onChanged(@Nullable WorkInfo workInfo) {if (workInfo != null) {Data progress = workInfo.getProgress();int value = progress.getInt(PROGRESS, 0)// Do something with progress}} });調試:
public class MyApplication extends Application implements Configuration.Provider {@NonNull@Overridepublic Configuration getWorkManagerConfiguration() {return new Configuration.Builder().setMinimumLoggingLevel(android.util.Log.DEBUG).build();} }adb shell dumpsys jobscheduler
adb shell am broadcast -a "androidx.work.diagnostics.REQUEST_DIAGNOSTICS" -p "<your_app_package_name>"
?
協程:
- 處理多任務并發的手段,最大的特點就是可以自動幫助我們切換線程???????
- 協程就像輕量級的線程。線程由系統調度,協程由開發者控制。
- kotlin協程本質上是對線程池的封裝
添加依賴:
implementation'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0'
implementation'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0'
??????????????8.Room
8.1示例
------------------------Entity----------------------------- @Entity public class User {@PrimaryKeypublic int uid;@ColumnInfo(name = "first_name")public String firstName;@ColumnInfo(name = "last_name")public String lastName; } ------------------------Dao----------------------------- @Dao public interface UserDao {@Query("SELECT * FROM user")List<User> getAll();@Query("SELECT * FROM user WHERE uid IN (:userIds)")List<User> loadAllByIds(int[] userIds);@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +"last_name LIKE :last LIMIT 1")User findByName(String first, String last);@Insertvoid insertAll(User... users);@Deletevoid delete(User user); } ------------------------Database----------------------------- @Database(entities = {User.class}, version = 1) public abstract class AppDatabase extends RoomDatabase {public abstract UserDao userDao(); }AppDatabase db = Room.databaseBuilder(getApplicationContext(),AppDatabase.class, "database-name").build();UserDao userDao = db.userDao(); List<User> users = userDao.getAll();8.2
??????? javaCompileOptions {annotationProcessorOptions {arguments = ["room.schemaLocation":"$projectDir/schemas".toString()]} }配置如上可以看到json文件
8.3 調試數據庫
adb shell
sqlite3 /data/data/your-app-package/databases/XXX.db
.help 幫助
.exit ?退出
.table 查看表
select * from ?"具體表名"; 注意分隔 查詢所有字段
排序 order by:
select * from ?"具體表名" order by XXX;排序
select * from ?"具體表名" order by XXX desc;逆序
條件查詢 where:
select * from "表名"?where "字段名"='字段值';
select * from "表名" where "字段名" between "" and ?"";
select * from "表名" where "字段名" not between "" and ?"";
select * from "表名" where "字段名" is NULL;空查詢
多條件查詢 or ,and,in, not in:
select * from "表名" where "字段條件語句1" ?and "字段條件語句2" or "字段條件語句3";
select * from "表名" where "字段名" in "字段值1,字段值2" ;
select * from "表名" where "字段名" not ?in "字段值1,字段值2" ;
模糊查詢 like:
select * from "表名" where "字段名" ?like?"字段值";
通配符:_?代表一個未指定字符,%?代表不定個未指定字符
select * from "表名" where "字段名" ?like?" _";以_表示未知字符
select * from "表名"?where "字段名"?like '[ALN]%'以A或L或N開頭的
更新:
update ‘表名’?set value='字段值' where ‘字段名’='字段值';
多表查詢:
select "表別名.字段名" from "表名A" A left join "表名B" B ON A.Key = B.key
select "字段名" from "表名A" A left join "表名B" B ON A.Key = B.key Where B.key is null
select "字段名" from "表名A" A inner?join "表名B" B ON A.Key = B.key
select "字段名" from "表名A" A right join "表名B" B ON A.Key = B.key
select "字段名" from "表名A" A right join "表名B" B ON A.Key = B.key Where A.key is null
???????select "字段名" from "表名A" A full outer join "表名B" B ON A.Key = B.key
???????select "字段名" from "表名A" A full outer join "表名B" B ON A.Key = B.key?Where A.key is null or B.key is null
??????????????
?
參考:即學即用Android Jetpack - WorkManger - 簡書
LiveData 概覽 ?|? Android 開發者 ?|? Android Developers
https://blog.csdn.net/m0_37700275/article/details/104683011
總結
以上是生活随笔為你收集整理的android JeckPack官方文档学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 荷兰红旗问题
- 下一篇: 纸带打点计算机是什么原理,从电火花打点计