我是靠谱客的博主 开放河马,最近开发中收集的这篇文章主要介绍Android使用MvvM+kotlin实现简单WanAndroid前言:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言:

最近在学习mvvm,利用空闲时间写了一个简单版的wanAndroid项目.介绍就不说了,直接上代码.

1.引入:在App——build.gradle目录引入以下代码即可:

dataBinding{
    enabled true
}

img

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,绑定视图,请求数据,数据请求成功后直接显示.这里就不写重复赘述了。

img

12.遇到的问题:

12.1 databinding绑定图片和一般的用法不一样,一般的直接设置背景图片就可以,拿到数据后直接用glide显示,这里是和视图绑定的,所以我们得新建一个图片显示的工具类本文暂定ImageUtil,方法必须和布局中的名称一致,否则会报错.

我们在ImageUitl中新建一个显示首页文章列表图片的方法:

img

@BindingAdapter("image_view")
public static void setImageView(ImageView imageView, String urlString) {
    Glide.with(imageView.getContext()).load(urlString).into(imageView);
}

img

12.2 当实体类有一个list我们好处理,但是如果又嵌套一个的话比较麻烦,本博主也是参考网上的方法,找了很多资料才找到这个办法,刚开始一直获取到的第一个数据.

我们这里就以知识模块为例.返回的数据是一个知识体系列表,然后这个体系列表里面又有一个体系文章标题列表

img

<data>
    <variable
        name="knowledge"
        type="fule.com.playandroidkotlin.ui.model.KnowledgeModel.DataBean" />
​
    <!导入一个list!>
    <import type="java.util.List" />
​
    <variable
        name="knowList"
        type="List&lt;fule.com.playandroidkotlin.ui.model.ChildrenModel>" />
    <!表示list的位置!>
    <variable
        name="index"
        type="int" />
</data>

12.3 下图中一个表示知识体系列表,一个表示体系列表下的栏目列表

img

12.4 刚开始在fragment布局中layout设置了宽和高会一直报错

图(1)是错误的写法,会一直报错,这是我作为一个初学者啥也不懂踩的坑

img 图(2)才是正确的写法

img

13.实现的效果图如下:

img

14.最后,项目的完整源码地址:

MvvmPlayAndroid: mvvm玩Android,鸿神wanAndroidApi练手项目,包含5个模块

当然,这个小demo还有很多问题需要处理,比如登录注册功能,点赞收藏等等,后面有时间会慢慢补上,欢迎各位大佬前来讨论,指出小弟的问题,如有问题,及时提示,我会及时改正.

最后

以上就是开放河马为你收集整理的Android使用MvvM+kotlin实现简单WanAndroid前言:的全部内容,希望文章能够帮你解决Android使用MvvM+kotlin实现简单WanAndroid前言:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部