Lifecycle
Lifecycle中Activity和Fragment都已经实现了LifecycleOwner接口,在Presenter层中创建传入owner,也可以传入lifecycle
1class MyPresenter(owner:LifecycleOwnter){
2 //在初始化的时候创建Obvserver
3 init{
4 owner.lifecycle.addObserver(MyViewLifeImpl)
5 }
6 //使用一个内部类单独管理生命周期
7 private val viewLifeImpl by lazy {
8 ViewLifeImpl()
9 }
10 inner class MyViewLifeImpl:LifecycleEventObserver{
11 //被动通知View层变化
12 override fun onStateChanged(
13 source: LifecycleOwner, event: Lifecycle.Event) {
14 when(event){
15 Lifecycle.Event.ON_START ->{
16 println("监听开启")
17 }
18 Lifecycle.Event.ON_PAUSE ->{
19 println("监听结束")
20 }
21 else ->{
22
23 }
24 }
25 }
26 }
27 //或者使用主动获取state
28 owner.lifecycle.currentState
29}
30
31
32class MyActivity(){
33 private val myPresenter by lazy{
34 MyPresenter(this)
35 }
36}
37
1currentState中方法isAtLeast可以与生命周期比较,比较原理是比较enum顺序
2也可以使用
3使用注解来监听
4 inner class ViewLifeImpl2: LifecycleObserver {
5 //官方
6 /**
7 * 被动通知View层变化
8 */
9 @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
10 fun removeTT(){
11 println("removeTT")
12 }
13 }
Navigation
简单实用
1<androidx.fragment.app.FragmentContainerView
2 android:name="androidx.navigation.fragment.NavHostFragment"
3 android:id="@+id/fragment_container_view"
4 android:layout_width="match_parent" app:defaultNavHost="true"//让nav处理系统返回键
5 app:navGraph ="@navigation/nav_config"
6 android:layout_height="match_parent"
7/>
1app:defaultNavHost="true"//让nav处理系统返回键
设置nav_config
将FragmentContainerView(一个容器)和nav_config链接起来
navigation下
//startDestination默认启动fragment
每一个都对应一个类和需要一个id
1<navigation xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:app="http://schemas.android.com/apk/res-auto"
3 android:id="@+id/nav_config"
4 app:startDestination="@id/login_fragment">
5 <fragment
6 android:id="@+id/login_fragment"
7 android:name="cn.udday.navigationstudy.fragment.LoginFragment">
8
9 </fragment>
10 <fragment
11 android:id="@+id/register_fragment"
12 android:name="cn.udday.navigationstudy.fragment.RegisterFragment">
13
14 </fragment>
15
16 <fragment
17 android:id="@+id/forget_fragment"
18 android:name="cn.udday.navigationstudy.fragment.ForgetFragment">
19
20 </fragment>
21</navigation>
跳转
在nav_config中设置action就是跳转,id为对外的,destination为对内的跳转目标
1<fragment
2 android:id="@+id/login_fragment"
3 android:name="cn.udday.navigationstudy.fragment.LoginFragment">
4 <action android:id="@+id/to_register_fragment"
5 app:destination="@+id/register_fragment"/>
6 <action android:id="@+id/to_forget_fragment"
7 app:destination="@+id/forget_fragment"/>
8 </fragment>
Activity中,两个按钮指向两个nav_config中的<action 中的id
1override fun onClick(v: View?) {
2 when(v!!.id){
3 R.id.toRegisterPage -> findNavController().navigate(R.id.to_register_fragment)
4 R.id.toForgetPage -> findNavController().navigate(R.id.to_forget_fragment)
5 }
跳转Activity同理(Fragment不能用系统返回键返回)
跳转动画
新建anim包
新建slipe_from_right_to_left_in
slipe_from_right_to_left_out
1<set xmlns:android="http://schemas.android.com/apk/res/android">
2 <translate
3 android:duration = "400"//400毫秒
4 android:fromXDelta="100%p"
5 android:toXDelta="0"/>
6
7</set>
8<set xmlns:android="http://schemas.android.com/apk/res/android">
9 <translate
10 android:duration = "400"
11 android:fromXDelta="0"
12 android:toXDelta="-100%p"/>
13</set>
在nav-config中
1<action android:id="@+id/to_register_fragment"
2 app:destination="@+id/register_fragment"
3 app:exitAnim="@anim/slipe_from_right_to_left_out"
4 app:enterAnim="@anim/slide_from_right_to_left_in"/>
5 //一个进
6 exitAnim和enterAnim是跳转去
7 popEnterAnim和popExitAnims是跳转回来
全局添加Activity切换动画
主题配置下
1<resources xmlns:tools="http://schemas.android.com/tools">
2 <!-- Base application theme. -->
3 <style name="Theme.NavigationStudy" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
4 <!-- Primary brand color. -->
5 <item name="colorPrimary">@color/purple_500</item>
6 <item name="colorPrimaryVariant">@color/purple_700</item>
7 <item name="colorOnPrimary">@color/white</item>
8 <!-- Secondary brand color. -->
9 <item name="colorSecondary">@color/teal_200</item>
10 <item name="colorSecondaryVariant">@color/teal_700</item>
11 <item name="colorOnSecondary">@color/black</item>
12 <!-- Status bar color. -->
13 <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
14 <!-- Customize your theme here. -->
15 <item name="android:windowAnimationStyle">@style/activityAnimation</item>
16 <!-- 这句话将下面的引用至主题 -->
17 </style>
18 <style name="activityAnimation" parent="@android:style/Animation">
19 <item name="android:activityOpenEnterAnimation">@anim/slide_from_right_to_left_in</item>
20 <item name="android:activityOpenExitAnimation">@anim/slide_from_right_to_left_out</item>
21 <item name="android:activityCloseEnterAnimation">@anim/slide_from_left_to_right_in</item>
22 <item name="android:activityCloseExitAnimation">@anim/slide_from_left_to_right_out</item>
23 </style>
24</resources>
跳转与回退
跳转
1Fragment.findNavController()
2View.findNavController()
3Activity.findNavController(viewId:Int)
1NavHostFragment.findNavController(Fragment)
2Navigation.findNavController(Activity,@IdRes int viewId)
3Navigation.findNavController(View)
回退
1NavController.navigateUp()/NavController.popBackStack()
navigateUP()适用于左上角那种返回键
popBackStack()适用系统返回键
元素共享
使用动画启动 Activity:https://developer.android.google.cn/training/transitions/start-activity
fragment动画:https://developer.android.google.cn/guide/fragments/animate?hl=zh_cn
Fragment元素共享
1//两个元素的transitionName一致
2android:transitionName=""
3
4//在发出的Fragment中点击事件
5 R.id.toRegisterPage ->{
6 val extras:FragmentNavigator.Extras =
7 FragmentNavigatorExtras(userAvatarIv to "userAvatarTn")
8 findNavController().navigate(R.id.to_register_fragment,null,null,extras)
9 }
10//在接受的Fragment中
11 override fun onCreate(savedInstanceState: Bundle?) {
12 super.onCreate(savedInstanceState)
13 sharedElementEnterTransition = TransitionInflater.from(requireContext()).inflateTransition(R.transition.shared_image)
14 }
15//新建transition,加上shared_image
1//shared_image
2<?xml version="1.0" encoding="utf-8"?>
3<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
4 <changeImageTransform />//替换成
5 <autoTransition
6 android:duration="400"/>
7</transitionSet>
1//添加多个元素共享的办法
2override fun onClick(v: View?) {
3 when(v!!.id){
4 R.id.toRegisterPage ->{
5 val imagePair :Pair<View,String> = Pair<View,String>(userAvatarIv,"userAvatarTn")
6 val imagePair2 :Pair<View,String> = Pair<View,String>(userAvatarIv,"userAvatarTn")
7 val extras:FragmentNavigator.Extras =
8 FragmentNavigatorExtras(imagePair,imagePair2)
9 findNavController().navigate(R.id.to_register_fragment,null,null,extras)
10 }
Activity元素共享
同样的需要一个android:transitionName=""
1//发起方
2R.id.toAgreementAPage ->{
3 val imagePair = androidx.core.util.Pair<View,String>(userAvatarIv,"userAvatarTn")//特别注意,这里的Pair是Androidx中的
4 val options:ActivityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(
5 requireActivity(),
6 imagePair
7 )
8 val extras = ActivityNavigator.Extras.Builder()
9 .setActivityOptions(options)
10 .build();
11 findNavController().navigate(R.id.to_agreement_activity,null,null,extras)
12}
数据共享
1R.id.toRegisterPage ->{
2 //两个共享元素
3 //头像
4 val imagePair = Pair<View,String>(userAvatarIv,"userAvatarTn")
5 //用户名
6 val userNamePair = Pair<View,String>(userNameInp,"userNameTn")
7 val extras:FragmentNavigator.Extras =
8 FragmentNavigatorExtras(imagePair,userNamePair)
9 //数据
10 val bundle = Bundle()
11 bundle.putString("userName",userNameInp.text.toString())
12 findNavController().navigate(R.id.to_register_fragment,bundle,null,extras)
13}
使用bundle将数据传入navigate的args中
接受方
1val userName:String?= arguments?.getString("userName")
2rootView.RegUserNameInp.setText(userName)
Acitivty
1val userName: String? = intent.getStringExtra("userName")
2agreeUserNameInp.setText(userName)
启动DataBinding
1android {
2 ...
3 buildFeatures {
4 dataBinding true
5 }
6}
1plugins {
2 id 'kotlin-kapt'
3}
在xml文件中对最外层布局按alt+回车可以生成DataBinding
新建一个data class
右键名称,Copy Reference,复制全路径名称
1<data>
2 <variable
3 name="user"
4 type="com.example.databindingstudy.domain.User" />
5</data>
1android:text="@{user.name}"
在Activity中
把下划线改成驼峰命名法
activity_main
ActivityMainBinding
1override fun onCreate(savedInstanceState: Bundle?) {
2 super.onCreate(savedInstanceState)
3
4 val binding:ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)
5 binding.user = User("张三",14,Gender.Man)
6 setContentView(binding.root)
7}
或者用
1val contentView:ActivityMainBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
Fragment中使用
1abstract class BaseViewFragment<T:ViewDataBinding> :Fragment() {
2 protected var binding:T? = null
3 override fun onCreateView(
4 inflater: LayoutInflater,
5 container: ViewGroup?,
6 savedInstanceState: Bundle?
7 ): View? {
8 val rootView = inflater.inflate(getSubLayoutId(), container, false)
9 binding = DataBindingUtil.bind<T>(rootView)
10 //binding = DataBindingUtil.inflate<T>(inflater, getSubLayoutId(), container, false)第二种方法
11
12 return rootView
13 //return binding!!.root
14 }
15 abstract fun getSubLayoutId():Int
16}
带ViewModel
1abstract class BaseVmFragment<T:ViewDataBinding,VM:ViewModel>:BaseViewFragment<T>() {
2 protected lateinit var viewModel: ViewModel
3
4 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
5 super.onViewCreated(view, savedInstanceState)
6 //创建ViewModel
7 initViewModel()
8 //观察数据变化 -->更新UI
9 observerData()
10 //设置相关事件
11 initEvent()
12 //开始去加载数据
13 startLoadData()
14 }
15 open fun startLoadData() {
16
17 }
18 open fun initEvent() {
19
20 }
21
22 open fun observerData() {
23
24 }
25
26 private fun initViewModel() {
27 viewModel = ViewModelProvider(this,ViewModelProvider.NewInstanceFactory()).get(getSubVMClass())
28 }
29
30
31 abstract fun getSubVMClass(): Class<VM>
32}
搭好MVVM
1class OnSellViewModel:ViewModel() {
2}
1class OnSellRepository {
2}
1class OnSellFragment:BaseVmFragment<FragmentOnSellBinding,OnSellViewModel>() {
2 override fun getSubVMClass(): Class<OnSellViewModel> {
3 return OnSellViewModel::class.java
4 }
5
6 override fun getSubLayoutId(): Int {
7 return R.layout.fragment_on_sell
8 }
9}
在ViewModel里面建立关心的数据
1class OnSellViewModel:ViewModel() {
2 //所关心的数据
3
4 //加载状态:Loading,Success,Empty,Error,None
5 val loadState by lazy {
6 MutableLiveData<LoadState>()
7 }
8
9 //数据列表 contentList
10 val contentList by lazy {
11 MutableLiveData<MutableList<OnSellItem>>()
12 }
13}
在Ui即Fragment中创建观察
1override fun observerData() {
2 //观察ViewModel里的数据变化
3 viewModel.loadState.observe(this, Observer { newState ->
4 println("newState --> $newState")
5 //更新UI
6 //TODO
7 })
8
9 viewModel.contentList.observe(this, Observer { contentList ->
10 "contentList.size --> ${contentList.size}"
11 //当内容列表发生变化的时候,就会通知到这里了
12 //TODO
13 })
14 }
新建RetrofitClient
1object RetrofitClient {
2 private const val BASE_URL = "https://v2.alapi.cn/api/eventHistory/"
3 private val okHttpClient = OkHttpClient.Builder()
4 .callTimeout(30,TimeUnit.SECONDS)
5 .build()
6 //创建retrofit
7 private val retrofit = Retrofit.Builder()
8 .baseUrl(BASE_URL)
9 .addConverterFactory(GsonConverterFactory.create())
10 .client(okHttpClient)
11 .build()
12 val apiService = retrofit.create(ApiService::class.java)
13}
在Repository中新建加载的方法
1class OnSellRepository {
2 suspend fun getOnSellDataS(year:Int):OnSellItem = RetrofitClient.apiService.getOnSellList(year)
3}
在ViewModel中持有Repository的实例,同时在loadData中加载数据
1class OnSellViewModel:ViewModel() {
2 private val repository by lazy {
3 OnSellRepository()
4 }
5 private var year = 2021;
6 fun loadData() {
7 //这个加载需要UI层转圈圈(Loading)
8 //更新状态
9 loadState.value = LoadState.LOADING
10 //加载数据
11 loadDataS(year)
12 }
13
14 private fun loadDataS(year:Int) {
15 //根据年份加载数据
16 viewModelScope.launch {
17 val onSellDataS = repository.getOnSellDataS(year)
18 println("result code --> ${onSellDataS.code}")
19 println("result msg--> ${onSellDataS.msg}")
20 println("result data--> ${onSellDataS.data.get(0).date}")
21
22 }
23 }
24 //所关心的数据
25
26 //加载状态:Loading,Success,Empty,Error,None
27 val loadState by lazy {
28 MutableLiveData<LoadState>()
29 }
30
31 //数据列表 contentList
32 val contentList by lazy {
33 MutableLiveData<MutableList<OnSellItem>>()
34 }
35}
与RecycleView配合
1private fun loadDataS(year:Int) {
2 //根据年份加载数据
3 viewModelScope.launch {
4// val onSellDataS = repository.getOnSellDataSearch(year)
5 val onSellDataS = repository.getOnSellDataS()
6 println(onSellDataS.msg)
7 println(onSellDataS.code)
8 //对数据进行判断,数据有空能为空,有可能网络请求出错
9 if (onSellDataS.code == 200){
10 contentList.value = onSellDataS.data
11 //在处理之后返回Success
12 loadState.value = LoadState.SUCCESS
13 }else{
14 loadState.value = LoadState.EMPTY
15 Log.e(TAG,"${onSellDataS.code} : ${onSellDataS.msg}")
16 }
17 //处理一下数据
18 }
19 }
新建Adapter
1class OnSellListAdapter: RecyclerView.Adapter<OnSellListAdapter.InnerHolder>() {
2
3 private val mMutableList by lazy {
4 mutableListOf<Data>()
5 }
6 class InnerHolder(itemView: View,val binding: ItemOnSellBinding):RecyclerView.ViewHolder(itemView) {
7
8 }
9
10 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InnerHolder {
11 //这里的不可以设置成员变量,这里是频繁创建的
12 //DataBinding日常操作
13 val itemBinding = DataBindingUtil.inflate<ItemOnSellBinding>(
14 LayoutInflater.from(parent.context),
15 R.layout.item_on_sell, parent, false
16 )
17 return InnerHolder(itemBinding.root,itemBinding)
18 }
19
20 override fun getItemCount(): Int {
21 return mMutableList.size;
22 }
23
24 override fun onBindViewHolder(holder: InnerHolder, position: Int) {
25
26 //在这里设置数据
27 //拿到对应位置的数据
28 val itemData:Data = mMutableList[position]
29 //需要binding设置数据
30 holder.binding.itemOnSellData = itemData
31 /*
32 在xml中设置了data,然后获取OnSellData,然后绑定domain,然后设置相应的控件,在获取到数据之后与数据进行绑定
33 */
34 }
35
36 fun setData(contentList: MutableList<Data>) {
37 //清空
38 mMutableList.clear()
39 //添加为成员变量
40 mMutableList.addAll(contentList)
41 //全部更新
42 notifyDataSetChanged()
43 //如果是添加到头部或者尾部,可以局部更新
44 }
45
46}
更改BaseFragmentView中的信息
1abstract class BaseViewFragment<T:ViewDataBinding> :Fragment() {
2
3 protected lateinit var binding:T
4 //做成成员变量,直接获取
5 protected lateinit var rootView:View
6 override fun onCreateView(
7 inflater: LayoutInflater,
8 container: ViewGroup?,
9 savedInstanceState: Bundle?
10 ): View? {
11 binding = DataBindingUtil.inflate<T>(inflater, getSubLayoutId(), container, false)
12 rootView = binding.root
13 return rootView
14 }
15 abstract fun getSubLayoutId():Int
16}
1override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
2 super.onViewCreated(view, savedInstanceState)
3 //创建ViewModel
4 initViewModel()
5 //观察数据变化 -->更新UI
6 observerData()
7 //初始化相关的控件
8 initView()
9 //设置相关事件
10 initEvent()
11 //开始去加载数据
12 startLoadData()
13 }
设置RecycleView
1private val mAdapter by lazy {
2 OnSellListAdapter()
3}
4override fun initView() {
5 rootView.onSellListView.run {
6 //布局管理器
7 layoutManager = LinearLayoutManager(context)
8 //适配器
9 adapter = mAdapter
10 //
11 }
12}
在observerData中设置
1viewModel.contentList.observe(this, Observer { contentList ->
2 "contentList.size --> ${contentList.size}"
3 //当内容列表发生变化的时候,就会通知到这里了
4 //更新列表
5 mAdapter.setData(contentList)
6})
设置更新列表
1fun setData(contentList: MutableList<Data>) {
2 //清空
3 mMutableList.clear()
4 //添加为成员变量
5 mMutableList.addAll(contentList)
6 //全部更新
7 notifyDataSetChanged()
8 //如果是添加到头部或者尾部,可以局部更新
9}
控件样例
1<TextView
2 android:id="@+id/ItemOnSellTitle"
3 android:gravity="center"
4 android:textColor="@color/black"
5 android:text="@{itemOnSellData.title}"
6 android:layout_width="match_parent"
7 android:layout_height="wrap_content" />