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.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.1 带参数创建fragment
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.add(R.id.fragment_container_view, ExampleFragment.class, bundle)
.commit();
--对应
@Override
public 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
@Override
public 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动画
setCustomAnimations
3.6Fragment状态
3.7Fragment通信
类型
Activity之间的通信
Fragment之间的通信
与子Fragment之间的通信
方法:
使用ViewModel共享数据
使用接口共享数据
Fragment自己的toolbar
onCreate-- setHasOptionsMenu(true);
onCreateOptionsMenu -- inflater.inflate(R.menu.sample_menu, menu);
onOptionsItemSelected--点击事件
onPrepareOptionsMenu--修改菜单
requireActivity().invalidateOptionsMenu()---更新菜单
xml中使用
java中
onViewCreated--viewBinding.myToolbar.inflateMenu
viewBinding.myToolbar.setOnMenuItemClickListener--点击事件
viewBinding.myToolbar.setNavigationIcon(R.drawable.ic_back)--返回
viewBinding.myToolbar.setNavigationOnClickListener
3.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.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) {
...
}
@Override
public void onStart(LifecycleOwner owner) {//LifecycleOwner
if (enabled) {
// connect
}
}
public void enable() {
enabled = true;
if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
// connect if not connected
}
}
@Override
public 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;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//初始化lifecycleRegistry
lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.markState(Lifecycle.State.CREATED);
}
@Override
public void onStart() {
super.onStart();
lifecycleRegistry.markState(Lifecycle.State.STARTED);
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}
}
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 {
@Override
protected 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();
@Override
protected void addOnPropertyChangedCallback(
Observable.OnPropertyChangedCallback callback) {
callbacks.add(callback);
}
@Override
protected 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
----------------------双向数据绑定@=
-----------------实体类
@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.1优势
因为LiveData采用的是观察者模式,这样一来就可以在数据发生改变时获得通知,更新UI。
观察者被绑定到组件的生命周期上,当被绑定的组件销毁(onDestroy)时,观察者会立刻自动清理自身的数据。
例如:当Activity处于后台状态时,是不会收到LiveData的任何事件的。
LiveData可以感知被绑定的组件的生命周期,只有在活跃状态才会通知数据变化。
当组件处于活跃状态或者从不活跃状态到活跃状态时总是能收到最新的数据
在屏幕发生旋转或者被回收再次启动,立刻就能收到最新的数据。
如果对应的LiveData是单例的话,就能在app的组件间分享数据。这部分详细的信息可以参考继承LiveData
//----------------------创建LiveData
public class NameViewModel extends ViewModel {
private MutableLiveData currentName;
public MutableLiveData getCurrentName() {
if (currentName == null) {
currentName = new MutableLiveData();
}
return currentName;
}
}
//---------------------观察LiveData(UI发生改变的时候通知)
public class NameActivity extends AppCompatActivity {
private NameViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = new ViewModelProvider(this).get(NameViewModel.class);
final Observer nameObserver = new Observer() {
@Override
public void onChanged(@Nullable final String newName) {
nameTextView.setText(newName);
}
};
//观察Livedata
model.getCurrentName().observe(this, nameObserver);
}
}
//---------------------更新LiveData,(更新UI)
button.setOnClickListener(new OnClickListener() {
@Override
public 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 it
Bundle state = registry.consumeRestoredStateForKey(PROVIDER);
// Apply the previously saved state
if (state != null) {
query = state.getString(QUERY);
}
}
});
}
@NonNull
@Override
public Bundle saveState() {
Bundle bundle = new Bundle();
bundle.putString(QUERY, query);
return bundle;
}
...
}
class SearchFragment extends Fragment {
private SearchManager searchManager = new SearchManager(this);
...
}
原理:用来执行后台任务的
优点:
替换:
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 + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"
// optional - RxJava2 support
implementation "androidx.work:work-rxjava2:$work_version"
// optional - GCMNetworkManager support
implementation "androidx.work:work-gcm:$work_version"
// optional - Test helpers
androidTestImplementation "androidx.work:work-testing:$work_version"
// optional - Multiprocess support
implementation "androidx.work:work-multiprocess:$work_version"
}
WorkManager 可处理三种类型的永久性工作:
类型 | 周期 | 使用方式 |
---|---|---|
立即 | 一次性 | OneTimeWorkRequest 和 Worker 如需处理加急工作- 调用 |
长期运行 | 一次性或定期 | 任意 在工作器中调用 |
可延期 | 一次性或定期 | 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 0
setProgressAsync(new Data.Builder().putInt(PROGRESS, 0).build());
}
@NonNull
@Override
public 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()
.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()
.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().setInputData(createInputDataForUri()).build())
.then(OneTimeWorkRequestBuilder().build())
.enqueue()
// -----------------------多任务按顺序执行
workManager.beginUniqueWork(//beginUniqueWork
IMAGE_MANIPULATION_WORK_NAME, // 任务名称
ExistingWorkPolicy.REPLACE, // 任务相同的执行策略 分为REPLACE,KEEP,APPEND
mutableListOf(
OneTimeWorkRequest.from(CleanUpWorker::class.java)
))
.then(OneTimeWorkRequestBuilder().setInputData(createInputDataForUri()).build())
.then(OneTimeWorkRequestBuilder().build())
.enqueue()
//-------------------------唯一工作执行
PeriodicWorkRequest sendLogsWorkRequest = new
PeriodicWorkRequest.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> workInfos = workManager.getWorkInfos(workQuery);
//--------------------------------观察进度
WorkManager.getInstance(getApplicationContext())
// requestId is the WorkRequest id
.getWorkInfoByIdLiveData(requestId)
.observe(lifecycleOwner, new Observer() {
@Override
public 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 @Override public 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 "
"
协程:
GlobalScope.launch {
withContext(Dispatchers.Main){
//切换线程
}
}
//主线程协程
GlobalScope.launch(Dispatchers.Main) {}
lifecycleScope.launch {}
viewModelScope.launch {}
//默认情况下协程是串行的
//并行方式
lifecycleScope.launch {
lifecycleScope.async { getDataA() }
lifecycleScope.async { getDataB() }
}
//协程停止
?.cancel()
lifecycleScope和viewModelScope会绑定调用者的生命周期,因此通常情况下不需要手动去停止
添加依赖:
implementation'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0'
implementation'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0'
8.1示例
------------------------Entity-----------------------------
@Entity
public class User {
@PrimaryKey
public 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 getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List 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);
@Insert
void insertAll(User... users);
@Delete
void 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 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