• Stars
    star
    183
  • Rank 210,154 (Top 5 %)
  • Language
    Kotlin
  • License
    Apache License 2.0
  • Created almost 7 years ago
  • Updated over 2 years ago

Reviews

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

Repository Details

Activity Builder.

Tieguanyin(铁观音)

项目是做什么的?

我们遇到了怎样的问题

我们先来看个例子:

public class UserActivity extends Activity {

    String name;
    int age;
    String title;
    String company;
    
    ...
}

我们有这样一个 Activity,启动它,我们需要传入四个参数,那么我们通常会怎么做呢?

Intent intent = new Intent(this, UserActivity.class);
intent.putExtra("age", age);
intent.putExtra("name", name);
intent.putExtra("company", company);
intent.putExtra("title", title);
startActivity(intent);

仅仅是这样,还不够,所以我们还需要在 UserActivity 这个类当中去读取这些值:

Intent intent = getIntent();
this.age = intent.getIntExtra( "age", 0);
this.name = intent.getStringExtra("name");
this.company = intent.getStringExtra("company" );
this.title = intent.getStringExtra("title");

如果你只有这么一个 Activity 那倒也还好,可是如果你有十个这样的 Activity 呢?

我们怎么去解决

其实我们仔细观察前面的代码,就会发现这两大段传参和读参的代码,都是模式化的代码,我们只需要通过注解处理器来生成就可以了,因此我们给出的解决方法是:

@Builder
public class UserActivity extends Activity {

    @Required
    String name;

    @Required
    int age;

    @Optional
    String title;

    @Optional
    String company;
    
    ...
}

这样的话,对于 Java 代码,我们会生成 UserActivityBuilder,通过它启动 UserActivity

UserActivityBuilder.builder(30, "bennyhuo")
        .company("Kotliner")
        .title("Kotlin Developer")
        .start(this);

注意到,我们的 nameage 都是 Required,因此我们生成的 Builder 在构造时必须对他们进行赋值,而其他两个因为是 Optional,用户可以根据实际情况选择性调用。

而对于 Kotlin 来说,我们则选择为 ContextViewFragment 生成扩展方法,所以我们只需要:

startUserActivity(30, "bennyhuo", "Kotliner", "Kotlin Developer")

需要注意的是,对于 companytitle 这两个可选的字段,我们的扩展方法提供了默认参数 null,因此我们可以选择性提供这些参数的值:

startUserActivity(30, "bennyhuo",  title = "Kotlin Developer")

这些方便快捷的方法帮我们处理了 Intent 传递参数的过程,当然,我们也在运行时对 Activity 的声明周期进行了监听,在 ActivityonCreate 方法调用时,对这些参数进行了注入,因此:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    nameView.setText(name);
    ...
}

super.onCreate(savedInstanceState); 之后,属性 name 就已经被合理的初始化了。

Fragment 我们也提供了类似的逻辑。

状态保存

在一些特定的场景下,例如转屏时,Activity 或者 Fragment 会被销毁并重新创建,销毁前会调用 onSaveInstanceState 来保存状态。我们同样通过监听其生命周期来实现对用户配置好的属性的值进行保存,以保证这些属性在 Activity 或者 Fragment 重新创建时能够得以恢复。

Activity 转场

除了提供参数传递功能外,还支持通过注解为 Activity 配置 pendingTransition,例如:

@Builder(pendingTransition = PendingTransition(enterAnim = R.anim.fade_in, exitAnim = R.anim.fade_out))
class UserActivity : AppCompatActivity() {
    ...
}

这样每次启动 UserActivity 时,我们都会在相应的方法当中调用 overridePendingTransition 来设置这些转场动画。

SharedElement 元素动画

从 Android 5.0 开始,系统在 Activity、Fragment、View 之间支持了共享元素动画,但接口使用起来略显复杂,因此我们通过对 Activity 或者 Fragment 添加注解,在启动或者显示相应的组件时,调用相应的方法来实现共享元素动画,让页面的跳转更加连贯。

我们支持用户通过 idtransitionName 来实现元素的关联。

@Builder(
        sharedElements = [SharedElement(sourceId = R.id.openJavaActivity, targetName = "hello")],
        sharedElementsWithName = [(SharedElementWithName("button2"))],
        sharedElementsByNames= [(SharedElementByNames(source = "button1",target = "button3"))]
)
class DetailsActivity : AppCompatActivity() {
    ...
}

Activity 的结果

有些情况下我们需要目标 Activity 在结束时回传一些结果给当前 Activity,例如我们为了修改用户信息,需要从 UserActivity 跳转到 EditUserActivity,编辑完成之后需要把修改后的结果返回给 UserActivity,我们只需要:

@Builder(resultTypes = {@ResultEntity(name = "name", type = String.class),
                @ResultEntity(name = "age", type = int.class),
                @ResultEntity(name = "title", type = String.class),
                @ResultEntity(name = "company", type = String.class)})
public class EditUserActivity extends Activity {
    ...
}

这样我们就可以这样启动 EditUserActivity

EditUserActivityBuilder.builder(30, "Kotlin", "bennyhuo", "Kotlin Developer")
        .start(this, new EditUserActivityBuilder.OnEditUserActivityResultListener() {
            @Override
            public void onResult(int age, String company, String name, String title) {
                ... // handle result
            }
        });

编辑之后这样返回:

EditUserActivityBuilder.smartFinish(this, 36, "Kotliner","bennyhuo", "Kotlin Dev");

如果是 Kotlin 代码,那么我们还可以使用 Lambda 表达式让代码变得简单:

startEditUserActivity(36, "Kotliner", "bennyhuo", "Kotlin Dev"){
    age, company, name, title ->  
    ... // handle result
}

值得一提的是,对于在编辑用户信息时, UserActivity 的实例因各种原因(例如开发者选项中的”不保留活动“开启时)被销毁,从 EditUserActivity 返回时,UserActivity 被重新创建,导致之间的回调(匿名内部类、Lambda 表达式)持有的外部引用失效,进而使回调没有意义。为了解决这个问题,我会在页面返回,上一个页面被重新创建时尝试替换掉失效的实例以保证回调可以正常使用,其中主要包括:

  1. 外部 Activity 的实例,这个通常没有问题。
  2. 外部 View 的实例,通常也是回调所在的 Activity 当中的 View,在更新实例时,我们通过 View 的 id 来索引,因此如果布局当中有重复的 id,回调可能将无法更新到正确的实例而产生问题。因此请注意保持 Activity 的布局当中 View 的 id 的唯一性。
  3. 外部 Fragment 的实例,通常也是所在的 Activity 当中的 Fragment,为了保证 Fragment 的唯一性,我使用了 Fragment 未公开的属性 mWho 来进行索引。

尽管从理论的角度,这个更新实例的方法较为可靠,但毕竟这个功能比较 Tricky,如果大家在使用过程中发现回调调用之后没有反应,那么请开 Issue 一起讨论解决方案。

属性名常量

有些情况下,大家在页面跳转时不是很方便调用我们生成的方法,那么这时候为了方便使用,我们也会生成以属性名为值的常量,方便使用,例如:

public final class UserActivityBuilder {
  public static final String REQUIRED_age = "age";
  public static final String REQUIRED_name = "name";
  public static final String OPTIONAL_company = "company";
  public static final String OPTIONAL_title = "title";
  ...
}

Fragment 支持

由于从 API 28 开始,Android 废弃了 android.app.Fragment 相关的 API,转而推荐使用 support-fragment,同时由于框架本身也需要监听 Fragment 的生命周期,因此我们对于 android.app.Fragment 不予支持,请谅解。

项目如何接入?

仓库配置:

// snapshot
repositories {
    ...
    maven {
        url "https://oss.sonatype.org/content/repositories/snapshots/"
    }
    ...
}

// release
repositories {
    ...
    mavenCentral()
    ...
}

依赖配置:

plugins {
    id 'com.android.application'
    id 'kotlin-android'

    // for ksp
    id("com.google.devtools.ksp").version("1.5.31-1.0.1")
    // for kapt
    id "kotlin-kapt"
}

dependencies {
    // for android support
    api "com.bennyhuo.tieguanyin:runtime:$latest_version"
    // for androidx
    api "com.bennyhuo.tieguanyin:runtime-androidx:$latest_version"
    // for kapt
    kapt "com.bennyhuo.tieguanyin:compiler:$latest_version"
    // for ksp
    ksp "com.bennyhuo.tieguanyin:compiler-ksp:$latest_version"
}

当前版本:kapt 2.0.1/ksp 2.1.0

注意,kapt 和 ksp 选一个即可;如果你不用 Kotlin,那么 kapt 替换成 annotationProcessor。

最后在 ApplicationonCreate 当中调用:

Tieguanyin.init(this);

即可。

NewIntent

由于 onNewIntent 没有相应的回调,我们无法在框架内部做到用户无感的数据注入,因此如果你需要处理这种情况,请主动调用 processNewIntent 方法:

在 Java 中:

@Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    MyActivityBuilder.processNewIntent(this, intent);
}

在 Kotlin 中:

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    processNewIntent(intent)
}

我们也提供了参数 updateIntent,如果你不希望在注入数据的时候同时也调用 setIntent(intent) 来更新 activityintent,请将它置为 false

更新日志

compiler-ksp & annotations 2.1.0

  1. 废弃 Optional 注解当中的默认值字段,数值、字符串的默认值可以直接在声明处指定。
  2. 为生成的代码添加字段文档
  3. 优化生成的函数,统一调用路径
  4. 为 Builder 类型添加 onIntent 回调,方便调用者自定义 intent
  5. 参数和返回值的常量字段名改为全大写

其他相关

  • Apt-Utils:解决了类型在 Java 和 Kotlin 之间的统一性和兼容性问题,提供了注解处理器一些常用的工具方法,尤其适合同时生成 Java 和 Kotlin 代码的注解处理器项目。
  • Apt-Tutorials:基于本项目简化后并录制的一套注解处理器的教学视频。

License

Apache License 2.0

More Repositories

1

Kotlin-Tutorials

仓库持续记录以 Kotlin 为基础的视频内容的制作过程
Kotlin
4,107
star
2

DiveIntoKotlinCoroutines-Sources

《深入理解 Kotlin 协程》源码
Kotlin
289
star
3

KotlinDeepCopy

DeepCopy extensions for Kotlin Data class. Provide Reflection, Apt, Ksp and Kcp implementations.
Kotlin
280
star
4

CoroutineLite

Simple implementation of kotlinx.coroutines to clarify the design of Kotlin Coroutines.
Kotlin
166
star
5

CppCoroutines

C++
141
star
6

NewDataClassAction

This is a IntelliJ plugin for Kotlin. You may use this to create a data class from a Json string.
Java
93
star
7

hello-kni

Demo for Jni call Kotlin-Native lib.
Kotlin
93
star
8

kotlin-coroutines-android

Useful extensions for coroutines. AutoDispose + MainScope
Kotlin
87
star
9

Apt-Tutorials

注解处理器教程,使用 Kotlin 编写
Kotlin
71
star
10

HackRetrofit

A hacked edition of Retrofit 2.0.2.
Java
53
star
11

Klue

Kotlin
51
star
12

KotlinBlogTranslation

Kotlin 官方博客翻译计划
Python
49
star
13

aMysqlClient

一个类似于Navicat的Mysql Android客户端
Java
44
star
14

Kotlin-Trim-Indent

This is a Kotlin compiler plugin for a compile-time indent trim of raw String.
Kotlin
41
star
15

kotlin-ir-printer

Kotlin
39
star
16

Mixin

An annotation processor to mix Java or Kotlin Classes up into a single Class. Also a sample of X Processing which is an abstract layer of apt and ksp.
Kotlin
30
star
17

KotlinMetaProgrammingInAction-Sources

Kotlin
28
star
18

ReleasableVar

A delegate for those non null vars of which values need to be cleared at the end of the lifecycle.
Java
28
star
19

Android-LuaJavax

Powerful Kotlin style API for Android Lua.
C
26
star
20

KotlinTuples

Kotlin tuples.
Kotlin
20
star
21

TryRun

Kotlin
19
star
22

PortableAndroidHandler

Pure Java implementation of Android Handler.
Java
18
star
23

Shell

Android Shell run without root. Just like adb shell does
Kotlin
16
star
24

Apt-Utils

This is a util library to help you setup apt project easily. Simply call AptContext.init(env) in your Processor, and you can access to the Filer/Messager/Types/Elements from AptContext.
Kotlin
16
star
25

kotlin-code-analyzer

Kotlin
15
star
26

CodeViewer

Android 手机代码阅读器
Java
14
star
27

Kotliner

Kotliner.cn 页面源码
Shell
13
star
28

Kotlin-Native-Demo

A Kotlin-Native Demo with gradle and makefile.
Makefile
11
star
29

SwipeFinishableActivity

Swipable support for Activity to finish itself like Wechat App does.
Java
11
star
30

Cpp-Tutorials

C++
10
star
31

ObjectPropertyDelegate

ObjectPropertyDelegate for Kotlin class properties & functions.
Kotlin
10
star
32

HackViewBinding

Java
9
star
33

Bennyhuo

HTML
8
star
34

enbandari.github.io

这是 www.kotliner.cn 页面仓库
HTML
8
star
35

kotlin-compile-testing-extensions

Kotlin
8
star
36

RetroApollo-Android

Apollo-Android wrapper like Retrofit for GraphQL.
Kotlin
7
star
37

kotlinp

Kotlin
7
star
38

ActivityStack

Kotlin
7
star
39

Kotlin1.4FeaturesSample

Kotlin
6
star
40

jumpcutter2

jumpcutter with edl supports.
Python
5
star
41

KotlinValueDef

Kotlin
4
star
42

Symbol-Processing-Utils

Kotlin
4
star
43

EffectiveJavaInAction

Effective Java 这本书在业界非常流行,连 Java 之父 Gosling 都赞不绝口。可是,这本书本身也存在问题:Java 的初学者往往因为经验缺乏,读起来会有『你说得好有道理哦,可你说的都是什么』的感觉。基于这一点,我计划录制一套视频,从我自己的视角来解读一下这本书,希望让经典更通俗易懂。
4
star
44

kotlin-compiler-plugin-template

Kotlin
3
star
45

SimplePlugin

A simple plugin for intellij platform. This is the demo project from http://www.jetbrains.org/intellij/sdk/docs/tutorials/custom_language_support
Java
3
star
46

kotlin-compiler-plugin-embeddable-plugin

Kotlin
3
star
47

text-cover-simple

Rust
3
star
48

Magic-C-Programming

C
3
star
49

QCloudImageUploaderForMarkDown

Use this to help you upload images to QCloud and replace images urls in you markdown files.
Kotlin
3
star
50

SwiftCoroutinesSample

Swift
2
star
51

kotlin-grammar-tools

Java
2
star
52

rust-learning

Rust
2
star
53

symbol-processing-module-support

Kotlin
2
star
54

ByrWifiConnector

北邮校园网无线认证助手
Java
2
star
55

text-cover

Rust
2
star
56

Images

Images is a tool set to process images.
JavaScript
2
star
57

Kotlin-Coroutine-HelloWorld

This is a very first sample of Kotlin Coroutine I used in the meetup of Beijing. Hello World!
Kotlin
2
star
58

k2-issues

Kotlin
2
star
59

TensorflowDemo

Tensorflow demo by Kotlin Native. Organised by CMake.
CMake
1
star
60

HelloDart

Dart
1
star
61

kotlin-strip-metadata

Kotlin
1
star
62

image-resize-tool

Rust
1
star
63

bilibili-parser

1
star
64

k2-bugs

1
star
65

KmmSample

Kotlin
1
star
66

java-new

Java
1
star
67

SwiftCoroutinesDemo

Swift
1
star
68

HelloFlutter

Dart
1
star
69

anko-legacy

Kotlin
1
star
70

CodeAnalyzer

代码分析工具(主要是统计);Analyzer of our code ( mainly about statistics so far)
Java
1
star
71

EasyDroid-Files

Easy way to access file.
Java
1
star
72

GradleRepositoriesPlugin

A bunch of maven repositories with predefined functions for Gradle.
Kotlin
1
star
73

TouchAssistant

Kotlin
1
star
74

ItemAnimatableListView

If you wanna animate your items when you operate them (add/remove) in a ListView/ExpandableListView, you should check this.
Java
1
star