Jetpack初尝试 NavController,LiveData,DataBing,ViewModel,Paging

文章目录

        • 插件配置
        • NavController 使用
          • 1. 创建xml
          • 2. 创建Activity
          • 3. res 创建navigation/nav_garden和说明
          • 流程
        • ViewModel 负责页面的数据
        • LiveData onChanged
        • Observable addOnPropertyChangedCallback
        • 创建viewmodle
        • 创建viewmodle 可以用SavedStateHandle存储和读取数据
        • DataBinding
        • API接口使用
          • 定义 接口
          • viewmodel中使用
        • Paging使用
          • 自定义PageKeyedDataSource
          • 自定义 DataSource.Factory
          • viewmodle中使用
        • 自定义属性
          • 自定义方法
          • xml中使用

插件配置

  • classpath “androidx.navigation:navigation-safe-args-gradle-plugin:2.2.0”
  • apply plugin: ‘androidx.navigation.safeargs.kotlin’
  • dataBinding { enabled = true}
  • implementation ‘android.arch.paging:rxjava2:1.0.1’
  • implementation ‘android.arch.paging:runtime:1.0.1’

NavController 使用

1. 创建xml
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <fragment
            android:id="@+id/nav_host"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_garden"/>

    FrameLayout>

layout>

2. 创建Activity
class MainActivity2 : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView<ActivityMain2Binding>(this, R.layout.activity_main2)
    }

}
3. res 创建navigation/nav_garden和说明
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 app:startDestination="@id/view_pager_fragment">

 <fragment
     android:id="@+id/view_pager_fragment"
     android:name="com.gctech.androidstudydemo.jetpack.HomeViewPagerFragment"
     tools:layout="@layout/fragment_view_pager">

     <action
         android:id="@+id/action_view_pager_fragment_to_plant_detail_fragment"
         app:destination="@id/plant_detail_fragment"
         app:enterAnim="@anim/slide_in_right"
         app:exitAnim="@anim/slide_out_left"
         app:popEnterAnim="@anim/slide_in_left"
         app:popExitAnim="@anim/slide_out_right" />

 fragment>

 <fragment
     android:id="@+id/plant_detail_fragment"
     android:name="com.gctech.androidstudydemo.jetpack.EmptyFragment"
     android:label="详情标题">
     <argument
         android:name="id"
         app:argType="string" />
 fragment>

navigation>

startDestination
destination
action
通过id指向目标
传参数 argument name
获取参数 如果传入的有参数就会生成对应的Args 然后获取到
private val args: EmptyFragmentArgs by navArgs()

流程

nav_garden->startDestination->id->name
action->destination->id->name

ViewModel 负责页面的数据

包含 LiveData和ObservableField 和其他数据

LiveData onChanged

观察者模式->订阅数据的变化

Observable addOnPropertyChangedCallback

数据和view双向绑定

创建viewmodle

ViewModelProvider.Factory

创建viewmodle 可以用SavedStateHandle存储和读取数据

AbstractSavedStateViewModelFactory(@NonNull SavedStateRegistryOwner owner, @Nullable Bundle defaultArgs)

DataBinding

页面用viewmodel item用实体类

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="hasPlantings"
            type="boolean" />

        <import type="android.view.View"/>

        <variable
            name="vm"
            type="com.gctech.androidstudydemo.jetpack.viewmodels.EmptyDataViewModel" />
    data>

    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{vm.datas.title}"
            android:visibility="@{vm.datas.isGone() ? View.VISIBLE : View.INVISIBLE}" />

    FrameLayout>

layout>

 class EmptyFragment : Fragment() {
    private val args: EmptyFragmentArgs by navArgs()

    private lateinit var binding: FragmentEmptyBinding

    private val viewModel: EmptyDataViewModel by viewModels {
        InjectorUtils.provideCommonViewModelFactory("")
    }


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentEmptyBinding.inflate(inflater, container, false)

        binding.tvContent.setOnClickListener {
            ToastUtils.showShort("========")
            viewModel.datas.get()?.title ="6666"
            viewModel.datas.notifyChange()
        }


        viewModel.datas.set(A("1", true, "434"))
        binding.vm = viewModel
        binding.lifecycleOwner = viewLifecycleOwner
        binding.hasPlantings = true
        return binding.root
    }

}

API接口使用

定义 接口
interface ApiService {

    /**
     * 1.测试第一个接口
     */
    @GET("xxx/testOne")
    suspend fun testOne(): HttpResult<List<Country>>

    /**
     * 1.测试第二 个接口
     */
    @GET("xxx/testTwo")
    suspend fun testTwo(@Query("list") countries: Int): HttpResult<List<Country>>

    /**
     * 1.测试分页接口
     */
    @GET("xxx/testPage")
    fun testPage(@Query("page") page: Int, @Query("pageSize") pageSize: Int= 20): Call<HttpResult<Tx>>
}
viewmodel中使用
class EmptyDataViewModel(
    private val params: Any?
) : ViewModel() {
    val datas = ObservableField<A>()
    val firstName = ObservableField<String>()
    val lastName = ObservableField<String>()
    val isShowDialog = MutableLiveData<Boolean>()
    val allName = object : ObservableField<String>(firstName, lastName) {
        override fun get(): String? {
            return "${firstName.get()} ${lastName.get()}"
        }
    }

    //调用一个接口
    fun country() = liveData(Dispatchers.IO) {
        isShowDialog.postValue(true)
        try {
            emit(
                Api.createService(ApiService::class.java)
                    .testOne()
            )
            isShowDialog.postValue(false)
        } catch (e: Exception) {
            isShowDialog.postValue(false)
        }
    }

    //顺序调用接口
    fun country2() = liveData(Dispatchers.IO) {
        isShowDialog.postValue(true)
        val d = Api.createService(ApiService::class.java)
            .testOne()
        val d2 = Api.createService(ApiService::class.java)
            .testTwo(d.data!!.size)
        try {
            emit(d2)
            isShowDialog.postValue(false)
        } catch (e: Exception) {
            isShowDialog.postValue(false)
        }
    }

    //合并多个接口
    fun country3() = liveData(Dispatchers.IO) {
        isShowDialog.postValue(true)
        val d = Api.createService(ApiService::class.java)
            .testOne()
        val d2 = Api.createService(ApiService::class.java)
            .testTwo(3)

        try {
            emit(Triple(d, d2, null))
            isShowDialog.postValue(false)
        } catch (e: Exception) {
            isShowDialog.postValue(false)
        }
    }

    val title = MutableLiveData<String>()

    fun addData() {
        viewModelScope.launch {
            //调用接口
        }

        datas.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
            override fun onPropertyChanged(sender: Observable?, propertyId: Int) {

            }
        })

    }
}


 // fragment中使用
	    binding.tvContent.setOnClickListener {
            ToastUtils.showShort("========")
            viewModel.country3().observe(viewLifecycleOwner) {
                viewModel.datas.get()?.title = "${it.first.data?.size}"
                viewModel.datas.notifyChange()
            }
        }
        viewModel.isShowDialog.observe(viewLifecycleOwner) {
            if (it) {
                LoadDialogUtil.showWaitDialog(activity as Context)
            } else {
                LoadDialogUtil.dismissWaitDialog()
            }
        }

Paging使用

自定义PageKeyedDataSource
class CustomPageDataSource() :
    PageKeyedDataSource<Int, A>() {
    override fun loadInitial(
        params: LoadInitialParams<Int>,
        callback: LoadInitialCallback<Int, A>
    ) {
        loge("loadInitial size : ${params.requestedLoadSize} ")
        fetchData(LoadParams(1, 10)) {
            callback.onResult(it.tx, null, 2)
        }


    }

    override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, A>) {
        loge("loadAfter size : ${params.requestedLoadSize}  page:${params.key}")
        fetchData(params) {
            if (params.key == 3) {
                callback.onResult(mutableListOf(), params.key + 1)
            } else {

                callback.onResult(it.tx, params.key + 1)
            }
        }

    }

    override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, A>) {
        loge("loadBefore size : ${params.requestedLoadSize}  page:${params.key}")
        fetchData(params) {
            callback.onResult(it.tx, params.key - 1)
        }
    }


    private fun fetchData(params: LoadParams<Int>, pagingCallback: (Tx) -> Unit) {

        Api.createService(ApiService::class.java)
            .testPage(params.key, params.requestedLoadSize)
            .enqueue(object : Callback<HttpResult<Tx>> {
                override fun onFailure(call: Call<HttpResult<Tx>>, t: Throwable) {
                    t.printStackTrace()
                }

                override fun onResponse(
                    call: Call<HttpResult<Tx>>,
                    response: Response<HttpResult<Tx>>
                ) {
                    val data = response.body()
                    data?.let {
                        pagingCallback(it.data!!)
                    }
                }

            })
    }

}

自定义 DataSource.Factory
class CustomPageDataSourceFactory() : DataSource.Factory<Int, A>() {
    override fun create(): DataSource<Int, A> {
        return CustomPageDataSource()
    }
}
viewmodle中使用
class CommonListDataViewModel(
    private val params: Any?,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    val moreLoading = MutableLiveData<Boolean>()//上拉加载更多状态
    val liveDataMerger = MediatorLiveData<Any>()

    val data2 = LivePagedListBuilder(
        CustomPageDataSourceFactory(), PagedList.Config.Builder()
            .setPageSize(10)
            .setEnablePlaceholders(true)
            .setInitialLoadSizeHint(10)
            .build()
    ).build()


    val datas = MutableLiveData(MutableList(10) {
        A("@it", false, "标题$it")
    })

    fun refresh() {
        data2.value?.let {
            (it.dataSource as PageKeyedDataSource).invalidate()
        }

    }

    fun addData() {
//        liveDataMerger.addSource(refreshing, Observer {
//            liveDataMerger.value = it
//        })
//        liveDataMerger.addSource(moreLoading, Observer {
//            liveDataMerger.value = it
//        })
        viewModelScope.launch {
            //调用接口
        }
    }
}

// fragment中使用 
  private fun subscribeUi(adapter: CustomAdapter, binding: FragmentListLoadmoreBinding) {
        //观察多个liveData
        viewModel.data2.observe(viewLifecycleOwner) {
            adapter.submitList(it)
            Handler().postDelayed({
                binding.isLoading = false
            }, 2000)
        }
        binding.btnClick.setOnClickListener {
            viewModel.refresh()
        }

    }


自定义属性

自定义方法
    @BindingAdapter("visibleGone")
    fun showHide(view: View, show: Boolean) {
        view.visibility = if (show) View.VISIBLE else View.GONE
    }
   
xml中使用
<TextView
            android:id="@+id/tv_loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            android:text="isLoading..."
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:visibleGone="@{isLoading}" />

你可能感兴趣的:(android,jetpack)