android-jetpack-demo

Introduction: 🔥 快速入门 Android Jetpack 以及相关 Kotlin、RxJava、MVVM 等主流技术,独立构架 App 的基础技能
More: Author   ReportBugs   OfficialWebsite   
Tags:

android-jetpack-demo

jetpack apache2.0 Gitter Build Status SonarCloud codebeat badge GitHub repo size GitHub code size in bytes GitHub Release Date GitHub language count GitHub top language version GitHub last commit GitHub commit activity GitHub All Releases PRs Welcome Average time to resolve an issue Percentage of issues still open GitHub search hit counter HitCount

目录

一、项目简介

[2019/10/16] 近期一直忙于公司项目,github 更新缓慢,稍后会将项目实践中的问题沉淀总结一下,期待各位斧正~,也欢迎有意向一同学习的同学,提交PR,在issues中讨论,按模块共同学习。或者提交建议

Android-Jetpack-Demo 是一个简单的、集成当前 Google 主流 Android 技术的示例 Demo,旨在帮助有需要的初级开发者,快速上手 Android 新技术、新架构。主要使用livedatalifecyclepagingroomnavigationworkmanagerrxjavakotlindagger2以及viewmodelMVVM简单架构。

代码中都有详细的注释,主要操作演示关注logcat的日志输出

二、更新日志

  • v1.1.0(2019 年 6 月 27 日)
    • 更新AndroidStudio以及Gradle编译版本
    • 更新jetpackkotlin版本为当前最新
    • 压缩存档,以备模块化版本
    • kotlin初级语法的基础博文
  • v1.0.0(2018 年 11 月 14 日)
    • 实现jetpack组件的初级基础用法的演示
    • dagger2的基础用法演示
    • kotlin初级语法的整理注释
    • databinding的基础用法
    • AAC的初级使用

三、Sample 示例

下载体验 apk或者手机扫描二维码下载Demoapk

扫描下载

四、项目组成[^1]

项目主要简单的演示一些android技术与框架库的入门使用,RxJava操作符、Kotlin基本语法,以及JetPack的组件的简单使用。

  • Android Architecture Components
  • RxJava
  • Kotlin
  • Dagger2
  • Jetpack
    • lifecycle
    • livedata
    • databinding
    • navigation
    • paging
    • room
    • workmanager

五、规划

  • [x] 基础使用入门的代码演示
    • [x] DataBinding代码详解
    • [x] Kotlin代码详解
    • [ ] jetpack组件的使用详解
    • [ ] rxJava的使用详解
    • [ ] dagger/koin注入框架的演示详解
    • [ ] App架构相关的详解
  • [ ] 进阶技术&架构的演示
  • [ ] 对应代码的详细博文
  • [ ] 其他前沿技术链接

六、示例内容(部分)

databindinglifecyclelogcat

  • Kotlin语法及部分博文Kotlin
package org.zhiwei.jetpack.kt.base

/**
 * 作者: 志威  zhiwei.org
 * 主页: Github: https://github.com/zhiwei1990
 * 日期: 2019 年 09 月 19 日 11:13
 * 签名: 天行健,君子以自强不息;地势坤,君子以厚德载物。
 *      _              _           _     _   ____  _             _ _
 *     / \   _ __   __| |_ __ ___ (_) __| | / ___|| |_ _   _  __| (_) ___
 *    / _ \ | '_ \ / _` | '__/ _ \| |/ _` | \___ \| __| | | |/ _` | |/ _ \
 *   / ___ \| | | | (_| | | | (_) | | (_| |  ___) | |_| |_| | (_| | | (_) |
 *  /_/   \_\_| |_|\__,_|_|  \___/|_|\__,_| |____/ \__|\__,_|\__,_|_|\___/  -- 志威 zhiwei.org
 *
 * You never know what you can do until you try !
 * ----------------------------------------------------------------
 * Kotlin 的类与对象的相关定义与信息
 * 1、kotlin 中 class 定义类,默认都是 public 的,而且是 final 的,不可继承
 * 2、若要可继承,就需要 open 关键词修饰
 * 3、一个 kt 文件中可以多个 class,以及混合 top level 的变量/常量/函数的定义
 * 4、默认定义的 class 是 final 的,其内部的变量/函数,也就不必要使用 protected 的权限,其作用也就相当于 private 了。
 * 5、每个 class 类都有一个伴生静态 object 类 companion object 在 class 加载的时候就初始化了,作为类的静态成员存在。(object 类,自身是没有伴生类的)
 * 6、kotlin 不同于 java,一般的声明成员属性,不用 getter/setter,当然除非你要控制只能 getter 不能 setter,那样就需要重写
 * 7、在 class 定义函数和 top level 中差不都,也就是 protected 这个权限符号的区分。默认函数也是 final 的。
 * 8、如果 class 是 final 的,函数 open 修饰,是无效的。而且,open 的函数或者变量不能 private 修饰,且与 final 修饰符是互斥的。
 * 9、构造函数分为主构造函数,次构造函数,而且 kotlin 中,如果主构造函数显式的写在 class 的名后,则所有次级构造函数必须调用主构造函数
 * 10、class 类都有一个自身的 init 函数,在 class 加载时候就运行,早于构造函数的调用!!!
 * 11、接口实现,或者类的继承,需要用:,类似于 java 中的 extends,implementation,可多个接口,但只有一个父类
 * 12、抽象类 abstract,其抽象函数 不同于接口的函数,它是不能有默认方法体的。
 * 13、如果子类实现多个接口,且接口中拥有共同的函数命,就会冲突,在子类中就需要显式指明调用哪个
 * 14、单例类 object,也就是静态的单例模式,
 * 15、数据类,一个数据 bean 对象的类,特殊的 class 使用 data class 声明
 */
public final class KtClazz {

    //<editor-folder desc="类的构造函数的讲解模块">

    constructor()//默认 class 类都有一个的无参构造函数

    constructor(name: String)//这样写三个构造函数,属于平级,所以不需要依次调用。倘若在上面 class KtClazz 后添加了构造函数

    constructor(name: String, age: Int)

    //</editor-folder>

    //<editor-folder desc="类函数的定义模块">

    //简单演示 class 中的变量/常量声明定义
    private var abc = "abc"
    protected var bbc = "bbc"//这里会注意,在 top level 中 不能 protected 修饰变量,函数的定义,class 中可以
    // ,但是对于一个 final 的(也就是默认声明)类,这个权限也就相当于 private 了,只有对于 open 的 class,protected 的变量,才能被子类操作
    internal var cbc = "cbc"
    public var dbc = "dbc"

    var bNum = 0b001//二进制的表示数
    var hNum = 0x0f00e//16 进制数,kotlin 中没有 8 进制的表示
    var bigNum = 00_999_999_000.000//可以使用 _ 下划线分割数据,便于读取,但是不会影响实际数值
    val longStr = """long str \srng\t\'在这种 string 的方式,转义符也会失效"""

    val name = "class name is a final value"//类中可以声明不可变量,也就是普通常量,但是不是 static 的静态的,如果声明静态需要在其伴生对象中


    /**
     * 函数的定义,默认也是 public final 的,权限符号可以修改,如果想要被继承,就要用 open 修饰
     * 只要 class 中有一个函数是 open 的,那么这个 class 就必须是 open 的。
     */
    public final fun configData() {
        println("普通默认的无参函数定义")
    }

    /**
     * 有参数的函数定义
     */
    private fun paramConfig(name: String, age: Int) {
        println("name: " + name + "age: " + age)
    }

    /**
     * 可变参数的函数定义,这里用到了 vararg 的关键词,如此调用方就可以传递一个或者多个参数进来。类似于 java 中的 (String... apple)的写法
     */
    internal fun varargConfig(vararg apple: String) {
        println("该函数,是可以接收可变个数的参数")
    }

    //</editor-folder>

    /**
     * 伴生的 object 类,静态类,可以写这个 KtClassObj 的名字,也可以省略不写。
     */
    /*private*/ companion object /*KtClazzObj*/ {
        private const val constName = "静态常量名"//静态常量,声明定义在 class 的伴生对象类中

    }

}

//<editor-folder desc="构造函数演示">

//todo 演示主次构造函数,如果存在 class 声明处的构造函数(这里就是无参的,而且 constructor 可以省略掉)
//内部再有次级构造函数,则需要依次调用主构造函数
class KtClazz2 constructor() {
    constructor(name: String) : this()//调用主构造函数
}

//todo 在主构造函数中,可以同步声明参数为成员属性,就需要 var/val ,可根据实际,添加权限修饰符
//如果没有 var/val,则在 class 内,函数不能直接引用到这个参数字段。需要内部再声明一个,并在 init
class KtClazz3 /*constructor*/(private var name: String, apple: String) {//作为主构造函数 constructor 可省略

    constructor(name: String, age: Int) : this(name, "")//调用主构造函数

    private var mApple = apple//

    fun testApple() {
        //可以引用到 name,但是不能引用到 apple 需要用 mApple
        println(mApple)
        println(name)
    }
}

//todo 演示 init 与构造函数的调用时机,再 UnitTest 中看演示,得出结论,init 函数调用早于构造函数!!,这个需要注意!
class KtClazz4 {

    constructor() {
        println("~~无参数的调用~~")
    }

    constructor(name: String) /*: this()*/ {//如果加上:this()就表示调用该有参函数之前,先调用上面的无参的。
        println("==这里是 含参数$name 构造函数的调用输出 ===")
    }

    init {
        println("---这里是 init 的调用输出---")
    }
}

//</editor-folder>


//<editor-folder desc="接口抽象类 演示">

//接口的定义
private interface IProxy {
//    public var name: String//kotlin 接口内可以定义属性,但是不能设置默认值,实现类就必须实现这个属性
    //kotlin 中接口函数可以有默认的自定义内容,这样的话,实现接口的时候,就不必须实现这个有默认实现的函数方法
    public fun proxy(): String {
        println("默认定义接口的实现函数内容")
        return "default proxy"
    }

    //这个函数,没有默认实现,所以实现类就需要重写这个
    fun tt()

}

//可继承类,
open class opKtClazz {

    protected open fun ott() {

    }

    //定义这两个函数,就是为了演示 subClass 实现接口和继承类的时候,出现函数命冲突,的处理
    open fun tt() {
        println("opKtClazz 的 tt")
    }

    open fun proxy(): String {
        return "null"
    }

}

//抽象类,使用 abstract,就不用 open 修饰了,冗余
abstract class AbsKtClazz {

    abstract fun abs()//抽象函数,不同于接口,不能有默认实现

}

//kotlin 中实现接口,继承类,都是用:符号,多个接口和父类,可以用,分割;可以实现多接口,但是只能有一个父类,和 java 相同,不同于 C/C++
private class ProxyImpl : IProxy, AbsKtClazz() {

    override fun abs() {

    }

    override fun tt() {
        println("实现类中的 tt")
    }

}

//继承 open 的类
private class subKtClazz : opKtClazz(), IProxy {

    //和 java 类似,覆写函数,权限可以放宽,不能收紧
    public override fun ott() {
        super.ott()
    }

    override fun tt() {

    }

    //todo 这个函数名,在接口和父类中都有,所以可以指定调用哪个,或者根据条件区分
    override fun proxy(): String {
        //模拟条件判断,或者可根据业务选。
        if (1 > 0) super<opKtClazz>.proxy() else super<IProxy>.proxy()
        return "sub proxy"
    }
}

//</editor-folder>

//<editor-folder desc="数据类,单例类">

//数据类,就是 final 的不能 open,不能 abstract,就一个主构造函数,不能有其他构造函数。可以有类代码体,变量声明,以及函数等。
// todo 但是,多数情况都是作为单独的数据 bean 封装。实例化数据类的时候,可以单独为一个变量,也可以直接将属性实例化,但是只能实例非私有的
//val (name, age, sex, desc) = org.zhiwei.jetpack.kt.base.User("小明", 22, 1, "小明是个男的,大学生一枚")
data class User(
    private val name: String,
    protected var age: Int,//因为 final,所以 protected 也就失效,类似 private
    internal val sex: Int,
    public var desc: String
) {
    //除了上面的构造函数内的声明变量,也可以在 class 内声明。todo 注意主构造函数内必须至少有一个变量声明。
    var address: String = "北京"

    //也可以有自己的函数方法
    fun configApple() {

    }

    //数据类可以有伴生对象
    companion object {
        //伴生类
    }
}

//单例类,特殊的一个类,用 object 声明,只有空参主构造函数,也就没有伴生对象了。一般用作工具类,单例模式等.调用方式就是 SingleApple.getDeviceId()
object SingleApple {

    fun getDeviceId(): String = "deviceId Str"

}

//</editor-folder>

更多详情,请下载代码,内有详细注释,鉴于本人才学有限,若有不足之处,请大神不吝赐教

七、关于作者 jianshugithubcsdn

作者本人只是一个,就职于某知名(@_@ 有名字的)互联网公司的,技术小白一枚,对于编程有着某种兴趣和热爱,然技术确实渣渣,好读书、不求甚解~~

人之为学有难易乎、为之,则难者亦易矣;不为,则易者亦难矣。

倘若本项目对你有一丝丝的帮助和价值,烦请给个star,或者有什么好的建议或意见,也可以发个issues,谢谢!:happy:

Github starsGithub followersGithub issues

  • License
Copyright 2019 zhiwei.org

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.

[^1]: 项目当前(2019/10/16开发环境为 AndroidStudio 3.5.1gradle 5.4.1Jdk8Kotlin 1.3.51

Apps
About Me
Google+: Trinea trinea
GitHub: Trinea