概述
前言:
最近在学习mvvm,利用空闲时间写了一个简单版的wanAndroid项目.介绍就不说了,直接上代码.
1.引入:在App——build.gradle目录引入以下代码即可:
dataBinding{ enabled true }
2.配置gradle.properties
android.useAndroidX=true android.enableJetifier=true
3.wanAndroid项目主要有首页、知识、导航、项目四个模块,采用MvvM+Kotlin方式
主界面MainActivity代码如下:
/** * @作者: njb * @时间: 2020/1/13 12:51 * @描述: 主界面 */ open class MainActivity : BaseActivity() { private val fragmentList: MutableList<Fragment> = ArrayList() private val strings = arrayOf("首页", "知识", "导航", "项目") override val layoutId: Int get() = R.layout.activity_main override fun initView() { fragmentList.add(HomeFragment()) fragmentList.add(KnowledgeFragment()) fragmentList.add(NavigationFragment()) fragmentList.add(ProjectFragment()) viewPager!!.adapter = object : FragmentStateAdapter(this) { override fun createFragment(position: Int): Fragment { return fragmentList[position] } override fun getItemCount(): Int { return fragmentList.size } } viewPager.offscreenPageLimit = 3 val tabLayoutMediator = TabLayoutMediator( tab_layout, viewPager, TabConfigurationStrategy { tab: TabLayout.Tab, position: Int -> tab.text = strings[position] } ) tabLayoutMediator.attach() initToolBar() } private fun initToolBar() { setSupportActionBar(toolbar) supportActionBar!!.setDisplayHomeAsUpEnabled(false) supportActionBar!!.setHomeButtonEnabled(false) iv_search.setImageResource(R.drawable.ic_baseline_search_24) } override fun addListener() { iv_search.setOnClickListener(View.OnClickListener { startActivity( Intent( this@MainActivity, SearchActivity::class.java ) ) }) } }
4.首页Fragment代码:
/** * @作者: njb * @时间: 2020/1/10 18:19 * @描述: 首页 */ class HomeFragment : Fragment(), CompletedListener { private var mBinding: ViewDataBinding? = null private var artListAdapter: ArtListAdapter? = null private var viewModel: HomeViewModel? = null private var layoutManager: LinearLayoutManager? = null private var page: Int = 1 private var viewHead: View? = null private var banner: Banner? = null private var bannerModel: List<BannerModel>? = null private var viewModels:BannerViewModel ? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { mBinding = DataBindingUtil.inflate(inflater, R.layout.fm_home, container, false) val view = mBinding!!.root viewHead = LayoutInflater.from(context).inflate(R.layout.item_home_banner, null) initBanner() initView(view) initListener(view) return mBinding!!.root } /** * 初始化view */ private fun initView(view: View) { artListAdapter = ArtListAdapter(null) layoutManager = LinearLayoutManager(activity!!) layoutManager!!.orientation = LinearLayoutManager.VERTICAL view.rv_home.layoutManager = layoutManager artListAdapter!!.addHeaderView(viewHead) view.rv_home.addItemDecoration(DividerDecoration(ContextCompat.getColor(activity!!,R.color.ce7e7e7),2)) view.rv_home.adapter = artListAdapter viewModel = HomeViewModel(artListAdapter!!, this) //显示加载动画 viewModel!!.getArtCircleList(page) } private fun initBanner() { banner = viewHead!!.findViewById(R.id.home_banner) //设置banner样式 banner!!.setBannerStyle(BannerConfig.CIRCLE_INDICATOR) //设置图片加载器 banner!!.setImageLoader(GlideImageLoader()) //设置banner动画效果 banner!!.setBannerAnimation(Transformer.Default) //设置自动轮播,默认为true banner!!.isAutoPlay(true) //设置轮播时间 banner!!.setDelayTime(3000) //设置指示器位置(当banner模式中有指示器时) banner!!.setIndicatorGravity(BannerConfig.CENTER) //banner设置方法全部调用完毕时最后调用 banner!!.start() viewModels = BannerViewModel(banner!!,this) viewModels!!.getBannerList() } /** * 初始化事件 */ private fun initListener(view: View) { artListAdapter!!.setOnItemClickListener{ listener,View,position -> Intent(context, WebViewActivity::class.java).run { putExtra(AppConstant.WEBVIEW_TITLE_KEY, artListAdapter!!.data[position].title) putExtra(AppConstant.WEBVIEW_ID_KEY, artListAdapter!!.data[position].id) putExtra(AppConstant.WEBVIEW_URL_KEY, artListAdapter!!.data[position].link) startActivity(this, null) } } view.rf_home.setOnRefreshListener { page = 1 viewModel!!.getArtCircleList(page) view.rf_home.finishRefresh(200) } view.rf_home.setOnLoadMoreListener { page++ viewModel!!.getArtCircleList(page) view.rf_home.finishLoadMore(200) } } override fun onCompleted() { } }
5.HomeViewModel
/** *@作者: njb *@时间: 2020/1/10 17:55 *@描述: */ class HomeViewModel( private val adapter: ArtListAdapter, private val completedListener: CompletedListener ) { private var observer: Observer<BaseModel<ArticleListModel>>? = null private var repository = HomeRepository() fun getArtCircleList(page:Int) { observer = object : Observer<BaseModel<ArticleListModel>> { override fun onComplete() { completedListener.onCompleted() } override fun onSubscribe(d: Disposable) { } override fun onNext(t: BaseModel<ArticleListModel>) { if (t.errorCode == 0) { t.data?.let { if(page == 1){ adapter.setNewData(it.datas) }else{ adapter.addData(it.datas!!) } } } } override fun onError(e: Throwable) { completedListener.onCompleted() } } repository.getArcticList(page, observer as Observer<BaseModel<ArticleListModel>> ) } }
6.首页请求HomeRespository
/** *@作者: njb *@时间: 2020/1/10 18:00 *@描述: */ class HomeRepository :BaseRepository(){ fun getArcticList( page: Int, observer: Observer<BaseModel<ArticleListModel>>) { apiServer.articleList(page).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observer) } }
7.首页文章列表适配器
/** *@author: njb *@date: 2020/2/11 0011 16:47 *@desc: 文章列表适配器 */ class ArtListAdapter (data:List<ArticleListModel.DatasBean>?): BaseQuickAdapter<ArticleListModel.DatasBean,BaseViewHolder>(R.layout.item_home,data){ override fun convert(helper: BaseViewHolder, item: ArticleListModel.DatasBean) { val itemBinding = DataBindingUtil.bind<ItemHomeBinding>(helper.itemView)!! itemBinding.homebean = item itemBinding.executePendingBindings() } }
8.首页布局:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.ning.mvvmplayandroid.weight.MyRefreshLayout android:id="@+id/rf_home" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_home" android:layout_width="match_parent" android:layout_height="match_parent" /> </com.ning.mvvmplayandroid.weight.MyRefreshLayout> </LinearLayout> </layout>
9.首页Banner加在文章列表头部,Banner广告布局:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.youth.banner.Banner android:id="@+id/home_banner" android:layout_width="match_parent" android:layout_height="200dp" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
10.首页文章列表item布局:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="homebean" type="fule.com.playandroidkotlin.ui.model.ArticleListModel.DatasBean" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" tools:ignore="MissingConstraints"> <TextView android:id="@+id/tv_username" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" android:layout_marginRight="20dp" android:text="@{homebean.author}" android:textColor="@color/colorPrimary" android:textSize="12sp" /> <TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" android:text="@{String.valueOf(homebean.niceDate)}" android:textColor="@color/colorPrimary" android:textSize="12sp" /> <androidx.cardview.widget.CardView android:id="@+id/cv_content" android:layout_width="100dp" android:layout_height="80dp" app:layout_constraintTop_toBottomOf="@+id/tv_username" android:layout_marginTop="10dp" android:elevation="0dp" app:cardCornerRadius="4dp" app:cardElevation="0dp"> <ImageView android:id="@+id/iv_content" android:layout_width="100dp" android:layout_height="80dp" android:scaleType="centerCrop" app:home_image="@{homebean.envelopePic}"/> </androidx.cardview.widget.CardView> <TextView android:id="@+id/tv_content" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginTop="10dp" android:ellipsize="end" android:gravity="top|start" android:lineSpacingExtra="2dp" android:maxLines="2" android:text="@{homebean.title}" android:textColor="@color/black" android:textSize="14sp" app:layout_constraintLeft_toRightOf="@+id/cv_content" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_username" /> <TextView android:id="@+id/tv_type" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="10dp" android:layout_marginTop="10dp" android:layout_toRightOf="@+id/cv_content" android:gravity="center" android:padding="4dp" android:text="@{homebean.chapterName}" android:background="@drawable/shape_article_type_bg" android:textColor="@color/white" android:textSize="12sp" app:layout_constraintLeft_toRightOf="@+id/cv_content" app:layout_constraintTop_toBottomOf="@+id/tv_content" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@+id/tv_content" app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="10dp" app:srcCompat="@drawable/ic_favorite_black_24dp" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
11.从下图可以看到数据是和视图绑定到一起的,数据发生变化,视图也会改变.其他三个模块的代码都是和首页一样,创建view,绑定视图,请求数据,数据请求成功后直接显示.这里就不写重复赘述了。
12.遇到的问题:
12.1 databinding绑定图片和一般的用法不一样,一般的直接设置背景图片就可以,拿到数据后直接用glide显示,这里是和视图绑定的,所以我们得新建一个图片显示的工具类本文暂定ImageUtil,方法必须和布局中的名称一致,否则会报错.
我们在ImageUitl中新建一个显示首页文章列表图片的方法:
@BindingAdapter("image_view") public static void setImageView(ImageView imageView, String urlString) { Glide.with(imageView.getContext()).load(urlString).into(imageView); }
12.2 当实体类有一个list我们好处理,但是如果又嵌套一个的话比较麻烦,本博主也是参考网上的方法,找了很多资料才找到这个办法,刚开始一直获取到的第一个数据.
我们这里就以知识模块为例.返回的数据是一个知识体系列表,然后这个体系列表里面又有一个体系文章标题列表
<data> <variable name="knowledge" type="fule.com.playandroidkotlin.ui.model.KnowledgeModel.DataBean" /> <!导入一个list!> <import type="java.util.List" /> <variable name="knowList" type="List<fule.com.playandroidkotlin.ui.model.ChildrenModel>" /> <!表示list的位置!> <variable name="index" type="int" /> </data>
12.3 下图中一个表示知识体系列表,一个表示体系列表下的栏目列表
12.4 刚开始在fragment布局中layout设置了宽和高会一直报错
图(1)是错误的写法,会一直报错,这是我作为一个初学者啥也不懂踩的坑
图(2)才是正确的写法
13.实现的效果图如下:
14.最后,项目的完整源码地址:
MvvmPlayAndroid: mvvm玩Android,鸿神wanAndroidApi练手项目,包含5个模块
当然,这个小demo还有很多问题需要处理,比如登录注册功能,点赞收藏等等,后面有时间会慢慢补上,欢迎各位大佬前来讨论,指出小弟的问题,如有问题,及时提示,我会及时改正.
最后
以上就是开放河马为你收集整理的Android使用MvvM+kotlin实现简单WanAndroid前言:的全部内容,希望文章能够帮你解决Android使用MvvM+kotlin实现简单WanAndroid前言:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复