├── .gitignore ├── .travis.yml ├── README.md ├── annotation ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── lzh │ └── compiler │ └── parceler │ └── annotation │ ├── Arg.java │ ├── BundleBuilder.java │ ├── BundleConverter.java │ ├── Converter.java │ ├── FastJsonConverter.java │ ├── GsonConverter.java │ └── NonNull.java ├── api ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── lzh │ └── compiler │ └── parceler │ ├── ActivityResultCallback.java │ ├── ActivityResultDispatcher.java │ ├── BundleFactory.java │ ├── BundleHandle.java │ ├── CacheManager.java │ ├── Constants.java │ ├── IBundleBuilder.java │ ├── IntentLauncher.java │ ├── ParcelInjector.java │ ├── Parceler.java │ ├── RuntimeInjector.java │ └── Utils.java ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lzh │ │ └── compiler │ │ └── parcelerdemo │ │ ├── BundleActivity.java │ │ ├── InjectorActivity.java │ │ ├── KotlinLoginActivity.kt │ │ ├── LoginActivity.java │ │ ├── MainActivity.java │ │ ├── TestCastActivity.java │ │ ├── base │ │ └── BaseActivity.java │ │ └── bean │ │ ├── Book.java │ │ ├── BundleInfo.java │ │ ├── Info.java │ │ ├── NormalUser.java │ │ └── SerialUser.java │ └── res │ ├── layout │ ├── activity_bundle.xml │ ├── activity_injector.xml │ ├── activity_login.xml │ ├── activity_main.xml │ └── activity_test_cast.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── compiler ├── .gitignore ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── lzh │ │ └── compiler │ │ └── parceler │ │ └── processor │ │ ├── ParcelException.java │ │ ├── ParcelerCompiler.java │ │ ├── factory │ │ ├── BuilderFactory.java │ │ └── ClassFactory.java │ │ ├── model │ │ ├── Constants.java │ │ ├── ElementParser.java │ │ └── FieldData.java │ │ └── util │ │ ├── UtilMgr.java │ │ └── Utils.java │ └── resources │ └── META-INF │ └── services │ └── javax.annotation.processing.Processor ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── javadoc.gradle └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/ 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | 10 | .idea/ 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | sudo: false 4 | 5 | android: 6 | components: 7 | - platform-tools 8 | - tools 9 | - build-tools-25.0.0 10 | - android-23 11 | - sys-img-armeabi-v7a-android-23 12 | - extra-android-m2repository 13 | licenses: 14 | - 'android-sdk-preview-license-52d11cd2' 15 | - 'android-sdk-license-.+' 16 | - 'google-gdk-license-.+' 17 | 18 | script: ./gradlew clean assemble --stacktrace -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parceler   2 | 3 | Parceler是一款简单、轻量级的Bundle数据存取扩展框架。 4 | 5 | 使用此框架,你可以做到: 6 | 7 | 1. 向Bundle中存入任意类型的数据 8 | 2. 从Bundle中读取任意类型的数据 9 | 3. 将数据从Bundle容易中注入到指定的成员变量中去 10 | 4. 将数据从指定成员变量中注入到Bundle中去 11 | 5. 更方便的进行页面启动传值(避免key值硬编码) 12 | 6. 支持在kotlin环境下使用 13 | 7. 实现onActivityResult回调派发。避免到onActivityResult中做一堆判断。 14 | 15 | 更重要的:框架的**总方法数不到100,且无任何额外依赖**! 16 | 17 | ## 依赖 18 | 19 | > 添加JitPack仓库 20 | 21 | ```Groovy 22 | maven { url 'https://jitpack.io' } 23 | ``` 24 | 25 | > 添加依赖 26 | 27 | LastestVersion=[![](https://jitpack.io/v/yjfnypeu/Parceler.svg)](https://jitpack.io/#yjfnypeu/Parceler) 28 | 29 | ```Groovy 30 | dependencies { 31 | // 若要在kotlin环境下使用,请将annotationProcessor替换为kapt。 32 | annotationProcessor "com.github.yjfnypeu.Parceler:compiler:$LastestVersion" 33 | implementation "com.github.yjfnypeu.Parceler:api:$LastestVersion" 34 | } 35 | ``` 36 | 37 | ## 用法 38 | 39 | ### 1. 配置数据转换器 40 | 41 | 数据转换器是框架的核心类,只有配置过对应的数据转换器才能使框架做到**支持对任意类型数据进行存取**的效果。 42 | 43 | 由于常用的数据格式是JSON。所以框架针对流行的fastjson与GSON分别定制了各自的转换器(**FastJsonConverter**和**GsonConverter**),方便进行直接使用。 44 | 45 | 请注意,框架本身并没有直接依赖fastjson或者GSON, 所以具体使用哪种转换器。取决于你当前的运行环境支持使用哪种转换器,比如我们项目有依赖fastjson。那么就可以选择依赖FastJson的转换器: 46 | 47 | ``` 48 | Parceler.setDefaultConverter(FastJsonConverter.class); 49 | ``` 50 | 51 | 啰嗦了那么多,其实就是一句配置即可,然后就可以直接进行方便的数据存取了。 52 | 53 | ### 2. 使用BundleFactory进行任意数据存取 54 | 55 | 框架提供BundleFactory类来作为数据存取的操作类: 56 | 57 | ``` 58 | // 创建操作类实例。bundle为所需要的Bundle数据容器。 59 | // 若为null则将创建一个新的Bundle对应提供使用 60 | BundleFactory factory = Parceler.createFactory(bundle); 61 | 62 | // 通过factory对象进行数据存取 63 | ... 64 | 65 | // 操作完成后。获取操作完成后的Bundle容器实例 66 | Bundle result = factory.getBundle(); 67 | ``` 68 | 69 | 然后即可使用此BundleFactory对任意数据进行存取: 70 | 71 | ```java 72 | // 将指定数据value使用key值存入bundle中 73 | factory.put(key, value); 74 | // 将指定key值的数据从bundle中取出,并转换为指定type数据类型再返回 75 | T t = factory.get(key, Class); 76 | ``` 77 | 78 | #### 示例说明 79 | 80 | 当前我们有两个不同的实体类: 81 | 82 | ```java 83 | // NormalUser未实现序列化 84 | public class NormalUser { 85 | public String username; 86 | } 87 | // SerialUser实现序列化 88 | public class SerialUser implements Serializable { 89 | public String username; 90 | } 91 | ``` 92 | 93 | 然后进行数据存储: 94 | 95 | ``` 96 | NormalUser normalUser = new NormalUser(); 97 | SerialUser serialUser = new SerialUser(); 98 | normalUser.username = "this is normal user bean"; 99 | serialUser.username = "this is serial user bean"; 100 | 101 | BundleFactory factory = Parceler.createFactory(new Bundle()); 102 | factory.put("normal", normalUser); 103 | factory.put("serial", serialUser); 104 | 105 | Bundle result = factory.getBundle(); 106 | ``` 107 | 108 | 最终result数据: 109 | 110 | ![](https://user-gold-cdn.xitu.io/2018/3/30/162766469fe51c10?w=653&h=175&f=png&s=42165) 111 | 112 | 可以看到:NormalUser的实例被自动转换成了JSON进行存储了。 113 | 114 | 然后再从Bundle中进行数据读取: 115 | 116 | ``` 117 | NormalUser newNormalUser = factory.get("normal", NormalUser.class); 118 | SerialUser newSerialUser = factory.get("serial", SerialUser.class); 119 | ``` 120 | 121 | ![](https://user-gold-cdn.xitu.io/2018/3/30/1627669776c6172a?w=646&h=165&f=png&s=44335) 122 | 123 | ### 3. Bundle数据自动注入 124 | 125 | 最常见的使用场景就是在进行Activity跳转传值时使用: 126 | 127 | 发起注入操作可放置于基类中进行使用。所以可以将注入操作添加在Activity基类中: 128 | 129 | ```java 130 | // 将注入器配置到基类中。一次配置,所有子类共同使用 131 | public abstract class BaseActivity extends Activity { 132 | 133 | @Override 134 | protected void onCreate(Bundle savedInstanceState) { 135 | super.onCreate(savedInstanceState); 136 | // 启动时从intent中读取数据并注入到当前类中。 137 | Parceler.toEntity(this,getIntent()); 138 | } 139 | 140 | // ============可用以下方式方便的进行数据现场保护========== 141 | @Override 142 | protected void onSaveInstanceState(Bundle outState) { 143 | super.onSaveInstanceState(outState); 144 | // 将当前类中的使用注解的成员变量的值注入到outState中进行保存。 145 | Parceler.toBundle(this,outState); 146 | } 147 | 148 | @Override 149 | protected void onRestoreInstanceState(Bundle savedInstanceState) { 150 | super.onRestoreInstanceState(savedInstanceState); 151 | // 需要恢复现场时。将数据从saveInstanceState中读取并注入当前类中。恢复现场 152 | Parceler.toEntity(this,savedInstanceState); 153 | } 154 | } 155 | ``` 156 | 157 | 然后就可以愉快的在各种子类中方便的进行使用了: 158 | 159 | ```java 160 | public class UserActivity extends BaseActivity { 161 | 162 | // 直接使用。 163 | @Arg 164 | User user; 165 | // 使用指定key值 166 | @Arg("rename_address") 167 | Address address; 168 | @Arg 169 | int age; 170 | 171 | ... 172 | 173 | } 174 | ``` 175 | 176 | 然后当此UserActivity页面启动后,即可自动将getIntent中的bundle数据,注入到这些被Arg所注解的成员变量中去。 177 | 178 | ### 4. 使用BundleBuilder, 避免key值硬编码 179 | 180 | 以上方的UserActivity为例。需要跳转到此页面并将数据传递过去。我们需要将数据装入Intent中: 181 | 182 | 常见的使用流程都应该是下面这样的: 183 | 184 | ``` 185 | Bundle bundle = Parceler.createFactory(null) 186 | .put("user", user) 187 | .put("address", address) 188 | .put("age", age) 189 | .getBundle(); 190 | 191 | Intent intent = new Intent(this, UserActivity.class); 192 | intent.addExtras(bundle); 193 | startActivity(intent); 194 | ``` 195 | 196 | 可以看到有很多的key值的硬编码。这在开发过程中其实是不推荐的。所以框架提供了BundleBuilder注解: 197 | 198 | ```java 199 | @BundleBuilder 200 | public class UserActivity extends BaseActivity { 201 | ... 202 | } 203 | ``` 204 | 205 | 添加此注解后。将会生成对应的用于生成相应的bundle数据的类, 通过此生成类即可避免key值硬编码: 206 | 207 | ```java 208 | // 将数据通过生成类UserActivityBundleBuilder进行装载 209 | IBundleBuilder builder = UserActivityBundleBuilder.create(new Bundle()) 210 | .setUser(user) 211 | .setAddress(address) 212 | .setAge(age); 213 | 214 | // 使用自带提供的IntentLauncher类,方便的进行启动 215 | Parceler.createLauncher(builder) 216 | .start(context); 217 | 218 | // 或者需要直接使用装载的数据 219 | Bundle result = builder.build(); 220 | ``` 221 | 222 | ### 5. 使用回调处理onActivityResult 223 | 224 | 使用此回调机制。需要在BaseActivity中配置回调的派发方法: 225 | 226 | ``` 227 | public class BaseActivity extends Activity { 228 | @Override 229 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 230 | Parceler.dispatchActivityResult(this, requestCode, resultCode, data); 231 | } 232 | } 233 | ``` 234 | 235 | 然后即可直接在启动时分别配置回调监听器: 236 | 237 | ``` 238 | ActivityResultCallback callback = new ActivityResultCallback() { 239 | @Override 240 | public void onResult(int resultCode, Intent data) { 241 | // TODO 242 | } 243 | }; 244 | 245 | Parceler.createLauncher(TargetActivity.class, bundle) 246 | .setResultCallback(callback) 247 | .start(activity); 248 | ``` 249 | 250 | 友情提醒:当配置了有效的回调之后。可以选择不再设置requestCode。不用再每次都抓耳挠腮的去为requestCode取值了。 251 | 252 | ## 混淆配置 253 | ```Proguard 254 | -keep class com.lzh.compiler.parceler.annotation.** 255 | -keep class * implements com.lzh.compiler.parceler.ParcelInjector 256 | -keepclasseswithmembernames class * { 257 | @com.lzh.compiler.parceler.annotation.Arg ; 258 | } 259 | ``` 260 | 261 | ## 联系作者 262 | 263 | 欢迎提issue
264 | Email:470368500@qq.com
265 | QQ Group:108895031 266 | 267 | ## License 268 | ``` 269 | Copyright 2015 Haoge 270 | 271 | Licensed under the Apache License, Version 2.0 (the "License"); 272 | you may not use this file except in compliance with the License. 273 | You may obtain a copy of the License at 274 | 275 | http://www.apache.org/licenses/LICENSE-2.0 276 | 277 | Unless required by applicable law or agreed to in writing, software 278 | distributed under the License is distributed on an "AS IS" BASIS, 279 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 280 | See the License for the specific language governing permissions and 281 | limitations under the License. 282 | ``` 283 | 284 | 285 | 286 | -------------------------------------------------------------------------------- /annotation/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /annotation/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'maven' 3 | dependencies { 4 | compileOnly 'com.alibaba:fastjson:1.2.31' 5 | compileOnly 'com.google.code.gson:gson:2.8.0' 6 | } 7 | targetCompatibility = '1.7' 8 | sourceCompatibility = '1.7' 9 | 10 | task sourcesJar(type: Jar, dependsOn: classes) { 11 | classifier = 'sources' 12 | from sourceSets.main.allSource 13 | } 14 | 15 | task javadocJar(type: Jar, dependsOn: javadoc) { 16 | classifier = 'javadoc' 17 | from javadoc.destinationDir 18 | } 19 | 20 | artifacts { 21 | archives sourcesJar 22 | archives javadocJar 23 | } -------------------------------------------------------------------------------- /annotation/src/main/java/com/lzh/compiler/parceler/annotation/Arg.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler.annotation; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | /** 24 | * 此注解作用于任意实体类中的成员变量。用以标记此成员变量应该被数据注入器ParcelInjector读取并进行注入操作。 25 | * 26 | * @author haoge 27 | */ 28 | @Target({ElementType.FIELD}) 29 | @Retention(RetentionPolicy.RUNTIME) 30 | public @interface Arg { 31 | /** 32 | * 重命名key值。当为空时,表示将使用成员变量的名字作为从Bundle进行存取时所使用的key值。 33 | */ 34 | String value() default ""; 35 | } 36 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/lzh/compiler/parceler/annotation/BundleBuilder.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parceler.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Add this annotation to the class who need to generating Builder class. 10 | * @author haoge on 2017/12/25. 11 | */ 12 | @Target({ElementType.TYPE}) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface BundleBuilder { 15 | } 16 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/lzh/compiler/parceler/annotation/BundleConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler.annotation; 17 | 18 | import java.lang.reflect.Type; 19 | 20 | /** 21 | * Bundle数据转换器。默认提供了两个json数据解析器:{@link FastJsonConverter}与{@link GsonConverter}. 22 | * @author haoge 23 | */ 24 | public interface BundleConverter { 25 | 26 | /** 27 | * 将指定数据data转换为对应type的数据类型并返回。 28 | * 29 | *

30 | * 请注意:被转换后的数据。应与参数指定的转换数据类型type一致。 31 | *

32 | * 33 | * @return 转换后的数据 34 | */ 35 | Object convertToEntity(Object data, Type type); 36 | 37 | /** 38 | * 将指定数据data。转换为可被放入Bundle中的数据类型。并返回。 39 | * 40 | *

41 | * 请注意:被转换后的数据类型。应该为可被直接放入Bundle类中的数据类型, 如json串 42 | *

43 | * 44 | * @return 被转换后的数据。 45 | */ 46 | String convertToBundle(Object data); 47 | } 48 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/lzh/compiler/parceler/annotation/Converter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler.annotation; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | /** 24 | * 此注解作用于 已被{@link Arg}所标记 的成员变量之上。用于在生成注入器类中。对此成员变量进行的注入操作。使用此处指定的数据转换器。 25 | * 26 | * @author haoge 27 | */ 28 | @Target({ElementType.FIELD}) 29 | @Retention(RetentionPolicy.RUNTIME) 30 | public @interface Converter { 31 | 32 | Class value(); 33 | } 34 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/lzh/compiler/parceler/annotation/FastJsonConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler.annotation; 17 | 18 | import com.alibaba.fastjson.JSON; 19 | import com.lzh.compiler.parceler.annotation.BundleConverter; 20 | 21 | import java.lang.reflect.Type; 22 | 23 | /** 24 | * 默认提供的FastJson数据转换器。使用此转换器前。请确定你的项目依赖了fastjson。 25 | * 26 | * @author haoge 27 | */ 28 | public final class FastJsonConverter implements BundleConverter { 29 | 30 | @Override 31 | public Object convertToEntity(Object data, Type type) { 32 | String json; 33 | if (data instanceof String) { 34 | json = (String) data; 35 | } else if (data instanceof StringBuilder || data instanceof StringBuffer) { 36 | json = data.toString(); 37 | } else { 38 | throw new RuntimeException(String.format("Unsupported type %s to parse with fastjson", data.getClass())); 39 | } 40 | 41 | return JSON.parseObject(json, type); 42 | } 43 | 44 | @Override 45 | public String convertToBundle(Object data) { 46 | return JSON.toJSONString(data); 47 | } 48 | 49 | static { 50 | try { 51 | //noinspection unused 52 | String ignore = JSON.class.getCanonicalName(); 53 | } catch (Throwable t) { 54 | throw new RuntimeException("You should add fastjson to your dependencies list first", t); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/lzh/compiler/parceler/annotation/GsonConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler.annotation; 17 | 18 | import com.google.gson.Gson; 19 | import com.lzh.compiler.parceler.annotation.BundleConverter; 20 | 21 | import java.lang.reflect.Type; 22 | 23 | /** 24 | * 默认提供的使用Gson的数据转换器,使用此转换器前。请确定你的项目依赖了gson。 25 | * @author haoge 26 | */ 27 | public class GsonConverter implements BundleConverter{ 28 | Gson gson = new Gson(); 29 | 30 | @Override 31 | public Object convertToEntity(Object data, Type type) { 32 | String json; 33 | if (data instanceof String) { 34 | json = (String) data; 35 | } else if (data instanceof StringBuilder || data instanceof StringBuffer) { 36 | json = data.toString(); 37 | } else { 38 | throw new RuntimeException(String.format("Unsupported type %s to parse with fastjson", data.getClass())); 39 | } 40 | 41 | return gson.fromJson(json, type); 42 | } 43 | 44 | @Override 45 | public String convertToBundle(Object data) { 46 | return gson.toJson(data); 47 | } 48 | 49 | static { 50 | try { 51 | //noinspection unused 52 | String ignore = Gson.class.getCanonicalName(); 53 | } catch (Throwable t) { 54 | throw new RuntimeException("You should add Gson to your dependencies list first", t); 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/lzh/compiler/parceler/annotation/NonNull.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler.annotation; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | /** 24 | * 此注解作用于已被{@link Arg}所标记的成员变量之上。用于在生成注入器类中。当未正确获取到对应的值时,强制抛出异常。 25 | * 26 | * @author haoge 27 | */ 28 | @Target({ElementType.FIELD}) 29 | @Retention(RetentionPolicy.RUNTIME) 30 | public @interface NonNull { 31 | } 32 | -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /api/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | android { 5 | compileSdkVersion 21 6 | buildToolsVersion '27.0.3' 7 | 8 | defaultConfig { 9 | minSdkVersion 8 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | lintOptions { 22 | abortOnError false 23 | } 24 | 25 | } 26 | 27 | dependencies { 28 | api project(':annotation') 29 | } 30 | 31 | apply from: '../javadoc.gradle' -------------------------------------------------------------------------------- /api/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/admin/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /api/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/ActivityResultCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | import android.content.Intent; 19 | 20 | public interface ActivityResultCallback { 21 | void onResult(int resultCode, Intent data); 22 | } 23 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/ActivityResultDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | import android.app.Activity; 19 | import android.content.Intent; 20 | import android.os.Build; 21 | 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.Iterator; 25 | import java.util.List; 26 | import java.util.Map; 27 | import java.util.Set; 28 | 29 | final class ActivityResultDispatcher { 30 | 31 | private Map> container = new HashMap<>(); 32 | 33 | private static ActivityResultDispatcher dispatcher = new ActivityResultDispatcher(); 34 | private ActivityResultDispatcher(){ } 35 | public static ActivityResultDispatcher get() { 36 | return dispatcher; 37 | } 38 | 39 | void bindRequestArgs(Activity activity, int requestCode, ActivityResultCallback callback) { 40 | if (activity.isFinishing() 41 | || callback == null 42 | || requestCode == -1) { 43 | return; 44 | } 45 | 46 | List list = findListByKey(activity); 47 | list.add(new RequestArgs(requestCode, callback)); 48 | } 49 | 50 | boolean dispatchActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { 51 | if (!container.containsKey(activity)) { 52 | return false; 53 | } 54 | 55 | boolean handle = false; 56 | List list = findListByKey(activity); 57 | for (RequestArgs args:list) { 58 | if (args.requestCode == requestCode) { 59 | args.callback.onResult(resultCode, data); 60 | list.remove(args); 61 | handle = true; 62 | break; 63 | } 64 | } 65 | 66 | releaseInvalidItems(); 67 | return handle; 68 | } 69 | 70 | // 移除无效的条目:比如当前activity在后台时被回收了 71 | private void releaseInvalidItems() { 72 | Set keys = container.keySet(); 73 | Iterator iterator = keys.iterator(); 74 | while (iterator.hasNext()) { 75 | Activity next = iterator.next(); 76 | if (next.isFinishing() 77 | || container.get(next).isEmpty() 78 | || (Build.VERSION.SDK_INT >= 17 && next.isDestroyed()) ) { 79 | iterator.remove(); 80 | } 81 | } 82 | } 83 | 84 | List findListByKey(Activity activity) { 85 | List list = container.get(activity); 86 | if (list == null) { 87 | list = new ArrayList<>(); 88 | container.put(activity, list); 89 | } 90 | return list; 91 | } 92 | 93 | private static class RequestArgs { 94 | int requestCode; 95 | ActivityResultCallback callback; 96 | 97 | public RequestArgs(int requestCode, ActivityResultCallback callback) { 98 | this.requestCode = requestCode; 99 | this.callback = callback; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/BundleFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | import android.os.Bundle; 19 | 20 | import com.lzh.compiler.parceler.annotation.BundleConverter; 21 | 22 | import java.lang.reflect.Type; 23 | 24 | /** 25 | *

提供的用于操作{@link Bundle}数据源的处理入口类。 26 | * 27 | * @author haoge 28 | */ 29 | public final class BundleFactory { 30 | 31 | /* 默认的数据转换器。通过{@link Parceler#setDefaultConverter(Class)}进行设置*/ 32 | static Class DEFAULT_CONVERTER = null; 33 | /* 用于进行操作的bundle实例*/ 34 | private Bundle bundle; 35 | /* 指定是否略过异常。*/ 36 | private boolean ignoreException = false; 37 | private Class converter; 38 | private boolean forceConvert; 39 | 40 | BundleFactory(Bundle bundle) { 41 | if (bundle == null) { 42 | bundle = new Bundle(); 43 | } 44 | this.bundle = bundle; 45 | } 46 | 47 | /** 48 | * 设置使用的数据转换器。若设置为null则表示使用通过{@link Parceler#setDefaultConverter(Class)}所设置的默认转换器, 49 | * 50 | *

51 | * 数据转换器的作用。分为两点: 52 | *

    53 | *
  1. 54 | * 当使用{@link #put(String, Object)}将数据添加入Bundle数据容器。若指定添加的数据类型不能直接被放入{@link Bundle}中, 55 | * 则通过此数据转换器的{@link BundleConverter#convertToBundle(Object)}方法对数据进行转换后再放入{@link Bundle}中。 56 | *
  2. 57 | *
  3. 58 | * 当使用{@link #get(String, Type)}或{@link #get(String, Class)}将数据从Bundle数据中读取出来时。 59 | * 若根据指定key值读取出来的数据类型与指定的数据类型不匹配。则将通过{@link BundleConverter#convertToEntity(Object, Type)}进行对应转换 60 | *
  4. 61 | *
62 | *

63 | * 64 | * @param converter 数据转换器的class。请注意转换器一定需要提供一个空的无参构造器。 65 | * @return itself 66 | * @see BundleConverter 67 | */ 68 | public BundleFactory setConverter(Class converter) { 69 | this.converter = converter; 70 | return this; 71 | } 72 | 73 | /** 74 | *

75 | * 指定在使用{@link #put(String, Object)}将数据存储入Bundle数据容器中时。是否在进行类型判断前强制要求对添加的数据源进行转换。 76 | *

77 | * 78 | *

请注意:此标记位起作用的前提条件包括: 79 | *

    80 | *
  1. 含有有效的可用的数据转换器。
  2. 81 | *
  3. 需要存储的数据源类型为非基本数据类型
  4. 82 | *
83 | * 84 | * @param forceConvert 是否强制进行转换。 85 | * @return itself 86 | */ 87 | public BundleFactory setForceConvert(boolean forceConvert) { 88 | this.forceConvert = forceConvert; 89 | return this; 90 | } 91 | 92 | /** 93 | * 设置是否忽略操作过程中的异常。 94 | * @param ignoreException ignore 当设置为true时。则在操作过程中若出现异常。将不会将此异常抛出。 95 | * @return itself 96 | */ 97 | public BundleFactory ignoreException(boolean ignoreException) { 98 | this.ignoreException = ignoreException; 99 | return this; 100 | } 101 | 102 | /** 103 | * 使用key值将数据源data放入bundle中进行存储 104 | * 105 | * @param key 106 | * 用于放置数据的key non-null 107 | * @param data 108 | * 被放置的数据 non-null 109 | * @return itself 110 | * @see #setConverter(Class) 111 | * @see #setForceConvert(boolean) 112 | * @see #putInternal(String, Object, Class, boolean) 113 | */ 114 | public BundleFactory put(String key, Object data) { 115 | return putInternal(key, data, converter == null ? DEFAULT_CONVERTER : converter, forceConvert); 116 | } 117 | 118 | /** 119 | * 120 | * 使用key值将数据源data放入bundle中进行存储 121 | * 122 | * @param key 123 | * 用于放置数据的key non-null 124 | * @param data 125 | * 被放置的数据 non-null 126 | * @param converterClass 127 | * 数据转换器. 当数据源data的数据类型不能被直接放入{@link Bundle}中时。将会使用此转换器对数据源data进行数据转换。并将转换后的数据放入{@link Bundle}中 128 | * @param forceConvert 129 | * 是否强制要求进行转换。若设置为true, 且转换器不为null时。将强制先对数据源使用转换器进行转换后再放入Bundle中。 130 | * @return itself 131 | * @see BundleConverter 132 | * @see #setForceConvert(boolean) 133 | */ 134 | private BundleFactory putInternal(String key, Object data, Class converterClass, boolean forceConvert) { 135 | if (key == null || data == null) { 136 | return this; 137 | } 138 | 139 | try { 140 | BundleConverter converter = CacheManager.transformConverter(converterClass); 141 | if (forceConvert && converter != null && !Utils.isBaseType(data.getClass())) { 142 | data = converter.convertToBundle(data); 143 | converter = null; 144 | } 145 | BundleHandle.get().toBundle(bundle, key, data, converter); 146 | } catch (Throwable t) { 147 | if (!ignoreException) { 148 | throw t; 149 | } 150 | } 151 | return this; 152 | } 153 | 154 | /** 155 | * 从数据源中取出指定key的数据。使用默认转换器 156 | * @see #getInternal(String, Type, Class) 157 | */ 158 | public T get(String key, Class type) { 159 | try { 160 | return get(key, ((Type) type)); 161 | } catch (ClassCastException cast) { 162 | if (!ignoreException) { 163 | throw cast; 164 | } 165 | return null; 166 | } 167 | } 168 | 169 | /** 170 | * 从数据源中取出指定key的数据。使用默认转换器 171 | * @see #getInternal(String, Type, Class) 172 | */ 173 | public T get(String key, Type type) { 174 | try { 175 | //noinspection unchecked 176 | return (T) getInternal(key, type, converter == null ? DEFAULT_CONVERTER : converter); 177 | } catch (ClassCastException cast) { 178 | if (!ignoreException) { 179 | throw cast; 180 | } 181 | return null; 182 | } 183 | } 184 | 185 | /** 186 | * 从数据源bundle中读取指定key值的数据。将其转换为对应type的对象实例并返回。 187 | * 188 | * @param key 用于从数据源中读取数据的指定key值 189 | * @param type 指定该数据应以怎样的数据类型进行返回。 190 | * @param converterClass 数据转换器。当从{@link Bundle}数据源中使用指定key获取的数据类型与指定type不匹配时。 191 | * 将使用此数据转换器将数据转换为指定type的数据类型实例。 192 | * @return 最终获取的数据。 193 | * @see BundleConverter 194 | */ 195 | private Object getInternal(String key, Type type, Class converterClass) { 196 | Object data = bundle.get(key); 197 | if (data == null || type == null) { 198 | return null; 199 | } 200 | 201 | try { 202 | BundleConverter converter = CacheManager.transformConverter(converterClass); 203 | //noinspection unchecked 204 | return BundleHandle.get().cast(data, type, converter); 205 | } catch (Throwable t) { 206 | if (!ignoreException) { 207 | throw t; 208 | } 209 | return null; 210 | } 211 | } 212 | 213 | /** 214 | * 获取数据源。 215 | * 216 | * @return 被操作的数据源实例。non-null. 217 | */ 218 | public Bundle getBundle() { 219 | return bundle; 220 | } 221 | 222 | 223 | } 224 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/BundleHandle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | import android.os.Build; 19 | import android.os.Bundle; 20 | import android.os.IBinder; 21 | import android.os.Parcelable; 22 | import android.text.TextUtils; 23 | import android.util.Size; 24 | import android.util.SizeF; 25 | import android.util.SparseArray; 26 | 27 | import com.lzh.compiler.parceler.annotation.BundleConverter; 28 | 29 | import java.io.Serializable; 30 | import java.lang.reflect.ParameterizedType; 31 | import java.lang.reflect.Type; 32 | import java.util.ArrayList; 33 | import java.util.Collection; 34 | 35 | /** 36 | *

此类只应被{@link BundleFactory}使用。用于真正从{@link Bundle}数据源中读取或者存储数据。 37 | * 38 | * @author haoge 39 | */ 40 | final class BundleHandle { 41 | private static BundleHandle handle = new BundleHandle(); 42 | private BundleHandle () {} 43 | static BundleHandle get() { 44 | return handle; 45 | } 46 | 47 | /** 48 | * 将任意类型数据data使用key放入Bundle中。 49 | * 50 | *

    51 | *
  • 如果data的数据类型能直接被放入{@link Bundle}, 则直接放入
  • 52 | *
  • 如果data的数据类型不能直接被放入{@link Bundle}, 则使用转换器进行数据转换再放入
  • 53 | *
54 | * 55 | * @param bundle 用于存储数据的容器. 56 | * @param key 用于存储数据的key值 57 | * @param data 需要被放置的数据data 58 | * @param converter 数据转换器实例 59 | */ 60 | void toBundle(Bundle bundle, String key, Object data, BundleConverter converter) { 61 | try { 62 | toBundleInternal(bundle, key, data); 63 | } catch (Throwable t) { 64 | if (converter != null) { 65 | data = converter.convertToBundle(data); 66 | toBundle(bundle, key, data, null); 67 | } else { 68 | throw t; 69 | } 70 | } 71 | } 72 | 73 | private void toBundleInternal(Bundle bundle, String key, Object data) { 74 | Class type = data.getClass(); 75 | if (type.isAssignableFrom(int.class) 76 | || data.getClass().isAssignableFrom(Integer.class)) { 77 | bundle.putInt(key, (Integer) data); 78 | } else if (type.isAssignableFrom(boolean.class) 79 | || type.isAssignableFrom(Boolean.class)) { 80 | bundle.putBoolean(key, (Boolean) data); 81 | } else if (type.isAssignableFrom(byte.class) 82 | || type.isAssignableFrom(Byte.class)) { 83 | bundle.putByte(key, (Byte) data); 84 | } else if (type.isAssignableFrom(char.class) 85 | || type.isAssignableFrom(Character.class)) { 86 | bundle.putChar(key, (Character) data); 87 | } else if (type.isAssignableFrom(long.class) 88 | || type.isAssignableFrom(Long.class)) { 89 | bundle.putLong(key, (Long) data); 90 | } else if (type.isAssignableFrom(float.class) 91 | || type.isAssignableFrom(Float.class)) { 92 | bundle.putFloat(key, (Float) data); 93 | } else if (type.isAssignableFrom(double.class) 94 | || type.isAssignableFrom(Double.class)) { 95 | bundle.putDouble(key, (Double) data); 96 | } else if (type.isAssignableFrom(byte[].class)) { 97 | bundle.putByteArray(key, (byte[]) data); 98 | } else if (type.isAssignableFrom(char[].class)) { 99 | bundle.putCharArray(key, (char[]) data); 100 | } else if (type.isAssignableFrom(int[].class)) { 101 | bundle.putIntArray(key, (int[]) data); 102 | } else if (type.isAssignableFrom(long[].class)) { 103 | bundle.putLongArray(key, (long[]) data); 104 | } else if (type.isAssignableFrom(float[].class)) { 105 | bundle.putFloatArray(key, (float[]) data); 106 | } else if (type.isAssignableFrom(double[].class)) { 107 | bundle.putDoubleArray(key, (double[]) data); 108 | } else if (type.isAssignableFrom(boolean[].class)) { 109 | bundle.putBooleanArray(key, (boolean[]) data); 110 | } else if (type.isAssignableFrom(String.class)) { 111 | bundle.putString(key, (String) data); 112 | } else if (type.isAssignableFrom(String[].class)) { 113 | bundle.putStringArray(key, (String[]) data); 114 | } else if (Bundle.class.isInstance(data)) { 115 | bundle.putBundle(key, (Bundle) data); 116 | } else if (IBinder.class.isInstance(data) 117 | && Build.VERSION.SDK_INT >= 18) { 118 | bundle.putBinder(key, (IBinder) data); 119 | } else if (data instanceof CharSequence) { 120 | bundle.putCharSequence(key, (CharSequence) data); 121 | } else if (data instanceof CharSequence[]) { 122 | bundle.putCharSequenceArray(key, (CharSequence[]) data); 123 | } else if (data instanceof Parcelable) { 124 | bundle.putParcelable(key, (Parcelable) data); 125 | } else if (data instanceof Parcelable[]) { 126 | bundle.putParcelableArray(key, (Parcelable[]) data); 127 | } else if (data instanceof Serializable 128 | && !(data instanceof Collection) 129 | && !data.getClass().isArray()) { 130 | bundle.putSerializable(key, (Serializable) data); 131 | } else if (Build.VERSION.SDK_INT > 21 132 | && data instanceof Size) { 133 | bundle.putSize(key, (Size) data); 134 | } else if (Build.VERSION.SDK_INT > 21 135 | && data instanceof SizeF) { 136 | bundle.putSizeF(key, (SizeF) data); 137 | } else { 138 | toBundleFromGenericType(bundle, key, data); 139 | } 140 | 141 | } 142 | 143 | @SuppressWarnings("unchecked") 144 | private boolean toBundleFromArrayList(Bundle bundle, String key, ArrayList list) { 145 | if (list.isEmpty()) { 146 | bundle.putIntegerArrayList(key, list); 147 | return true; 148 | } 149 | 150 | boolean handle = false; 151 | Object item = list.get(0); 152 | if (item instanceof Integer) { 153 | bundle.putIntegerArrayList(key, list); 154 | handle = true; 155 | } else if (item instanceof Parcelable) { 156 | bundle.putParcelableArrayList(key, list); 157 | handle = true; 158 | } else if (item instanceof String) { 159 | bundle.putStringArrayList(key, list); 160 | handle = true; 161 | } else if (item instanceof CharSequence) { 162 | bundle.putCharSequenceArrayList(key, list); 163 | handle = true; 164 | } 165 | 166 | return handle; 167 | } 168 | 169 | @SuppressWarnings("unchecked") 170 | private boolean toBundleFromSparseArray(Bundle bundle, String key, SparseArray list) { 171 | if (list.size() == 0) { 172 | bundle.putSparseParcelableArray(key, list); 173 | return true; 174 | } 175 | 176 | // extract item from first index and to check it if is supported. 177 | Object item = list.get(list.keyAt(0)); 178 | if (item instanceof Parcelable) { 179 | bundle.putSparseParcelableArray(key, list); 180 | return true; 181 | } 182 | 183 | return false; 184 | } 185 | 186 | @SuppressWarnings({"unchecked", "ConstantConditions"}) 187 | private void toBundleFromGenericType(Bundle bundle, String key, Object data) { 188 | if ((data instanceof ArrayList) && toBundleFromArrayList(bundle, key, (ArrayList) data)) { 189 | return; 190 | } 191 | if (data instanceof SparseArray && toBundleFromSparseArray(bundle, key, (SparseArray) data)) { 192 | return; 193 | } 194 | throw new RuntimeException("Could not put data to bundle"); 195 | } 196 | 197 | /** 198 | *

将指定数据data转换为指定类型type数据并返回。 199 | * 200 | *

    201 | *
  • 当data能直接与数据类型type匹配时,直接返回原始数据data
  • 202 | *
  • 当data不能与type匹配时,使用数据转换器对原始数据data进行转换后再返回。
  • 203 | *
204 | * 205 | * @param data 指定的数据data 206 | * @param type 指定数据类型type 207 | * @param converter 数据转换器 208 | * @return 转换后的指定type类型的数据。 209 | */ 210 | Object cast(Object data, Type type, BundleConverter converter) { 211 | return castInternal(data, type, converter); 212 | } 213 | 214 | private Object castInternal(Object data, Type type, BundleConverter converter) { 215 | Class raw = getRawClass(type); 216 | if (raw.isInstance(data)) return data; 217 | 218 | if (!(data instanceof String)) { 219 | if (converter == null) { 220 | throw new RuntimeException("Should only handle with String. Please check if you had set a converter to used?"); 221 | } else { 222 | data = converter.convertToBundle(data); 223 | } 224 | } 225 | 226 | String value = (String) data; 227 | if (TextUtils.isEmpty(value)) { 228 | return returnsValue(null, raw); 229 | } 230 | 231 | switch (raw.getCanonicalName()) { 232 | case "byte": 233 | case "java.lang.Byte": 234 | return Byte.valueOf(value); 235 | case "short": 236 | case "java.lang.Short": 237 | return Short.valueOf(value); 238 | case "int": 239 | case "java.lang.Integer": 240 | return Integer.valueOf(value); 241 | case "long": 242 | case "java.lang.Long": 243 | return Long.valueOf(value); 244 | case "float": 245 | case "java.lang.Float": 246 | return Float.valueOf(value); 247 | case "double": 248 | case "java.lang.Double": 249 | return Double.valueOf(value); 250 | case "char": 251 | case "java.lang.Character": 252 | return value.charAt(0); 253 | case "boolean": 254 | case "java.lang.Boolean": 255 | return Boolean.valueOf(value); 256 | case "java.lang.StringBuffer": 257 | return new StringBuffer(value); 258 | case "java.lang.StringBuilder": 259 | return new StringBuilder(value); 260 | default: 261 | if (converter != null) { 262 | return converter.convertToEntity(value, type); 263 | } else { 264 | return returnsValue(null, raw); 265 | } 266 | } 267 | } 268 | 269 | // 兼容基本数据类型返回,对返回数据进行二次处理。避免对基本数据类型返回null导致crash 270 | private Object returnsValue(Object value, Class type) { 271 | if (value != null) return value; 272 | 273 | switch (type.getCanonicalName()) { 274 | case "byte": 275 | case "short": 276 | case "int": 277 | return 0; 278 | case "long": 279 | return 0L; 280 | case "float": 281 | return 0f; 282 | case "double": 283 | return 0d; 284 | case "char": 285 | return '0'; 286 | case "boolean": 287 | return false; 288 | default: 289 | return null; 290 | } 291 | } 292 | 293 | private Class getRawClass(Type type) { 294 | if (type instanceof Class) { 295 | return (Class) type; 296 | } else if (type instanceof ParameterizedType) { 297 | return getRawClass(((ParameterizedType) type).getRawType()); 298 | } else { 299 | throw new RuntimeException("Only support of Class and ParameterizedType"); 300 | } 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/CacheManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | import com.lzh.compiler.parceler.annotation.BundleConverter; 19 | 20 | import java.lang.reflect.Field; 21 | import java.lang.reflect.Type; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | /** 26 | * 缓存管理器。用于对一些类进行缓存处理。达到运行加速的效果 27 | * @author haoge 28 | */ 29 | public final class CacheManager { 30 | 31 | /* 数据转换器容器: 存储所有使用过的有效的转换器实例。避免多次进行创建*/ 32 | private final static Map CONVERTER_CONTAINERS = new HashMap<>(); 33 | /* 实体类中字段数据类型容器:避免每次进行注入的时候都去反射读取*/ 34 | private final static Map> TYPES = new HashMap<>(); 35 | 36 | static BundleConverter transformConverter(Class converterClass) { 37 | if (converterClass == null) { 38 | return null; 39 | } 40 | BundleConverter converter = CONVERTER_CONTAINERS.get(converterClass); 41 | if (converter == null) { 42 | try { 43 | converter = converterClass.newInstance(); 44 | CONVERTER_CONTAINERS.put(converterClass, converter); 45 | } catch (Throwable e) { 46 | throw new RuntimeException(String.format("The subclass of BundleConverter %s should provided an empty construct method.", converterClass), e); 47 | } 48 | } 49 | return converter; 50 | } 51 | 52 | /** 53 | * 获取数据实体类entity中指定字段名fieldName的字段的数据类型。 54 | * @param fieldName 字段名 55 | * @param entity 实体类 56 | * @return 反射获取到的真实的数据类型。 57 | */ 58 | public static Type findType(String fieldName, Class entity) { 59 | Map fieldsMap = TYPES.get(entity); 60 | if (fieldsMap == null) { 61 | fieldsMap = new HashMap<>(); 62 | Field[] fields = entity.getDeclaredFields(); 63 | for (Field field : fields) { 64 | fieldsMap.put(field.getName(), field.getGenericType()); 65 | } 66 | TYPES.put(entity, fieldsMap); 67 | } 68 | return fieldsMap.get(fieldName); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | /** 19 | * 20 | * @author haoge 21 | */ 22 | class Constants { 23 | 24 | /** 25 | * 生成的注入器的类名后缀。 26 | */ 27 | static final String SUFFIX = "BundleInjector"; 28 | /** 29 | * 需要被过滤包名前缀。 30 | */ 31 | static final String[] FILTER_PREFIX = new String[]{ 32 | "com.android", 33 | "android", 34 | "java", 35 | "javax", 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/IBundleBuilder.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parceler; 2 | 3 | import android.os.Bundle; 4 | 5 | public interface IBundleBuilder { 6 | 7 | Class getTarget(); 8 | 9 | Bundle build(); 10 | 11 | BundleFactory getFactory(); 12 | } 13 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/IntentLauncher.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parceler; 2 | 3 | import android.app.Activity; 4 | import android.app.Service; 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.os.Build; 9 | import android.os.Bundle; 10 | 11 | import java.util.Random; 12 | 13 | /** 14 | * 用于配合BundleBuilder生成类进行使用的启动器。可用于进行Activity/Service/BroadcastReceiver启动。 15 | * @author haoge on 2017/12/26. 16 | */ 17 | public class IntentLauncher { 18 | 19 | private ActivityResultCallback callback; 20 | private int requestCode = -1; 21 | private Bundle options; 22 | private Bundle bundle; 23 | private Class target; 24 | private Intent extra; 25 | 26 | private static Random sCodeGenerator; 27 | 28 | private IntentLauncher(Bundle bundle, Class target) { 29 | this.bundle = bundle; 30 | this.target = target; 31 | } 32 | 33 | /** 34 | * 创建一个Intent启动器。此启动器关联此Builder类。 35 | * 36 | *

此Builder实例用于提供传输的Bundle数据。以及所关联的目标类:{@link IBundleBuilder#getTarget()}。 37 | * 38 | *

目前此此启动器所支持的关联目标类包括Activity、Service以及BroadcastReceiver的子类。 39 | * 40 | * @param builder 提供数据的Builder 41 | */ 42 | static IntentLauncher create(IBundleBuilder builder) { 43 | return new IntentLauncher(builder.build(), builder.getTarget()); 44 | } 45 | 46 | static IntentLauncher create(Bundle bundle, Class target) { 47 | return new IntentLauncher(bundle, target); 48 | } 49 | 50 | /** 51 | * 设置startActivity时所需要的requestCode。对应{@link Activity#startActivityForResult(Intent, int)} 52 | * 53 | * @param requestCode 请求码 54 | */ 55 | public IntentLauncher setRequestCode(int requestCode) { 56 | this.requestCode = requestCode; 57 | return this; 58 | } 59 | 60 | /** 61 | * 设置在onActivityResult时使用的回调。 62 | * @param callback callback 63 | */ 64 | public IntentLauncher setResultCallback(ActivityResultCallback callback) { 65 | this.callback = callback; 66 | return this; 67 | } 68 | 69 | /** 70 | * 设置startActivity时所需要的options参数。对应{@link Activity#startActivityForResult(Intent, int, Bundle)} 71 | * @param options {@link Activity#startActivityForResult(Intent, int, Bundle)} 72 | */ 73 | public IntentLauncher setOptions(Bundle options) { 74 | this.options = options; 75 | return this; 76 | } 77 | 78 | /** 79 | * 设置Intent镜像。在进行Intent创建时。若设置的extra Intent不为null。则将对此intent实例进行clone并替换Classname提供使用 80 | * @param intent Intent镜像 81 | */ 82 | public IntentLauncher setExtra(Intent intent) { 83 | this.extra = intent; 84 | return this; 85 | } 86 | 87 | /** 88 | * 根据之前配置的数据,获取所需要的Intent实例。 89 | */ 90 | public Intent getIntent(Context context) { 91 | if (context == null) { 92 | return null; 93 | } 94 | 95 | Class target = this.target; 96 | if (!Activity.class.isAssignableFrom(target) 97 | && !Service.class.isAssignableFrom(target) 98 | && !BroadcastReceiver.class.isAssignableFrom(target)) { 99 | return null; 100 | } 101 | 102 | Intent intent; 103 | if (extra != null) { 104 | intent = new Intent(extra); 105 | intent.setClass(context, target); 106 | extra = null; 107 | } else { 108 | intent = new Intent(context, target); 109 | } 110 | intent.putExtras(this.bundle); 111 | return intent; 112 | } 113 | 114 | /** 115 | * 使用此Context实例。根据对{@link IBundleBuilder#getTarget()}的类型判断,进行Intent启动。 116 | * 117 | *

    118 | *
  1. 119 | * 当类型为Activity的子类,则根据context是否为Activity实例。使用 120 | * {@link Activity#startActivityForResult(Intent, int, Bundle)}或者{@link Context#startActivity(Intent)} 121 | * 进行启动 122 | *
  2. 123 | *
  3. 当类型为Service的子类,则使用{@link Context#startService(Intent)}进行启动
  4. 124 | *
  5. 当类型为BroadcastReceiver的子类,则使用{@link Context#sendBroadcast(Intent)}进行启动
  6. 125 | *
  7. 当需要
  8. 126 | *
127 | */ 128 | public void start(Context context) { 129 | if (context == null) { 130 | return; 131 | } 132 | Intent intent = getIntent(context); 133 | Class target = this.target; 134 | 135 | if (Activity.class.isAssignableFrom(target)) { 136 | startActivity(context, intent); 137 | } else if (Service.class.isAssignableFrom(target)) { 138 | context.startService(intent); 139 | } else if (BroadcastReceiver.class.isAssignableFrom(target)) { 140 | context.sendBroadcast(intent); 141 | } 142 | } 143 | 144 | private void startActivity(Context context, Intent intent) { 145 | if (context instanceof Activity) { 146 | if (callback != null && requestCode == -1) { 147 | requestCode = sCodeGenerator.nextInt(0x0000FFFF); 148 | } 149 | Activity activity = (Activity) context; 150 | if (options != null && Build.VERSION.SDK_INT >= 16) { 151 | activity.startActivityForResult(intent, requestCode, options); 152 | } else { 153 | activity.startActivityForResult(intent, requestCode); 154 | } 155 | ActivityResultDispatcher.get().bindRequestArgs(activity, requestCode, callback); 156 | } else { 157 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 158 | context.startActivity(intent); 159 | } 160 | } 161 | 162 | static { 163 | sCodeGenerator = new Random(); 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/ParcelInjector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | import android.os.Bundle; 19 | 20 | import com.lzh.compiler.parceler.annotation.Arg; 21 | 22 | /** 23 | * 请不要直接手动实现此接口 24 | * 25 | *

26 | * 此接口用于定义注入的数据流的两种方向: 27 | *

    28 | *
  1. 将数据从实体类中注入{@link Bundle}: {@link #toBundle(Object, Bundle)}
  2. 29 | *
  3. 将数据从{@link Bundle}中注入实体类: {@link #toEntity(Object, Bundle)}
  4. 30 | *
31 | *

32 | * 33 | *

34 | * 此接口不应由外部直接实现使用。正常情况下。此接口应有如下两种实现类: 35 | *

    36 | *
  1. 根据使用了{@link Arg}注解的实体类编译时生成对应的注入器实现类:生成类名=实体类名+{@link Constants#SUFFIX}
  2. 37 | *
  3. 默认提供的在非APT环境下使用的{@link RuntimeInjector}
  4. 38 | *
39 | *

40 | * 41 | * @param 使用的实体类泛型 42 | * 43 | * @see RuntimeInjector 44 | * @author haoge 45 | */ 46 | public interface ParcelInjector { 47 | 48 | /** 49 | * 用于从Bundle数据容器中,取出数据并注入到实体类中对应的被{@link Arg}所注解的字段中去。 50 | * @param entity 被注入的实体类对象。 51 | * @param bundle {@link Bundle}数据容器 52 | */ 53 | void toEntity(T entity,Bundle bundle); 54 | 55 | /** 56 | * 用于从实体类entity中,将对应的被{@link Arg}注解过的字段的值。注入到Bundle数据容器中。 57 | * @param entity 实体类entity 58 | * @param bundle Bundle数据容器 59 | */ 60 | void toBundle(T entity, Bundle bundle); 61 | 62 | /** 63 | *

提供一个空实现的注入器。用于提供出去避免空指针 64 | */ 65 | ParcelInjector NONE_INJECTOR = new ParcelInjector() { 66 | @Override 67 | public void toEntity(Object entity, Bundle bundle) {} 68 | 69 | @Override 70 | public void toBundle(Object entity, Bundle bundle) {} 71 | }; 72 | 73 | /** 74 | * 提供一个运行时的注入器。用于当未找到编译时生成的注入器时进行使用。 75 | */ 76 | ParcelInjector RUNTIME_INJECTOR = RuntimeInjector.get(); 77 | } 78 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/Parceler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | import android.app.Activity; 19 | import android.content.Intent; 20 | import android.os.Bundle; 21 | 22 | import com.lzh.compiler.parceler.annotation.BundleConverter; 23 | 24 | import java.lang.ref.WeakReference; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | 28 | /** 29 | * 框架入口类。对外提供的功能的入口都在此类中。功能包括以下几点: 30 | * 31 | *

    32 | *
  1. 33 | * 将数据从任意实体类注入到数据容器{@link Bundle}中:{@link #toBundle(Object, Bundle)} 34 | *
  2. 35 | *
  3. 36 | * 将数据从数据容器{@link Bundle}中注入到对应实体类中:使用{@link #toEntity(Object, Intent)}或者{@link #toEntity(Object, Bundle)} 37 | *
  4. 38 | *
  5. 39 | * 创建Bundle数据处理工厂。对{@link Bundle}数据进行灵活存取:{@link #createFactory(Bundle)} 40 | *
  6. 41 | *
  7. 42 | * 设置默认的数据转换器:{@link #setDefaultConverter(Class)} 43 | *
  8. 44 | *
45 | * @author haoge 46 | */ 47 | public final class Parceler { 48 | 49 | /* 缓存的注入器,加速操作。*/ 50 | private static Map> INJECTORS = new HashMap<>(); 51 | 52 | /** 53 | * 将数据从数据容器{@link Bundle}中注入到对应实体类中 54 | * @see #toEntity(Object, Bundle) 55 | */ 56 | public static T toEntity(T entity, Intent intent) { 57 | return toEntity(entity,intent == null ? null : intent.getExtras()); 58 | } 59 | 60 | /** 61 | * 将数据从数据容器{@link Bundle}中注入到对应实体类中: 62 | * 63 | *

64 | * 此注入方式依赖于数据注入器{@link ParcelInjector}实现。 65 | * 注入器的获取方式请参考:{@link #getInjectorByClass(Class)}方法 66 | *

67 | * 68 | * @param 实体类泛型 69 | * @param entity 需要被注入数据的实体类。non-null 70 | * @param data Bundle数据容器。non-null 71 | * 72 | * @return 返回被注入操作后的entity实例。 73 | */ 74 | public static T toEntity(T entity, Bundle data) { 75 | if (entity == null || data == null) return entity; 76 | 77 | ParcelInjector injector; 78 | try { 79 | injector = getInjectorByClass(entity.getClass()); 80 | //noinspection unchecked 81 | injector.toEntity(entity,data); 82 | } catch (Throwable e) { 83 | throw new RuntimeException(String.format("inject failed : %s",e.getMessage()),e); 84 | } 85 | return entity; 86 | } 87 | 88 | /** 89 | *

将数据从实体类entity中读取,并注入到{@link Bundle}数据中。 90 | * 91 | *

92 | * 此注入方式依赖于数据注入器{@link ParcelInjector}实现。 93 | * 注入器的获取方式请参考:{@link #getInjectorByClass(Class)}方法 94 | *

95 | * 96 | * @param entity 需要被注入数据的实体类。non-null 97 | * @param data Bundle数据容器。non-null 98 | * 99 | * @return 返回被注入操作后的Bundle实例。 100 | */ 101 | public static Bundle toBundle(Object entity, Bundle data) { 102 | if (entity == null || data == null) return data; 103 | 104 | ParcelInjector injector; 105 | try { 106 | injector = getInjectorByClass(entity.getClass()); 107 | //noinspection unchecked 108 | injector.toBundle(entity,data); 109 | } catch (Throwable e) { 110 | throw new RuntimeException(String.format("inject failed : %s",e.getMessage()),e); 111 | } 112 | return data; 113 | } 114 | 115 | /** 116 | * internal api: 用于提供给通过编译时注解生成的注入器类进行使用。外部请不要调用 117 | * 118 | *

根据指定class获取其父类的通过编译时注解生成的注入器实例。或者返回{@link ParcelInjector#NONE_INJECTOR} 119 | * 120 | * @param clz 指定的class 121 | * @return 找到的注入器实例,non-null 122 | * @see ParcelInjector 123 | */ 124 | public static ParcelInjector getParentInjectorByClass (Class clz) { 125 | try { 126 | ParcelInjector injector = getInjectorByClass(clz.getSuperclass()); 127 | // filters runtime injector. 128 | if (injector instanceof RuntimeInjector) { 129 | injector = ParcelInjector.NONE_INJECTOR; 130 | } 131 | return injector; 132 | } catch (Throwable e) { 133 | return ParcelInjector.NONE_INJECTOR; 134 | } 135 | } 136 | 137 | /** 138 | *

根据指定class找到对应匹配的注入器. 注入器根据以下获取方式以先后顺序进行获取。 139 | * 140 | *

    141 | *
  1. 142 | * 根据class类名匹配在编译时通过APT方式生成的注入器类对象。若没有。则向上进行父类class的匹配。
    143 | * 匹配规则:注入器生成类名具备一定规则:生成器类名=class类型+{@link Constants#SUFFIX}. 144 | *
  2. 145 | *
  3. 146 | * 当没有匹配到对应的编译时生成的注入器时。提供框架提供的默认的{@link RuntimeInjector}类实例进行使用。 147 | *
  4. 148 | *
149 | * 150 | * @param clz 指定的用于匹配的class 151 | * @return 通过指定class匹配到的注入器类对象。non-null 152 | * 153 | * @see ParcelInjector 154 | */ 155 | private static ParcelInjector getInjectorByClass(Class clz) throws IllegalAccessException, InstantiationException { 156 | ParcelInjector injector; 157 | if (INJECTORS.containsKey(clz) && (injector = INJECTORS.get(clz).get()) != null) { 158 | return injector; 159 | } 160 | String clzName = clz.getName() + Constants.SUFFIX; 161 | 162 | for (String prefix : Constants.FILTER_PREFIX) { 163 | if (clzName.startsWith(prefix)) { 164 | INJECTORS.put(clz,new WeakReference<>(ParcelInjector.RUNTIME_INJECTOR)); 165 | return ParcelInjector.RUNTIME_INJECTOR; 166 | } 167 | } 168 | 169 | try { 170 | Class injectorClz = Class.forName(clzName); 171 | injector = (ParcelInjector) injectorClz.newInstance(); 172 | INJECTORS.put(clz,new WeakReference<>(injector)); 173 | return injector; 174 | } catch (ClassNotFoundException e) { 175 | injector = getInjectorByClass(clz.getSuperclass()); 176 | INJECTORS.put(clz,new WeakReference<>(injector)); 177 | return injector; 178 | } 179 | } 180 | 181 | /** 182 | * 创建一个{@link BundleFactory}对象,以对Bundle数据进行处理操作 183 | * @param src 原始的{@link Bundle}数据源。当为null时,表示将使用一个新建的{@link Bundle}作为数据源进行操作 184 | * @return itself 185 | */ 186 | public static BundleFactory createFactory(Bundle src) { 187 | return new BundleFactory(src); 188 | } 189 | 190 | public static IntentLauncher createLauncher(IBundleBuilder builder) { 191 | return IntentLauncher.create(builder); 192 | } 193 | 194 | public static IntentLauncher createLauncher(Class target, Bundle bundle) { 195 | return IntentLauncher.create(bundle, target); 196 | } 197 | 198 | /** 199 | * 针对{@link BundleFactory}指定默认使用的数据转换器。 200 | * @param converter 默认使用的转换器class. 此class应含有一个默认的无参构造。便于框架需要使用的来构造使用。 201 | */ 202 | public static void setDefaultConverter(Class converter) { 203 | BundleFactory.DEFAULT_CONVERTER = converter; 204 | } 205 | 206 | public static boolean dispatchActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { 207 | return ActivityResultDispatcher.get().dispatchActivityResult(activity, requestCode, resultCode, data); 208 | } 209 | 210 | private Parceler () {} 211 | } 212 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/RuntimeInjector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | import android.os.Bundle; 19 | import android.text.TextUtils; 20 | 21 | import com.lzh.compiler.parceler.annotation.Arg; 22 | import com.lzh.compiler.parceler.annotation.BundleConverter; 23 | import com.lzh.compiler.parceler.annotation.Converter; 24 | 25 | import java.lang.reflect.Field; 26 | import java.util.ArrayList; 27 | import java.util.HashMap; 28 | import java.util.List; 29 | import java.util.Map; 30 | 31 | /** 32 | * 提供一个完全基于反射使用的注入器。兼容非apt环境使用。 33 | */ 34 | final class RuntimeInjector implements ParcelInjector{ 35 | 36 | /* 缓存任意实体类与其内部所配置的Arg参数数据的映射表*/ 37 | private final static Map> CONTAINER = new HashMap<>(); 38 | 39 | private final static RuntimeInjector injector = new RuntimeInjector(); 40 | private RuntimeInjector(){} 41 | public static RuntimeInjector get() { 42 | return injector; 43 | } 44 | 45 | @Override 46 | public void toEntity(Object entity, Bundle bundle) { 47 | List list = findByEntity(entity.getClass()); 48 | BundleFactory factory = Parceler.createFactory(bundle); 49 | for (Args item:list) { 50 | Object result; 51 | factory.setConverter(item.converter); 52 | result = factory.get(item.key, item.field.getGenericType()); 53 | if (result != null) { 54 | setFieldValue(entity, result, item.field); 55 | } 56 | } 57 | } 58 | 59 | @Override 60 | public void toBundle(Object entity, Bundle bundle) { 61 | BundleFactory factory = Parceler.createFactory(bundle); 62 | List list = findByEntity(entity.getClass()); 63 | for (Args arg : list) { 64 | factory.setConverter(arg.converter); 65 | factory.put(arg.key, getFieldValue(entity, arg.field)); 66 | } 67 | } 68 | 69 | private void setFieldValue(Object entity, Object result, Field field) { 70 | try { 71 | field.setAccessible(true); 72 | field.set(entity, result); 73 | } catch (Throwable t) { 74 | // ignore 75 | } 76 | } 77 | 78 | private Object getFieldValue(Object entity, Field field) { 79 | try { 80 | field.setAccessible(true); 81 | return field.get(entity); 82 | } catch (Throwable t) { 83 | return null; 84 | } 85 | } 86 | 87 | /** 88 | * 解析出实体类entity中(包括父类)。所有的被{@link Arg}所注解的字段数据。 89 | * @param entity 被解析的实体类class 90 | * @return 获取的数据 91 | */ 92 | private List findByEntity(Class entity) { 93 | if (isSystemClass(entity)) { 94 | return new ArrayList<>(); 95 | } 96 | List list = CONTAINER.get(entity); 97 | if (list == null) { 98 | list = new ArrayList<>(); 99 | List subList = findByEntity(entity.getSuperclass()); 100 | list.addAll(subList); 101 | Field[] fields = entity.getDeclaredFields(); 102 | for (Field field : fields) { 103 | if (field.isAnnotationPresent(Arg.class)) { 104 | Arg arg = field.getAnnotation(Arg.class); 105 | Converter converter = field.getAnnotation(Converter.class); 106 | Args args = new Args(); 107 | args.key = TextUtils.isEmpty(arg.value()) ? field.getName() : arg.value(); 108 | args.field = field; 109 | args.converter = converter == null ? null : converter.value(); 110 | list.add(args); 111 | } 112 | } 113 | CONTAINER.put(entity, list); 114 | } 115 | return list; 116 | } 117 | 118 | /* 过滤系统类。由于系统类不参与注入。过滤以加速运行*/ 119 | private boolean isSystemClass(Class clz) { 120 | String clzName = clz.getCanonicalName(); 121 | for (String prefix : Constants.FILTER_PREFIX) { 122 | if (clzName.startsWith(prefix)) { 123 | return true; 124 | } 125 | } 126 | return false; 127 | } 128 | 129 | private static class Args { 130 | String key; 131 | Field field; 132 | Class converter; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /api/src/main/java/com/lzh/compiler/parceler/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.compiler.parceler; 17 | 18 | public class Utils { 19 | 20 | /* Used for generated code.*/ 21 | public static T wrapCast (Object data) { 22 | //noinspection unchecked 23 | return (T) data; 24 | } 25 | 26 | static boolean isBaseType(Class clz) { 27 | return clz == Integer.class 28 | || clz == int.class 29 | || clz == boolean.class 30 | || clz == Boolean.class 31 | || clz == byte.class 32 | || clz == Byte.class 33 | || clz == char.class 34 | || clz == Character.class 35 | || clz == float.class 36 | || clz == Float.class 37 | || clz == double.class 38 | || clz == Double.class 39 | || clz == long.class 40 | || clz == Long.class; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-kapt' 4 | 5 | android { 6 | compileSdkVersion 27 7 | buildToolsVersion '27.0.3' 8 | defaultConfig { 9 | applicationId "com.lzh.compiler.parcelerdemo" 10 | minSdkVersion 15 11 | targetSdkVersion 27 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | lintOptions { 16 | abortOnError false 17 | } 18 | 19 | buildTypes { 20 | debug { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | release { 25 | minifyEnabled false 26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | } 30 | 31 | def use_local = false 32 | def PARCELER_VERSION = '1.4.0' 33 | def Router_version = '2.8.3' 34 | 35 | dependencies { 36 | if (use_local) { 37 | kapt project(':compiler') 38 | implementation project(':api') 39 | } else { 40 | kapt "com.github.yjfnypeu.Parceler:compiler:$PARCELER_VERSION" 41 | implementation "com.github.yjfnypeu.Parceler:api:$PARCELER_VERSION" 42 | } 43 | 44 | implementation 'com.android.support:appcompat-v7:27.1.1' 45 | implementation 'com.alibaba:fastjson:1.1.57.android' 46 | implementation 'com.google.code.gson:gson:2.8.0' 47 | 48 | kapt "com.github.yjfnypeu.Router:router-compiler:$Router_version" 49 | implementation "com.github.yjfnypeu.Router:router-api:$Router_version" 50 | 51 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 52 | 53 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/admin/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -dontwarn com.lzh.compiler.parceler.processor.** 19 | -dontwarn butterknife.** 20 | #Parceler混淆规则 21 | -keep class com.lzh.compiler.parceler.annotation.** 22 | -keep class * implements com.lzh.compiler.parceler.ParcelInjector 23 | 24 | -keepclasseswithmembernames class * { 25 | @com.lzh.compiler.parceler.annotation.Arg ; 26 | } 27 | 28 | #添加ButterKnife混淆规则 29 | -keep class butterknife.** { *; } 30 | -keep class **$$ViewBinder { *; } 31 | 32 | -keepclasseswithmembernames class * { @butterknife.* ; } 33 | -keepclasseswithmembernames class * { @butterknife.* ; } 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/BundleActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import com.lzh.compiler.parceler.BundleFactory; 9 | import com.lzh.compiler.parceler.Parceler; 10 | import com.lzh.compiler.parceler.annotation.BundleBuilder; 11 | import com.lzh.compiler.parcelerdemo.bean.Book; 12 | import com.lzh.compiler.parcelerdemo.bean.Info; 13 | import com.lzh.compiler.parcelerdemo.bean.NormalUser; 14 | import com.lzh.compiler.parcelerdemo.bean.SerialUser; 15 | 16 | import java.lang.reflect.Type; 17 | import java.util.Set; 18 | 19 | /** 20 | * 此页面用于展示如何使用Parceler进行Bundle的数据存取操作。 21 | */ 22 | @BundleBuilder 23 | public class BundleActivity extends Activity { 24 | 25 | BundleFactory factory; 26 | TextView result; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_bundle); 32 | factory = Parceler.createFactory(new Bundle()); 33 | result = (TextView) findViewById(R.id.result); 34 | } 35 | 36 | public void putNormalData(View view) { 37 | factory.put("int", 1); 38 | factory.put("string", "Hello world"); 39 | factory.put("parcelable", new Info()); 40 | result.setText("存入普通数据成功"); 41 | } 42 | 43 | public void putSpecialData(View view) { 44 | factory.put("book", new Book("逗逼是怎么炼成的", 66.66f)); 45 | result.setText("存入特殊数据成功"); 46 | } 47 | 48 | public void getDataWithoutParceler(View view) { 49 | Bundle bundle = factory.getBundle(); 50 | Set keys = bundle.keySet(); 51 | 52 | StringBuilder builder = new StringBuilder("不使用Parceler进行Bundle数据读取展示:"); 53 | for (String key : keys) { 54 | builder.append("\r\n"); 55 | builder.append(key + " = " + bundle.get(key)); 56 | } 57 | 58 | result.setText(builder.toString()); 59 | } 60 | 61 | public void getDataWithParceler(View view) { 62 | StringBuilder builder = new StringBuilder("使用Parceler进行Bundle数据读取展示:"); 63 | resolveKeyValue(builder, "int", int.class); 64 | resolveKeyValue(builder, "string", String.class); 65 | resolveKeyValue(builder, "parcelable", Info.class); 66 | resolveKeyValue(builder, "book", Book.class); 67 | result.setText(builder.toString()); 68 | } 69 | 70 | private void resolveKeyValue(StringBuilder builder, String key, Type type) { 71 | builder.append("\r\n"); 72 | builder.append(key + " = " + factory.get(key, type)); 73 | } 74 | 75 | public void testSerialAndNormalStore(View view) { 76 | NormalUser normalUser = new NormalUser(); 77 | SerialUser serialUser = new SerialUser(); 78 | normalUser.username = "this is normal user bean"; 79 | serialUser.username = "this is serial user bean"; 80 | 81 | BundleFactory factory = Parceler.createFactory(new Bundle()); 82 | factory.put("normal", normalUser); 83 | factory.put("serial", serialUser); 84 | 85 | Bundle result = factory.getBundle(); 86 | 87 | NormalUser newNormalUser = factory.get("normal", NormalUser.class); 88 | SerialUser newSerialUser = factory.get("serial", SerialUser.class); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/InjectorActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.lzh.compiler.parceler.Parceler; 8 | import com.lzh.compiler.parceler.annotation.Arg; 9 | import com.lzh.compiler.parcelerdemo.base.BaseActivity; 10 | 11 | import java.util.Set; 12 | 13 | /** 14 | * 此页面用于演示使用Parceler在Bundle与Entity之间进行双向注入的展示 15 | */ 16 | public class InjectorActivity extends BaseActivity { 17 | 18 | TextView result; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_injector); 24 | result = (TextView) findViewById(R.id.result); 25 | } 26 | 27 | public void toEntity(View view) { 28 | Entity.User user = new Entity.User(); 29 | user.username = "toEntity"; 30 | user.password = "654321"; 31 | Bundle bundle = Parceler.createFactory(null) 32 | .put("user", user) 33 | .getBundle(); 34 | 35 | Entity entity = Parceler.toEntity(new Entity(), bundle); 36 | result.setText("toEntity:\r\n" + entity.toString()); 37 | } 38 | 39 | public void toBundle(View view) { 40 | Entity.User user = new Entity.User(); 41 | user.username = "toBundle"; 42 | user.password = "123456"; 43 | Entity entity = new Entity(); 44 | entity.user = user; 45 | 46 | // 读取entity实例中被注解的字段并存入bundle中 47 | Bundle bundle = Parceler.toBundle(entity, new Bundle()); 48 | // 打印bundle数据 49 | Set keys = bundle.keySet(); 50 | StringBuilder builder = new StringBuilder("toBundle:"); 51 | for (String key : keys) { 52 | builder.append("\r\n"); 53 | builder.append(key + "= " + bundle.get(key)); 54 | } 55 | result.setText(builder.toString()); 56 | } 57 | 58 | 59 | public static class Entity { 60 | @Arg 61 | public User user; 62 | 63 | public static class User { 64 | @Arg 65 | public String username; 66 | @Arg 67 | public String password; 68 | 69 | @Override 70 | public String toString() { 71 | return "User{" + 72 | "username='" + username + '\'' + 73 | ", password='" + password + '\'' + 74 | '}'; 75 | } 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | return "Entity{" + 81 | "user=" + user + 82 | '}'; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/KotlinLoginActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo 2 | 3 | import android.os.Bundle 4 | import android.widget.EditText 5 | import com.lzh.compiler.parceler.annotation.Arg 6 | import com.lzh.compiler.parceler.annotation.BundleBuilder 7 | import com.lzh.compiler.parcelerdemo.base.BaseActivity 8 | 9 | /** 10 | * 在kotlin中使用示例 11 | * Created by haoge on 2018/4/11. 12 | */ 13 | @BundleBuilder 14 | class KotlinLoginActivity : BaseActivity() { 15 | 16 | @Arg 17 | var username: String? = null 18 | @Arg 19 | var password: String? = null 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | setContentView(R.layout.activity_login) 24 | 25 | findViewById(R.id.username).setText(username) 26 | findViewById(R.id.password).setText(password) 27 | } 28 | 29 | override fun onBackPressed() { 30 | setResult(2) 31 | finish() 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo; 2 | 3 | import android.os.Bundle; 4 | import android.widget.EditText; 5 | 6 | import com.lzh.compiler.parceler.annotation.Arg; 7 | import com.lzh.compiler.parceler.annotation.BundleBuilder; 8 | import com.lzh.compiler.parcelerdemo.base.BaseActivity; 9 | 10 | @BundleBuilder 11 | public class LoginActivity extends BaseActivity{ 12 | 13 | @Arg("username") 14 | private String username; 15 | @Arg("password") 16 | String password; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_login); 22 | ((EditText) findViewById(R.id.username)).setText(username); 23 | ((EditText) findViewById(R.id.password)).setText(password); 24 | } 25 | 26 | public String getUsername() { 27 | return username; 28 | } 29 | 30 | public void setUsername(String username) { 31 | this.username = username; 32 | } 33 | 34 | @Override 35 | public void onBackPressed() { 36 | setResult(1); 37 | finish(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | 8 | import com.lzh.compiler.parceler.ActivityResultCallback; 9 | import com.lzh.compiler.parceler.IBundleBuilder; 10 | import com.lzh.compiler.parceler.Parceler; 11 | import com.lzh.compiler.parceler.annotation.FastJsonConverter; 12 | import com.lzh.compiler.parcelerdemo.base.BaseActivity; 13 | 14 | import java.util.HashMap; 15 | import java.util.LinkedHashMap; 16 | 17 | public class MainActivity extends BaseActivity{ 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | // 配置数据装换器 24 | Parceler.setDefaultConverter(FastJsonConverter.class); 25 | } 26 | 27 | /** 28 | * 到数据注入功能展示页 29 | */ 30 | public void toInjectorActivity(View view) { 31 | startActivity(new Intent(this, InjectorActivity.class)); 32 | } 33 | 34 | /** 35 | * 到基础Bundle存取功能展示页 36 | */ 37 | public void toBundleActivity(View view) { 38 | startActivity(new Intent(this, BundleActivity.class)); 39 | } 40 | 41 | public void toIntentActivity(View view) { 42 | // 根据LoginActivity所生成的BundleBuilder类。创建Builder实例。并传入数据 43 | IBundleBuilder builder = LoginActivityBundleBuilder.create(null) 44 | .setUsername("IntentLauncher tester") 45 | .setPassword("123456"); 46 | 47 | // 使用IntentLauncher结合Builder进行组件启动 48 | Parceler.createLauncher(builder) 49 | .setRequestCode(1001) 50 | .start(this); 51 | } 52 | 53 | public void toTestCastActivity(View view) { 54 | Intent intent = new Intent(this, TestCastActivity.class); 55 | // 此处将会被系统序列化之后。类型会变化的数据类型实例存入Intent中进行传递。测试。 56 | HashMap map = new LinkedHashMap<>(); 57 | map.put("Hello", "World"); 58 | // 传递HashMap的子类,目标页取出时数据类型为 HashMap 59 | intent.putExtra("hashMap", map); 60 | 61 | // 传入StringBuilder, 目标页取出时数据类型为 String 62 | intent.putExtra("builder", (CharSequence) new StringBuilder("StringBuilder")); 63 | // 传递StringBuffer, 目标页取出时数据类型为 String 64 | intent.putExtra("buffer", (CharSequence) new StringBuffer("StringBuffer")); 65 | 66 | // 传递Parcelable的子类数组,目标页取出时数据类型为 Parcelable[] 67 | intent.putExtra("parcelables", new TestCastActivity.SubParcelable[]{new TestCastActivity.SubParcelable()}); 68 | 69 | startActivity(intent); 70 | } 71 | 72 | public void toKotlinLoginActivity(View view) { 73 | 74 | IBundleBuilder builder = KotlinLoginActivityBundleBuilder.create(null) 75 | .setUsername("Kotlin") 76 | .setPassword("123455"); 77 | 78 | Parceler.createLauncher(builder) 79 | .setResultCallback(new ActivityResultCallback() { 80 | @Override 81 | public void onResult(int resultCode, Intent data) { 82 | Log.e("MainActivity", "KotlinLoginResult:" + resultCode); 83 | } 84 | }) 85 | .start(this); 86 | } 87 | 88 | @Override 89 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 90 | super.onActivityResult(requestCode, resultCode, data); 91 | System.err.println("requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]"); 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/TestCastActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo; 2 | 3 | import android.os.Bundle; 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | import android.widget.Toast; 7 | 8 | import com.lzh.compiler.parceler.annotation.Arg; 9 | import com.lzh.compiler.parcelerdemo.base.BaseActivity; 10 | 11 | import java.util.LinkedHashMap; 12 | 13 | /** 14 | * 此测试页面主要用于测试部分数据跨组件序列化传递后。传递后所读取的对象与原始数据不一致的情况,如: 15 | * 16 | * StringBuilder与StringBuffer传递后。取出为String 17 | */ 18 | public class TestCastActivity extends BaseActivity { 19 | 20 | @Arg 21 | StringBuilder builder; 22 | @Arg 23 | StringBuffer buffer; 24 | @Arg 25 | SubParcelable[] parcelables; 26 | @Arg 27 | LinkedHashMap hashMap; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_test_cast); 33 | try { 34 | checkForNull(builder, "builder"); 35 | checkForNull(buffer, "buffer"); 36 | checkForNull(parcelables, "parcelables"); 37 | checkForNull(hashMap, "hashMap"); 38 | } catch (Exception e) { 39 | Toast.makeText(this, "类转换兼容测试失败。", Toast.LENGTH_SHORT).show(); 40 | finish(); 41 | } 42 | } 43 | 44 | void checkForNull(Object obj, String name) throws Exception{ 45 | if (obj == null) { 46 | throw new RuntimeException(String.format( 47 | "检查到检查对象TestCastActivity.%s为null,数据转换兼容失败", name 48 | )); 49 | } 50 | } 51 | 52 | public static class SubParcelable implements Parcelable { 53 | public SubParcelable() { 54 | } 55 | 56 | protected SubParcelable(Parcel in) { 57 | } 58 | 59 | @Override 60 | public void writeToParcel(Parcel dest, int flags) { 61 | } 62 | 63 | @Override 64 | public int describeContents() { 65 | return 0; 66 | } 67 | 68 | public static final Creator CREATOR = new Creator() { 69 | @Override 70 | public SubParcelable createFromParcel(Parcel in) { 71 | return new SubParcelable(in); 72 | } 73 | 74 | @Override 75 | public SubParcelable[] newArray(int size) { 76 | return new SubParcelable[size]; 77 | } 78 | }; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo.base; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import com.lzh.compiler.parceler.Parceler; 8 | 9 | // 将注入器配置到基类中。一次配置,所有子类共同使用 10 | public abstract class BaseActivity extends Activity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | Parceler.toEntity(this,getIntent()); 16 | } 17 | 18 | @Override 19 | public void setContentView(int layoutResID) { 20 | super.setContentView(layoutResID); 21 | } 22 | 23 | @Override 24 | protected void onSaveInstanceState(Bundle outState) { 25 | super.onSaveInstanceState(outState); 26 | Parceler.toBundle(this,outState); 27 | } 28 | 29 | @Override 30 | protected void onRestoreInstanceState(Bundle savedInstanceState) { 31 | super.onRestoreInstanceState(savedInstanceState); 32 | Parceler.toEntity(this,savedInstanceState); 33 | } 34 | 35 | @Override 36 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 37 | Parceler.dispatchActivityResult(this, requestCode, resultCode, data); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/bean/Book.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo.bean; 2 | 3 | 4 | import com.lzh.compiler.parceler.annotation.Arg; 5 | import com.lzh.compiler.parceler.annotation.NonNull; 6 | 7 | public class Book{ 8 | @NonNull 9 | @Arg 10 | public String username; 11 | @Arg 12 | public float price; 13 | 14 | public Book() { 15 | } 16 | 17 | public Book(String username, float price) { 18 | this.username = username; 19 | this.price = price; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "Book{" + 25 | "username='" + username + '\'' + 26 | ", price=" + price + 27 | '}'; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/bean/BundleInfo.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo.bean; 2 | 3 | import android.os.Binder; 4 | import android.os.Bundle; 5 | import android.os.IBinder; 6 | import android.os.Parcelable; 7 | import android.util.SparseArray; 8 | 9 | import com.lzh.compiler.parceler.annotation.Arg; 10 | 11 | import java.io.Serializable; 12 | import java.util.ArrayList; 13 | 14 | public class BundleInfo { 15 | 16 | // ====所有bundle直接支持的数据类型。============ 17 | @Arg 18 | public Bundle bundle = new Bundle(); 19 | @Arg 20 | public IBinder binder = new Binder(); 21 | @Arg 22 | public boolean bool = true; 23 | @Arg 24 | public Boolean UpBool = true; 25 | @Arg 26 | public boolean[] boolArr = new boolean[]{true}; 27 | @Arg 28 | public byte bt = 1; 29 | @Arg 30 | public Byte UpBt = 2; 31 | @Arg 32 | public byte[] byArr = new byte[]{0, 1}; 33 | @Arg 34 | public char cr = 'a'; 35 | @Arg 36 | public Character UpCr = 'b'; 37 | @Arg 38 | public char[] crArr = new char[]{'a'}; 39 | 40 | @Arg 41 | public int it = 1; 42 | @Arg 43 | public Integer UpInt = 2; 44 | @Arg 45 | public int[] itArr = new int[]{0, 1}; 46 | 47 | @Arg 48 | public long lg = 2L; 49 | @Arg 50 | public Long UpLg = 3L; 51 | @Arg 52 | public long[] lgArr = new long[]{2L}; 53 | 54 | @Arg 55 | public float ft = 1.0f; 56 | @Arg 57 | public Float UpFt = 2.0f; 58 | @Arg 59 | public float[] ftArr = new float[]{0f, 1f}; 60 | 61 | @Arg 62 | public double db = 1d; 63 | @Arg 64 | public Double UpDb = 2d; 65 | @Arg 66 | public double[] dbArr = new double[]{0d, 1d}; 67 | @Arg 68 | public String str = "str"; 69 | @Arg 70 | public String[] strArr = new String[]{"arr"}; 71 | @Arg 72 | public ArrayList strList = new ArrayList<>(); 73 | 74 | @Arg 75 | public StringBuilder charSequence = new StringBuilder("charSequence"); 76 | @Arg 77 | public StringBuilder[] charSequencesArr = new StringBuilder[]{new StringBuilder("charSequence")};// CharSequence[] 78 | @Arg 79 | public ArrayList charSequencesList = new ArrayList<>(); 80 | @Arg 81 | public Info parcelable = new Info(); 82 | @Arg 83 | public Info[] parcelables = new Info[]{new Info()};// Parcelable[] 84 | @Arg 85 | public ArrayList stringArrayList = new ArrayList<>(); 86 | @Arg 87 | public ArrayList parcelableArrayList = new ArrayList<>(); 88 | @Arg 89 | public ArrayList integerArrayList = new ArrayList<>(); 90 | @Arg 91 | public SparseArray parcelableSparseArray = new SparseArray<>(); 92 | 93 | @Arg 94 | public Serializable serializable = new Info(); 95 | 96 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/bean/Info.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo.bean; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * Created by admin on 16/10/14. 10 | */ 11 | 12 | public class Info implements Serializable, Parcelable{ 13 | public Info() { 14 | } 15 | 16 | protected Info(Parcel in) { 17 | } 18 | 19 | public static final Creator CREATOR = new Creator() { 20 | @Override 21 | public Info createFromParcel(Parcel in) { 22 | return new Info(in); 23 | } 24 | 25 | @Override 26 | public Info[] newArray(int size) { 27 | return new Info[size]; 28 | } 29 | }; 30 | 31 | @Override 32 | public String toString() { 33 | return "Info{}"; 34 | } 35 | 36 | @Override 37 | public int describeContents() { 38 | return 0; 39 | } 40 | 41 | @Override 42 | public void writeToParcel(Parcel dest, int flags) { 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/bean/NormalUser.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo.bean; 2 | 3 | /** 4 | * @author haoge on 2018/3/30. 5 | */ 6 | 7 | public class NormalUser { 8 | public String username; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzh/compiler/parcelerdemo/bean/SerialUser.java: -------------------------------------------------------------------------------- 1 | package com.lzh.compiler.parcelerdemo.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author haoge on 2018/3/30. 7 | */ 8 | 9 | public class SerialUser implements Serializable { 10 | public String username; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_bundle.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |