• Stars
    star
    220
  • Rank 179,413 (Top 4 %)
  • Language
    Kotlin
  • License
    Apache License 2.0
  • Created about 5 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Type based Jetpack MVVM library.

Android VMLib: One Quick MVVM Library Based On Jetpack

中文

License Version Code Grade Build Min Sdk Version Author QQ Group

This project is designed for fast development. The library is mainly based on Jetpack LiveData and ViewModel. At the same time, this project can support DataBinding as well as ViewBinding integration. Also, it provided over 20 kinds of utils classes, companied with features of kotlin, make it easier to use. Anyway, this project can accelerate your development and save a lot of code for you.

1. Use the library

1.1 Add jcenter first

The library is published to jcenter. So, you can use jcenter to introduce this library in your project:

repositories { mavenCentral() }

1.2 Add dependecy

implementation "com.github.Shouheng88:vmlib:$latest-version"

If you need the downloader library based on OkHttp, try add the dependency below:

implementation "com.github.Shouheng88:vmlib-network:$latest-version"

1.3 Initialize the library

Call VMLib.onCreate(this) in your custom Application,

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        VMLib.onCreate(this)
    }
}

This option is only used to get a global Context, so we could use it everywhere. And it won't take too much time.

1.4 Add proguard rules

# Add the rule below if you are using one of the EventBus
-keep class org.greenrobot.eventbus.EventBus {*;}
-keep class org.simple.eventbus.EventBus {*;}

# Add the rule if you want to use umeng
-keep class com.umeng.analytics.MobclickAgent {*;}

# Add the rule if you are using Android-UIX
-keep class me.shouheng.uix.common.UIX {*;}

# Add the rule and replace 'package' of your own App package if you are using ViewBinding
-keep class package.databinding.** {
    public static * inflate(android.view.LayoutInflater);
}

2. VMLib best practice

2.1 Embrace new interaction

Normaly, we need to initialize a LiveData instance everywhere if we want to use it in our project. This will lead to too many global variables in your ViewModel. By simply design, we could make it easy and clean. For example. if you want to request one page data from network, your viewmodel might be like this below,

// me.shouheng.eyepetizer.vm.EyepetizerViewModel#requestFirstPage
fun requestFirstPage() {
    // notify data loading state
    setLoading(HomeBean::class.java)
    // do netowrk request
    eyepetizerService.getFirstHomePage(null, object : OnGetHomeBeansListener {
        override fun onError(code: String, msg: String) {
            // notify load failed
            setFailed(HomeBean::class.java, code, msg)
        }

        override fun onGetHomeBean(homeBean: HomeBean) {
            // notify load succeed
            setSuccess(HomeBean::class.java, homeBean)
        }
    })
}

Then, in the activity, observe the data like below,

observe(HomeBean::class.java, {
    // on succeed
    val list = mutableListOf<Item>()
    it.data.issueList.forEach { issue ->
        issue.itemList.forEach { item ->
            if (item.data.cover != null
                && item.data.author != null
            ) list.add(item)
        }
    }
    adapter.addData(list)
}, { /* on failed */ loading = false }, { /* on loading */ })

This makes you logic simplier and more clean.

The magic is that we use the class type to locate a LiveData instance. Whenever we call setXXX in view model or observe in view layer, we use the Class type to get a LiveData instance from the so called LiveData Pool. So, that means, the Class is the unique identifies of LiveData.

Except Class, we can also use a bool variable and a integer to locate the LiveData.

2.2 Use DataBinding and Viewbinding

VMLib allows you use DataBinding, ViewBinding or none of them. When you want to use DataBinding, you need to make a little change on your gradle:

dataBinding {
    enabled true
}

and let your activity extend the CommonActivity.

For larger project, DataBinding might cause too much time for gradle building. So, for large project, you can use ViewBinding instead. At this time, you need to change the gradle as:

viewBinding {
    enabled true
}

and let your activity extend ViewBindingActivity.

Of course, if you want to use neither of them. What you need to do is just let your activity extend BaseActivity to use power provided by VMlib.

For fragment, VMLib provided similer abstract classes.

When let your activity or fragment extend base classes of VMLib, you have to specify a ViewModel type. For some pages, they are so simple that we don't need to define a ViewModel for it. In this case, we can use the empty view model provied by VMLib, EmptyViewModel.

2.3 Utils and utils-ktx

Different from other libraries, utils classes of VMLib was added by dependency of another project, Android-Utils. Android-Utils provided 20+ utils classes, including io, resources, image, animation and runtime permission etc. This is why VMLib is pwoerful. The utils classes of this library can meet almost all requirements of your daily development. You can get more information about Android-Utils by reading its document.

Except utils classes, VMLib also provided a utils kotlin extension based on Android-Utils. If you want to use the ktx library, you need to add the below dependency on your project,

implementation "me.shouheng.utils:utils-ktx:$latest-version"

By configing above, you can save a lot code. For example, if you want to get a drawable, tint it and then display it in ImageView. One line is enough:

iv.icon = drawableOf(R.drawable.ic_add_circle).tint(Color.WHITE)

If you want to request runtime permission in Activity, what you need to do is only writing one line below,

checkStoragePermission {  /* got permission */ }

As for avoding continous click, you only need one line,

btnRateIntro.onDebouncedClick { /* do something */ }

All in all, by VMLib you can significantly lower the difficulty of development.

2.4 Get result responsively

In VMLib, we refined logic of getting result from another Activity. In VMLib, you don't need to override onActivityResult method any more. You can use the onResult method and a integer for request code to get result:

onResult(0) { code, data ->
    if (code == Activity.RESULT_OK) {
        val ret = data?.getStringExtra("__result")
        L.d("Got result: $ret")
    }
}

This is in fact implemented by dispatching result and calling callback methods in BaseActivity. The goodness is that you don't need to override onActivityResult.

Except calling onResult method, you can also use the start method we provided and a callback to get result:

start(intent, 0) { resultCode, data ->
    if (resultCode == Activity.RESULT_OK) {
        val ret = data?.getStringExtra("__result")
        toast("Got result: $ret")
    }
}

By top level Activity, this is reather easy to achive and it won't cost too much code.

2.5 EventBus

VMLib support EventBus. Generally, for EventBus, you have two choices of EvnetBus and AndroidEventBus. To use EventBus, what you need to do is to use @ActivityConfiguration to decorate your activity and let useEventBus filed of it be true.

@ActivityConfiguration(useEventBus = true)
class DebugActivity : CommonActivity<MainViewModel, ActivityDebugBinding>() {
    // ...
}

Then, you need to use @Subscribe to subscribe:

@Subscribe
fun onGetMessage(simpleEvent: SimpleEvent) {
    // do something ...
}

At last, you can use method of Bus to send a global message anywhere.

VMLib can handle details of EventBus which make your code simpler.

2.6 Wrapper classes: Resources and Status

In VMLib, interaction between ViewModel and View is achived by transfering data wrappered by Resources and Status. The Status is an enum, which have three values, means 'Succeed', 'Failed' and 'Loading' seperatlly. The Resources contains a filed of Status, and a data filed which represent the data. Also the Resources provided 5 additional fileds whose name start with udf. You can use them to carry some extra information.

The wrapper is able to use not only just between view model and view layer but also other circumstances, for example, getting result from kotlin coroutines. The goodness is that you can use one class type transfer three states.

2.7 Container Activity

In order to use Fragment, we provided ContainerActivity, a container for Fragment. It's rather to use. For example, If we want to use SampleFragment in ContainerActivity, set some arguments, animation direction etc. The code below is enough for you:

ContainerActivity.open(SampleFragment::class.java)
    .put(SampleFragment.ARGS_KEY_TEXT, stringOf(R.string.sample_main_argument_to_fragment))
    .put(ContainerActivity.KEY_EXTRA_ACTIVITY_DIRECTION, ActivityDirection.ANIMATE_BACK)
    .withDirection(ActivityDirection.ANIMATE_FORWARD)
    .launch(context!!)

ContainerActivity can get fragment instance from fragment class and then display it in container. The logic is located in ContainerActivity, what you need to do is just implement your owen Fragment logic.

ContainerActivity is rather suitable for cases Fragment is simple. In such cases, you don't need to define Activity yourself, the ContainerActivity is enouth.

2.8 Compressor

So far, Compressor is the last part for VMLib.

This is an advanced and easy to use image compress library for Android, Compressor. It support not only async but also sync API. Also, it support multiple types of input and ouput, which can meet most of your requirements. Get more about it by its document.

3. About

License

Copyright (c) 2019-2020 Jeff Wang.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

More Repositories

1

MarkNote

An open sourced markdown note-taking application for Android.
Java
890
star
2

Compressor

An easy to use image compress library for Android.
Kotlin
600
star
3

iCamera

Yet another camera library for Android.
Kotlin
462
star
4

AwesomeSwift

❤️ SwiftUI All In One Example.
Swift
238
star
5

Android-references

[DEPRECATE] 请访问新项目 https://github.com/Shouheng88/Android-VMLib 👏 Android 示例程序:MVP, MVVM, 组件化, AndroidX, ARouter, RxJava, EventBus, ButterKnife, 视频播放, 视频直播, 网络访问, 布局和控件整理等
Java
214
star
6

Android-notes

[DEPRECATED] Articles, notes, interview questions and resources management for Android.
156
star
7

OmniList

开源的时间管理App,基于Material Design设计
Java
93
star
8

AndroidStartup

An Android startup jobs sceduler.
Kotlin
51
star
9

EasyMark

The markdown parser, editor and viewer for Android which is rather easy to integrate.
Java
47
star
10

autopackage

An Android auto package script.
Python
38
star
11

AndroidTools

🔧 Many useful tools for Android development, adb wrapper, smali, languages etc.
Python
38
star
12

xDialog

An beautiful and easy to use dialog library for Android.
Kotlin
24
star
13

LeafNote-Community

A platform to share information and materials about Leaf Note.
18
star
14

xAdapter

A convenient way to use Adapter in RecyclerView based on Kotlin DSL and BRVAH.
Kotlin
17
star
15

Seed

Booster is a SpringBoot generator used to genrate everything for your Springboot App to accelate your server development.
Java
13
star
16

products-spider

JD & TB products spider.
Python
11
star
17

jarjar

一个 Jar 瘦身工具,用来从 jar 文件中移除你调用不到的类文件。可以用来做 Android 包体积优化优化。
Python
10
star
18

the-chinese-city-rank

中国城市排行,选择更适合你定居的城市
Python
3
star
19

Shouheng88

3
star
20

Springcloud-references

the basic show cases of spring cloud development
Java
2
star