走進Jetpack組件庫
- 什么是Jetpack
- Jetpack的優(yōu)勢
- 為什么要使用Jetpack
- Jetpack眾多優(yōu)秀組件介紹
- 使用Jetpack架構開發(fā)
什么是Jetpack組件
- 概括:Jetpack是眾多優(yōu)秀組件的集合嫁怀,是Google推出一套引領Android開發(fā)的逐一統(tǒng)一開發(fā)規(guī)范的架構
Jetpack的優(yōu)勢
- 基于生命周期的感知叛复,可以減少NPE崩潰铣耘、內存泄漏温算、模板代碼岗钩。為我們開發(fā)出健壯且高質量的程序提供強力保障
- 組件可以單獨使用申眼,也可以搭配使用谬晕,搭配Kotlin語言特性可以進一步加速開發(fā)
為什么要使用Jetpack
-
- Android Jetpack 組件采用最新的設計方法構建宿亡,具有向后兼容性碑诉,可以減少崩潰和內存泄露彪腔。
-
- Android Jetpack 可以管理各種繁瑣的 Activity(如后臺任務、導航和生命周期管理)进栽,以便您可以專注于打造出色的應用德挣。
-
- 這些庫可在各種 Android 版本和設備中以一致的方式運作,助您降低復雜性泪幌。
Jetpack眾多組件介紹
使用Jetpack組件需要將項目升級到AndoridX
Jetpack 包含一系列 Android 庫盲厌,它們都采用最佳做法并在 Android 應用中提供向后兼容性
jetpack組件
Navigation : 為單個Activity架構而生的端內路由
- 特性:Activity,F(xiàn)ragment祸泪,Dialog提供路由能力的組件吗浩、導航時可攜帶參數(shù)、指定轉場動畫没隘、支持deepLink頁面直達懂扼、fragment回退棧管理能力
- 不足之處:十分依賴xml文件,不利于模塊化右蒲,組件化開發(fā)
- 添加依賴
def nav_version = "2.3.2"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
- 路由調轉阀湿,可攜帶參數(shù),指定轉場動畫
NavController navController = navHostFragment.getNavController();
navController.navigate(int resId, Bundle args, NavOptions navOptions)
- deppLink實現(xiàn)頁面直達能力
navController.handleDeepLink("/**/**")
- 管理Fragment回退棧
navController.popBackStack(int destinationId, boolean inclusive)
Lifecycles
構建生命周期感知型組件瑰妄,這些組件可以根據(jù) Activity 或 Fragment 的當前生命周期狀態(tài)調整行為陷嘴。
// 添加依賴
api 'androidx.appcompat:appcompat:1.1.0'
api 'androidx.lifecycler:lifecycle-common:2.1.0'
// 用法
class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectListener() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun disconnectListener() {
...
}
}
// 宿主需要實現(xiàn)LifecycleOwner接口
class MyFragment : xxx, LifecycleOwner {
var mLifecycleRegistry = LifecycleRegistry(this)
// 提供宿主Lifecycle對象
override fun getLifecycle():Lifecycle {
return mLifecycleRegistry
}
}
getLifecycle().addObserver(MyObserver())//注冊觀察者,觀察宿主生命周期狀態(tài)變化
ViewModel 具備生命周期感知的數(shù)據(jù)存儲組件
具有生命周期感知、頁面配置更改數(shù)據(jù)不會丟失间坐、數(shù)據(jù)共享
// 添加依賴
api 'androidx.appcompat:appcompat:1.1.0'
api 'androidx.lifecycler:lifecycle-viewmodel:2.0.0'
api 'androidx.lifecycle:lifecycle-livedata:2.0.0'
// 使用方式
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
// 創(chuàng)建ViewModel
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 創(chuàng)建ViewModel
val model: MyViewModel by viewModels()
// 獲取數(shù)據(jù) 灾挨, 更新UI
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI
})
}
}
LiveData 數(shù)據(jù)共享
配合ViewModel使用
特性:支持共享資源、支持粘性事件分發(fā)竹宋、生命周期感知劳澄、確保符合頁面需要的數(shù)據(jù)
不足:粘性時間不能自動取消
MutableLiveData<T> liveData = new MutableLiveData();
//注冊一個跟宿主生命周期綁定的觀察者,宿主銷毀了蜈七,會自動解除注冊
observe(LifecycleOwner owner,Observer<? super T> observer)
//觀察不到宿主生命周期秒拔,不會自動解除注冊
observeForever(Observer<? super T> observer)
//以下倆方法都是分發(fā)數(shù)據(jù)給所有的觀察者
//只能用在主線程
setValue(T value)
//子線程,主線程都可以使用
postValue(T value)
Room 輕量級orm數(shù)據(jù)庫飒硅,本質上是一個SQLite抽象層
特性:使用更加簡單(類似于Retrofit)砂缩,通過注解的方式實現(xiàn)相關功能作谚。編譯時自動生成實現(xiàn)類impl
api "android.arch.persistence.room:runtime:1.1.1"
kapt "android.arch.persistence.room:compiler:1.1.1"
//1. 創(chuàng)建一個操作數(shù)據(jù)庫數(shù)據(jù)的實體層
// 增刪改查
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@update("update table user set desc=:desc and where user_id = :userId")
User updateUser(String desc,String userId);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
}
//2. 創(chuàng)建數(shù)據(jù)庫
@Database(entities = {User.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {
public static MyDatabase mAppDb;
static{
mAppDb = Room.databaseBuilder(getApplicationContext(),
AppDatabase.class, "database-name").build();
}
public abstract UserDao userDao();
}
//3. 通過數(shù)據(jù)庫單例對象,獲取userDao數(shù)據(jù)操作對象.訪問數(shù)據(jù)庫
mAppDb.userDao().getAll();
DataBinding 是一種工具,數(shù)據(jù)與View的雙向綁定
特性:減少findViewById模版代碼梯轻、空安全判斷食磕、數(shù)據(jù)與視圖雙向綁定尽棕、釋放Fragment/Activity
// 開啟DataBinding
build.gradle中
android {
}
<!--xml中databinding的使用-->
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<data>
<variable
name="user"
type="xxx.User" />
<import type="xxx.UserManager"></import>
</data>
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tvName"
android:layout_width="200dp" //不能使用dataBinding動態(tài)綁定
android:text="@{user.name}" //單向綁定數(shù)據(jù)變更自動通知UI
android:textSize="@{@dimen/16sp}"http://資源引用
android:text="@{user.name+@string/suffix}" //字符串的拼接需要引用資源
android:text="@{UserManager.getUserName()}" //調用靜態(tài)方法,類必須先導入
android:onClick="@{()-> UserManager.login()}"
/>
<EditText
//雙向綁定數(shù)據(jù)變更自動更新UI喳挑,UI變更了也能自動更新user中name的數(shù)據(jù),比單向綁定多個=
android:text="@={user.name}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
<layout_user_info_item>
LayoutUserInfoItemBinding binding = DataBindingUtils.inflate(....)
Paging 列表分頁組件滔悉∫了校可以輕松完成分頁預加載達到無限滑動分頁效果
實現(xiàn)基于liveData頁面分頁加載功能
不足之處:不支持列表數(shù)據(jù)增刪改,列表添加HeaderView 和FooterView定位不準確
// 添加依賴
api 'android.arch.paging:runtime:1.0.0'
// 使用方式
//1.構建PagedList.Config對象,用以聲明以何種方式分頁
PagedList.Config config = new PagedList.Config.Builder()
.setPageSize(10)//指定每次分頁加載的條目數(shù)量
.setInitialLoadSizeHint(12)//指定初始化數(shù)據(jù)加載的條目數(shù)量
.build();
//2.創(chuàng)建數(shù)據(jù)源工廠類,用來創(chuàng)建數(shù)據(jù)提供者
DataSource.Factory factory = new DataSource.Factory() {
@NonNull
@Override
public DataSource create() {
return new ItemKeyedDataSource();
}
};
//3.構建一個能夠觸發(fā)加載頁面初始化數(shù)據(jù)的LiveData對象,并且把上面創(chuàng)建的DataSource.Factory和PagedList.Config 傳遞進去
LiveData<PagedList<T>> pageData = new LivePagedListBuilder(factory, config)
.build();//最后通過build方法 構建出LiveData對象回官。請注意它的 泛型是<PagedList<T>>
//4.最后我們只需要拿到前面構建出來的LiveData對象注冊一個Observer觀察者,僅僅如此就可以觸發(fā)頁面初始化數(shù)據(jù)的加載了
mViewModel.getPageData().observe(this, pagedList -> submitList(pagedList));
class MyItemKeyedDataSource extends ItemKeyedDataSource<GoodsModel>{
public abstract void loadInitial(LoadInitialParams<Key> params,LoadInitialCallback<Value> callback){
//頁面初始化數(shù)據(jù)加載
callback.onResult(list)
}
public void loadAfter(@NonNull LoadParams<Key> params,LoadCallback<Value> callback){
//向后分頁數(shù)據(jù)加載...
callback.onResult(list)
}
public void loadBefore(LoadParams<Key> params,LoadCallback<Value> callback){
//向前分頁數(shù)據(jù)加載...
callback.onResult(list)
}
}
WorkManager : 新一代后臺任務管理組件曹宴,功能比較強大,service能做的事情它都能做
支持周期性任務調度歉提、鏈式任務調度笛坦、豐富的任務約束條件、即便程序退出苔巨,依舊能保證任務的執(zhí)行
api "android.arch.work:work-runtime:1.0.1"
//#1.構建任務
class UploadFileWorker extends Worker{
public Result doWork() {
//執(zhí)行文件上傳的任務
return Result.success()
}
}
//#2.構建 執(zhí)行任務的request對象
OneTimeWorkRequest request = new OneTimeWorkRequest
.Builder(UploadFileWorker.class)
.build()
//#3.把任務加入調度隊列
WorkContinuation workContinuation = WorkManager.getInstance(context).beginWith(request);
workContinuation.then(workB).then(workC).enqueue()