├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kongzue │ │ └── messagebusdemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── kongzue │ │ │ └── messagebusdemo │ │ │ ├── Activity2.java │ │ │ ├── Activity3.java │ │ │ ├── Activity4.java │ │ │ ├── App.java │ │ │ ├── MainActivity.java │ │ │ ├── util │ │ │ ├── ListData.java │ │ │ ├── LoginInfo.java │ │ │ └── User.java │ │ │ └── views │ │ │ └── AutoCreateListView.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_2.xml │ │ ├── activity_3.xml │ │ ├── activity_4.xml │ │ ├── activity_main.xml │ │ └── item_list_test.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_round.webp │ │ ├── img_bug.png │ │ └── img_user.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── kongzue │ └── messagebusdemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme └── what_is_runner.jpg ├── runner ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── kongzue │ └── runner │ ├── Data.java │ ├── Event.java │ ├── Runner.java │ ├── ViewModel.java │ ├── interfaces │ ├── ActivityRunnable.java │ ├── AutoCreateListViewInterface.java │ ├── BaseModel.java │ ├── BindModel.java │ ├── CustomDataSetter.java │ ├── DataWatcher.java │ ├── DataWatchers.java │ ├── RootViewInterface.java │ └── SenderTarget.java │ └── util │ ├── AnyObjectSetter.java │ ├── AutoCreateListViewAdapter.java │ └── ViewDataSetter.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kongzue 的消息总线 2 | 3 | Kongzue Runner 旨在快速完成 App 逻辑构建,协助开发者低成本完成业务开发。 4 | 5 | Runner 提供一个独立的消息事件传递总线,不依赖 Intent,可以独立传递数据、执行事件,亦可以对尚未运行的 Activity 预设需要执行的事件,或者跨界面预设接下来要执行的事件。 6 | 7 | 还提供一套近乎全自动化的 ViewModel 框架,能够依据数据和 View 的对应关系自动实现数据绑定和界面适配(Beta)。 8 | 9 | ![Kongzue Runner](readme/what_is_runner.jpg) 10 | 11 | ## 优势 12 | 13 | - 操作简单易上手; 14 | 15 | - 不需要重写任何接口,无需繁琐的设置,不需要你做任何继承或者重写接口; 16 | 17 | - 可以对一个不存在,还没启动的 Activity 也能生效; 18 | 19 | - 跨类操作直接对内部成员赋值; 20 | 21 | - 自动化,默认主线程执行,操作 UI 更方便; 22 | 23 | - 直接丢就完事了,这货就是个挂; 24 | 25 | ## 引入 26 | 27 |
28 | 最新版本: 29 | 30 | Jitpack.io 31 | 32 |
33 | 34 | 35 | 1) 在 project 的 build.gradle 文件中找到 `allprojects{}` 代码块添加以下代码: 36 | 37 | ``` 38 | allprojects { 39 | repositories { 40 | google() 41 | jcenter() 42 | maven { url 'https://jitpack.io' } //增加 jitPack Maven 仓库 43 | } 44 | } 45 | ``` 46 | 47 | ⚠️请注意,使用 Android Studio 北极狐版本(Arctic Fox)创建的项目,需要您前往 settings.gradle 添加上述 jitpack 仓库配置。 48 | 49 | 2) 在 app 的 build.gradle 文件中找到 `dependencies{}` 代码块,并在其中加入以下语句: 50 | 51 | ``` 52 | implementation 'com.github.kongzue:Runner:0.0.3' 53 | ``` 54 | 55 | 56 | ## 怎么丢? 57 | 58 | 首先你得初始化,建议在 Application#onCreate 里进行: 59 | 60 | ```java 61 | Runner.init(this); 62 | ``` 63 | 64 | 然后就可以愉快的丢东西了! 65 | 66 | ### 丢事件 67 | 68 | 在已经实例化的 Activity 上执行操作: 69 | 70 | ```java 71 | //MainActivity.getInstance() 指向 MainActivity 的实例化对象,此处只做演示用,不建议这样用有内存泄漏的风险 72 | Event.runOnActivity(MainActivity.getInstance(), new ActivityRunnable() { 73 | @Override 74 | public void run(Activity activity) { 75 | //Todo... 76 | } 77 | }); 78 | ``` 79 | 80 | 不确定,或尚未实例化的情况下,在指定 Activity 上执行操作(会在实例化之后执行): 81 | 82 | ```java 83 | Event.runOnActivity(Activity2.class, new ActivityRunnable() { 84 | @Override 85 | public void run(Activity activity) { 86 | //Todo... 87 | } 88 | }); 89 | ``` 90 | 91 | 甚至不知道 class,只有个 Activity 的名字,在指定名字的 Activity 上执行操作(会在实例化之后执行): 92 | 93 | ```java 94 | Event.runOnActivity("Activity2", new ActivityRunnable() { 95 | @Override 96 | public void run(Activity activity) { 97 | //Todo... 98 | } 99 | }); 100 | ``` 101 | 102 | 额外说明,ActivityRunnable 具有泛型,你可以直接指定泛型为你的目标 Activity,这样就可以直接操作其内部的 public 修饰的成员或方法了: 103 | 104 | ```java 105 | Event.runOnActivity("Activity2", new ActivityRunnable() { 106 | @Override 107 | public void run(Activity2 activity2) { 108 | activity2.execPublicFunction(); 109 | } 110 | }); 111 | ``` 112 | 113 | #### 在回到此界面时执行 114 | 115 | 除了 runOnActivity 外,还有 runOnResume,此方法与 runOnActivity 的操作基本一致,但它的执行条件是 116 | 117 | - 当返回该界面时; 118 | 119 | - 当处于该界面时; 120 | 121 | 即若当前指定界面处于顶层,runOnResume 会立即执行,若处于后台或者非顶层,则当界面恢复到顶层时执行。 122 | 123 | ### 丢内容 124 | 125 | 首先,你需要在目标 Activity 上编写一个成员,例如: 126 | 127 | ```java 128 | Bitmap bitmapResult; 129 | ``` 130 | 131 | 对已经实例化的 Activity 中的成员直接赋值: 132 | 133 | ```java 134 | //activity2 为已经实例化的 Activity2 135 | Data.sendToActivity(activity2, "bitmapResult", BitmapFactory.decodeResource(getResources(),R.mipmap.img_bug)); 136 | ``` 137 | 138 | 不确定,或尚未实例化的情况下,在指定 Activity 中的成员直接赋值(会在实例化之后执行): 139 | 140 | ```java 141 | Data.sendToActivity(Activity2.class, "bitmapResult", BitmapFactory.decodeResource(getResources(),R.mipmap.img_bug)); 142 | ``` 143 | 144 | 至不知道 class,只有个 Activity 的名字,在指定 Activity 中的成员直接赋值(会在实例化之后执行): 145 | 146 | ```java 147 | Data.sendToActivity("Activity2", "bitmapResult", BitmapFactory.decodeResource(getResources(),R.mipmap.img_bug)); 148 | ``` 149 | 150 | 要是担心混淆导致成员名称发生变化,可以使用注解,在 Activity2 中对成员进行注解标注其接收的 key: 151 | 152 | ```java 153 | @SenderTarget("bitmapResult") 154 | Bitmap bitmap; 155 | ``` 156 | 157 | ### 对于任意类的成员内容更新 158 | 159 | 比如现在有一个数据存储类 User,请在其构造函数或初始化方法中添加 `Runner.bindAnyObject(object)`,例如: 160 | 161 | ```java 162 | public class User { 163 | 164 | public User() { 165 | Runner.bindAnyObject(this); 166 | } 167 | 168 | private String name; 169 | private int age; 170 | @SenderTarget("avatar") 171 | private Bitmap bitmap; 172 | 173 | //... 174 | } 175 | ``` 176 | 177 | 若当前已存在实例化的对象 user,那么可以通过以下代码更新其内容: 178 | 179 | ```java 180 | Data.sendToAnyObject(user, "name", "ZhangSan"); 181 | ``` 182 | 183 | 若担心混淆,可使用 `@SenderTarget(...)` 注解标注其接收的 key。 184 | 185 | 若当前 User 不确定是否实例化,可使用其 Class 或类名来代替设置: 186 | 187 | ```java 188 | Data.sendToAnyObject(User.class , "name", "ZhangSan"); 189 | ``` 190 | 191 | Kongzue Runner 的优势在于,你可以在程序的任何地方指定修改它的值,例如 Demo 中演示了,在 Activity2 中对 MainActivity 中的 user 对象内容进行操作 [查看代码](https://github.com/kongzue/Runner/blob/5c5ae5e235a910e383289d75d517e4318803100c/app/src/main/java/com/kongzue/messagebusdemo/Activity2.java#L131)。 192 | 193 | 另外,Kongzue Runner 配备了完善的弱引用,您无需担心内存泄漏的问题,若出于项目中存在多个实例化的相同对象的数据操作,建议使用实例化后的对象进行操作,或者在不需要处理其数据时,使用以下方法解绑对象: 194 | 195 | ```java 196 | Runner.unbindAnyObject(obj); 197 | ``` 198 | 199 | Kongzue Runner 操作数据遵循**栈**的处理方式,即,若存在多个相同类型的对象,使用 Class/className 模式操作时遵循后入栈的优先操作的方式,且不会对所有相同类型对象都进行处理。 200 | 201 | ## 随时更新 View 的内容 202 | 203 | 你可以为 View 指定一个注解,当对应 key 的广播执行时,**所有** (包括其他界面)拥有该注解的 View 的内容会被更新。 204 | 205 | 例如: 206 | 207 | ```java 208 | @DataWatcher("subscriberA") 209 | private TextView txtSubscribeMessage; 210 | ``` 211 | 212 | 发送更新内容通知: 213 | 214 | ```java 215 | Data.changeData("subscriberA", "Test Message"); 216 | ``` 217 | 218 | 随时更新会根据 View 组件的类型和数据类型进行匹配,例如当 View 为 TextView 内容为 int 时调用 textview.setText(resId) 去设置内容,此外还支持基本组件: 219 | 220 | | View | 数据类型 | 221 | | --------- | ------------------------------------------------------------ | 222 | | TextView | String、int(资源id)、CharSequence | 223 | | ImageView | Bitmap、int(资源id)、Drawable、Icon、Uri | 224 | | ListView | ListAdapter、List(仅支持执行对应 adapter 的数据更新操作 notifyDataSetChanged) | 225 | 226 | 此外,你还可以通过注解 `@DataWatchers` 设置订阅多个广播: 227 | 228 | ```java 229 | @DataWatchers({"subscriberA", "subscriberB"}) 230 | private TextView txtSubscribeMessage; 231 | ``` 232 | 233 | #### 根据 View 的 Tag 更新内容 234 | 235 | 你还可以使用以下代码根据 View 设置的 Tag 来修改内容,对所有界面同 Tag 全部生效。 236 | 237 | ```java 238 | Data.changeDataByTag("subscriberB", "Hello World"); 239 | ``` 240 | 241 | ### 对于任意类的 UI 内容更新 242 | 243 | 对于 Fragment 等无法统一获得管理的 UI 组件,可以使用: 244 | 245 | ```java 246 | Runner.bindAnyObject(this); 247 | ``` 248 | 249 | 对该组件完成绑定,对于 LifecycleOwner 的实现成员,例如 Fragment,会在销毁时自动解绑。 250 | 251 | 更新成员中的 View 内容: 252 | 253 | ```java 254 | Data.changeData("subscriberA", "Test Message"); 255 | ``` 256 | 257 | 要依据 Tag 更新成员内容,请额外为该类实现接口`RootViewInterface`: 258 | 259 | ```java 260 | public class SettingsFragment extends Fragment implements RootViewInterface { 261 | 262 | //rootView 指向您 UI 的根布局,必须为 ViewGroup 263 | ViewGroup rootView; 264 | 265 | @Override 266 | public View getRootView(){ 267 | return rootView; 268 | } 269 | 270 | @Override 271 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 272 | Runner.bindAnyObject(this); 273 | //create view... 274 | return rootView; 275 | } 276 | } 277 | ``` 278 | 279 | 即可完成绑定,使用以下方法更新 UI 内容: 280 | 281 | ```java 282 | Data.changeDataByTag("subscriberB", "Hello World"); 283 | ``` 284 | 285 | #### 自定义设置器 286 | 287 | 对于未预设的 View 或者你需要其他方式方法设置 View 的数据更新,可以使用设置自定义数据处理器: 288 | 289 | ```java 290 | Data.customDataSetter = new CustomDataSetter() { 291 | @Override 292 | public boolean setData(View view, Object data) { 293 | if (view instanceof CustomView) { 294 | //自定义设置数据类型 295 | view.setData((CustomData) data.getData()); 296 | //返回 true 表示让 Runner 不再继续判断处理 297 | return true; 298 | } 299 | return false; 300 | } 301 | }; 302 | ``` 303 | 304 | ## 自动化 ViewModel 305 | 306 | Runner 提供 View 和 Model 数据更新的双向绑定,即 Model 中的数据与界面上的 View 绑定,当数据发生变化时界面上的 View 内容自动更新,当界面中存在的可交互控件,例如 EditText、CheckBox,内容或状态发生变化时也将自动同步给 Model 中的内容。 307 | 308 | 要实现这些功能,首先请确保你的数据字段和 XML 中的 View 配置的 `android:tag` 属性保持一致,例如: 309 | 310 | ```xml 311 | 312 | 319 | 320 | 324 | 325 | 329 | 330 | 335 | 336 | 337 | ``` 338 | 339 | 则 Model 代码为: 340 | 341 | ```java 342 | public class LoginInfo { 343 | 344 | private String username; 345 | private String password; 346 | private boolean isRememberLogin; 347 | 348 | //省略对应的 get/set 方法... 349 | } 350 | ``` 351 | 352 | 此时,在 Activity 中初始化 LoginInfo 后,使用 `@BindModel` 注解标注 LoginInfo ,执行 `ViewModel.bindActivity(this);` 即可绑定界面元素: 353 | 354 | ```java 355 | public class Activity4 extends AppCompatActivity { 356 | 357 | @BindModel 358 | ListData listData; 359 | 360 | @Override 361 | protected void onCreate(Bundle savedInstanceState) { 362 | super.onCreate(savedInstanceState); 363 | setContentView(R.layout.activity_4); 364 | 365 | listData = new ListData(); 366 | ViewModel.bindActivity(this); 367 | } 368 | } 369 | ``` 370 | 371 | 要实现数据修改实时对界面更新,需要使 Model 继承 BaseModel 并在 set 方法后执行 `refreshUI();` 372 | 373 | ### 一点骚操作 374 | 375 | 对于简单的单布局 ListView 也可实现一键自动适配器,首先使 ListView 继承 `AutoCreateListViewInterface` 并回传子布局: 376 | 377 | ```java 378 | public class AutoCreateListView extends ListView implements AutoCreateListViewInterface { 379 | 380 | public AutoCreateListView(Context context) { 381 | super(context); 382 | } 383 | 384 | public AutoCreateListView(Context context, AttributeSet attrs) { 385 | super(context, attrs); 386 | } 387 | 388 | public AutoCreateListView(Context context, AttributeSet attrs, int defStyleAttr) { 389 | super(context, attrs, defStyleAttr); 390 | } 391 | 392 | @Override 393 | public int itemLayoutRes() { 394 | return R.layout.item_list_test; //回传子布局 395 | } 396 | } 397 | ``` 398 | 399 | 制作数据 Model: 400 | 401 | ```java 402 | public class ListData { 403 | 404 | List list; 405 | 406 | public ListData() { 407 | list = new ArrayList<>(); 408 | //list.add... 省略数据添加步骤 409 | } 410 | 411 | class Data{ 412 | String title; 413 | String tip; 414 | } 415 | } 416 | ``` 417 | 418 | 绑定到 Activity: 419 | 420 | ```java 421 | public class Activity4 extends AppCompatActivity { 422 | 423 | @BindModel 424 | ListData listData; 425 | 426 | @Override 427 | protected void onCreate(Bundle savedInstanceState) { 428 | super.onCreate(savedInstanceState); 429 | setContentView(R.layout.activity_4); 430 | 431 | listData = new ListData(); 432 | ViewModel.bindActivity(this); 433 | } 434 | } 435 | ``` 436 | 437 | ViewModel 会自动配置 Adapter,你无需关心任何事情。 438 | 439 | ## 开源协议 440 | 441 | ``` 442 | Copyright Kongzue Runner 443 | 444 | Licensed under the Apache License, Version 2.0 (the "License"); 445 | you may not use this file except in compliance with the License. 446 | You may obtain a copy of the License at 447 | 448 | http://www.apache.org/licenses/LICENSE-2.0 449 | 450 | Unless required by applicable law or agreed to in writing, software 451 | distributed under the License is distributed on an "AS IS" BASIS, 452 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 453 | See the License for the specific language governing permissions and 454 | limitations under the License. 455 | ``` -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | compileSdk 31 7 | 8 | defaultConfig { 9 | applicationId "com.kongzue.messagebusdemo" 10 | minSdk 21 11 | targetSdk 31 12 | versionCode BUILD_VERSION_INT as int 13 | versionName BUILD_VERSION 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | compileOptions { 25 | sourceCompatibility JavaVersion.VERSION_1_8 26 | targetCompatibility JavaVersion.VERSION_1_8 27 | } 28 | } 29 | 30 | def dialogx_version = "0.0.45.beta6" 31 | 32 | dependencies { 33 | 34 | implementation 'androidx.appcompat:appcompat:1.4.1' 35 | implementation 'com.google.android.material:material:1.5.0' 36 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 37 | implementation project(path: ':runner') 38 | testImplementation 'junit:junit:4.13.2' 39 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 40 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 41 | 42 | implementation "com.github.kongzue.DialogX:DialogX:${dialogx_version}" 43 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/kongzue/messagebusdemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.kongzue.messagebusdemo", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 18 | 23 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/Activity2.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.app.Activity; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.os.Bundle; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import com.kongzue.dialogx.dialogs.InputDialog; 15 | import com.kongzue.dialogx.dialogs.PopTip; 16 | import com.kongzue.dialogx.interfaces.OnInputDialogButtonClickListener; 17 | import com.kongzue.dialogx.util.InputInfo; 18 | import com.kongzue.messagebusdemo.util.User; 19 | import com.kongzue.runner.Data; 20 | import com.kongzue.runner.Event; 21 | import com.kongzue.runner.interfaces.ActivityRunnable; 22 | import com.kongzue.runner.interfaces.DataWatchers; 23 | import com.kongzue.dialogx.dialogs.MessageDialog; 24 | 25 | public class Activity2 extends AppCompatActivity { 26 | 27 | //不放心或者需要混淆的话,请使用 @SenderTarget("bitmapResult") 来标记接收 key 的成员 28 | Bitmap bitmapResult; 29 | 30 | @DataWatchers({"subscriberA", "subscriberB"}) 31 | private TextView txtSubscribeMessage; 32 | private ImageView imgSenderPicture; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_2); 38 | 39 | txtSubscribeMessage = findViewById(R.id.txt_subscribe_message); 40 | 41 | //如果有图像,直接显示 bitmapResult 42 | imgSenderPicture = findViewById(R.id.img_sender_picture); 43 | if (bitmapResult != null) { 44 | imgSenderPicture.setImageBitmap(bitmapResult); 45 | } 46 | 47 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 48 | } 49 | 50 | /** 51 | * 在 MainActivity 执行一个事件 52 | * 53 | * @param view 按钮 54 | */ 55 | public void runOnMainActivity(View view) { 56 | Event.runOnActivity("MainActivity", new ActivityRunnable() { 57 | @Override 58 | public void run(Activity activity) { 59 | MessageDialog.build() 60 | .setTitle("提示") 61 | .setMessage("这个事件来自 Activity2 创建。\n请注意此事件是立即在 MainActivity 中执行的,具体详情请查看 Logcat 日志顺序。") 62 | .setOkButton("OK") 63 | .show(activity); 64 | } 65 | }); 66 | PopTip.show("已执行\n请返回 MainActivity 查看!"); 67 | } 68 | 69 | /** 70 | * 在回到 MainActivity 后执行一个事件 71 | * 72 | * @param view 按钮 73 | */ 74 | public void runOnMainResume(View view) { 75 | Event.runOnActivity("MainActivity", new ActivityRunnable() { 76 | @Override 77 | public void run(Activity activity) { 78 | MessageDialog.build() 79 | .setTitle("提示") 80 | .setMessage("这个事件来自 Activity2 创建。\n请注意此事件是在回到 MainActivity 后执行的,具体详情请查看 Logcat 日志顺序。") 81 | .setOkButton("OK") 82 | .show(activity); 83 | } 84 | }); 85 | PopTip.show("已准备就绪\n请返回 MainActivity 查看!"); 86 | } 87 | 88 | /** 89 | * 为所有订阅者A推送一个消息 90 | * 91 | * @param view 按钮 92 | */ 93 | public void sendTextDataA(View view) { 94 | InputDialog.show("为所有订阅者A推送一个消息", "请输入内容,会使 MainActivity 和 Activity2 两个界面的订阅者组件全部变更内容", "OK") 95 | .setInputText("Test Message") 96 | .setInputInfo(new InputInfo().setSelectAllText(true)) 97 | .setOkButton(new OnInputDialogButtonClickListener() { 98 | @Override 99 | public boolean onClick(InputDialog baseDialog, View v, String inputStr) { 100 | Data.changeData("subscriberA", inputStr); 101 | PopTip.show("已完成!\n请观察本界面和上一层界面的订阅消息内容变化"); 102 | return false; 103 | } 104 | }); 105 | } 106 | 107 | /** 108 | * 为所有订阅者B推送一个消息 109 | * 110 | * @param view 按钮 111 | */ 112 | public void sendTextDataB(View view) { 113 | InputDialog.show("为所有订阅者B推送一个消息", "请输入内容,会使 MainActivity 和 Activity2 两个界面的订阅者组件全部变更内容", "OK") 114 | .setInputText("Hello World!") 115 | .setInputInfo(new InputInfo().setSelectAllText(true)) 116 | .setOkButton(new OnInputDialogButtonClickListener() { 117 | @Override 118 | public boolean onClick(InputDialog baseDialog, View v, String inputStr) { 119 | Data.changeData("subscriberB", inputStr); 120 | Data.changeDataByTag("subscriberB", inputStr); 121 | PopTip.show("已完成!\n请观察本界面和上一层界面的订阅消息内容变化"); 122 | return false; 123 | } 124 | }); 125 | } 126 | 127 | /** 128 | * 为 User 设置一个 age 129 | * 130 | * @param view 按钮 131 | */ 132 | public void setUserAge(View view) { 133 | Data.sendToAnyObject(User.class, "age", 35); 134 | PopTip.show("操作已完成"); 135 | } 136 | 137 | /** 138 | * 为 User 设置一个头像 139 | * 140 | * @param view 按钮 141 | */ 142 | public void setUserAvatar(View view) { 143 | Data.sendToAnyObject(User.class, "avatar", BitmapFactory.decodeResource(getResources(), R.mipmap.img_user)); 144 | PopTip.show("操作已完成"); 145 | } 146 | 147 | @Override 148 | public boolean onOptionsItemSelected(MenuItem item) { 149 | switch (item.getItemId()) { 150 | case android.R.id.home: 151 | onBackPressed(); 152 | default: 153 | return super.onOptionsItemSelected(item); 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/Activity3.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.MenuItem; 8 | import android.view.View; 9 | 10 | import com.kongzue.messagebusdemo.util.LoginInfo; 11 | import com.kongzue.runner.Data; 12 | import com.kongzue.runner.ViewModel; 13 | import com.kongzue.runner.interfaces.BindModel; 14 | 15 | public class Activity3 extends AppCompatActivity { 16 | 17 | @BindModel 18 | LoginInfo loginInfo; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_3); 24 | 25 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 26 | 27 | loginInfo = new LoginInfo("zhangsan", "123456").setIsRememberLogin(true); 28 | ViewModel.bindActivity(this); 29 | } 30 | 31 | public void btnShowInputInfo(View view) { 32 | Data.changeDataByTag("txtLog", loginInfo.toString()); 33 | } 34 | 35 | public void btnChangeLoginInfo(View view) { 36 | loginInfo.setUsername("李四") 37 | .setPassword("987654") 38 | .setIsRememberLogin(false); 39 | } 40 | 41 | public void showListTest(View view) { 42 | startActivity(new Intent(this, Activity4.class)); 43 | } 44 | 45 | @Override 46 | public boolean onOptionsItemSelected(MenuItem item) { 47 | switch (item.getItemId()) { 48 | case android.R.id.home: 49 | onBackPressed(); 50 | default: 51 | return super.onOptionsItemSelected(item); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/Activity4.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.os.Bundle; 6 | import android.view.MenuItem; 7 | 8 | import com.kongzue.messagebusdemo.util.ListData; 9 | import com.kongzue.messagebusdemo.util.LoginInfo; 10 | import com.kongzue.runner.ViewModel; 11 | import com.kongzue.runner.interfaces.BindModel; 12 | 13 | public class Activity4 extends AppCompatActivity { 14 | 15 | @BindModel 16 | ListData listData; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_4); 22 | 23 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 24 | 25 | listData = new ListData(); 26 | ViewModel.bindActivity(this); 27 | } 28 | 29 | @Override 30 | public boolean onOptionsItemSelected(MenuItem item) { 31 | switch (item.getItemId()) { 32 | case android.R.id.home: 33 | onBackPressed(); 34 | default: 35 | return super.onOptionsItemSelected(item); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/App.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.kongzue.runner.Runner; 7 | import com.kongzue.dialogx.DialogX; 8 | 9 | /** 10 | * @author: Kongzue 11 | * @github: https://github.com/kongzue/ 12 | * @homepage: http://kongzue.com/ 13 | * @mail: myzcxhh@live.cn 14 | * @createTime: 2022/5/4 13:48 15 | */ 16 | public class App extends Application { 17 | @Override 18 | public void onCreate() { 19 | super.onCreate(); 20 | DialogX.init(this); 21 | Runner.init(this); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Intent; 6 | import android.graphics.BitmapFactory; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | import com.kongzue.dialogx.dialogs.MessageDialog; 12 | import com.kongzue.messagebusdemo.util.User; 13 | import com.kongzue.runner.Data; 14 | import com.kongzue.runner.Event; 15 | import com.kongzue.runner.interfaces.ActivityRunnable; 16 | import com.kongzue.runner.interfaces.DataWatcher; 17 | import com.kongzue.dialogx.dialogs.PopTip; 18 | 19 | public class MainActivity extends AppCompatActivity { 20 | 21 | @DataWatcher("subscriberA") 22 | private TextView txtSubscribeMessage; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_main); 28 | 29 | txtSubscribeMessage = findViewById(R.id.txt_subscribe_message); 30 | } 31 | 32 | /** 33 | * 设置一个事件,等待 Activity2 启动后执行 34 | * 35 | * @param view 按钮 36 | */ 37 | public void waitRunOnActivity2(View view) { 38 | Event.runOnActivity(Activity2.class, new ActivityRunnable() { 39 | @Override 40 | public void run(Activity2 activity) { 41 | MessageDialog.build() 42 | .setTitle("提示") 43 | .setMessage("这个执行事件来自于 MainActivity 设置。") 44 | .setOkButton("OK") 45 | .show(activity); 46 | } 47 | }); 48 | PopTip.show("已准备就绪\n请启动 Activity2 查看!"); 49 | } 50 | 51 | /** 52 | * 启动 Activity2 53 | * 54 | * @param view 按钮 55 | */ 56 | public void runActivity2(View view) { 57 | startActivity(new Intent(this, Activity2.class)); 58 | } 59 | 60 | /** 61 | * 传递一个 Bitmap 到 Activity2 62 | * 63 | * @param view 按钮 64 | */ 65 | public void sendToActivity2(View view) { 66 | Data.sendToActivity("Activity2", "bitmapResult", BitmapFactory.decodeResource(getResources(), R.mipmap.img_bug)); 67 | PopTip.show("已准备就绪\n请进入 Activity2 查看!"); 68 | } 69 | 70 | User user; 71 | 72 | /** 73 | * 创建一个存储类 User 74 | * 75 | * @param view 按钮 76 | */ 77 | public void createUser(View view) { 78 | user = new User(); 79 | } 80 | 81 | /** 82 | * 展示 User 的信息 83 | * 84 | * @param view 按钮 85 | */ 86 | public void showUser(View view) { 87 | PopTip.show(user == null ? "[null]" : user.toString()); 88 | } 89 | 90 | /** 91 | * 置 User 为空 92 | * 93 | * @param view 按钮 94 | */ 95 | public void destroyUser(View view) { 96 | user = null; 97 | } 98 | 99 | /** 100 | * 为 User 设置一个 name 101 | * 102 | * @param view 按钮 103 | */ 104 | public void setUserName(View view) { 105 | Data.sendToAnyObject(User.class, "name", "ZhangSan"); 106 | } 107 | 108 | /** 109 | * MVVM 测试 110 | * @param view 按钮 111 | */ 112 | public void mvvmTest(View view) { 113 | startActivity(new Intent(this, Activity3.class)); 114 | } 115 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/util/ListData.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author: Kongzue 8 | * @github: https://github.com/kongzue/ 9 | * @homepage: http://kongzue.com/ 10 | * @mail: myzcxhh@live.cn 11 | * @createTime: 2022/10/21 18:24 12 | */ 13 | public class ListData { 14 | 15 | List list; 16 | 17 | public ListData() { 18 | list = new ArrayList<>(); 19 | list.add(new Data("zhangsan","2022")); 20 | list.add(new Data("lisi","2021")); 21 | list.add(new Data("wangwu","2020")); 22 | list.add(new Data("zhaoliu","2019")); 23 | list.add(new Data("sunqi","2018")); 24 | list.add(new Data("sunqi","2017")); 25 | list.add(new Data("zhouba","2016")); 26 | list.add(new Data("wujiu","2015")); 27 | list.add(new Data("zhenshi","2014")); 28 | list.add(new Data("kongzue","create")); 29 | list.add(new Data("version","1.0.0")); 30 | list.add(new Data("github","kongzue/Runner")); 31 | list.add(new Data("license","Apache License 2.0")); 32 | list.add(new Data("again","———————————————————————————————")); 33 | list.add(new Data("zhangsan","2022")); 34 | list.add(new Data("lisi","2021")); 35 | list.add(new Data("wangwu","2020")); 36 | list.add(new Data("zhaoliu","2019")); 37 | list.add(new Data("sunqi","2018")); 38 | list.add(new Data("sunqi","2017")); 39 | list.add(new Data("zhouba","2016")); 40 | list.add(new Data("wujiu","2015")); 41 | list.add(new Data("zhenshi","2014")); 42 | list.add(new Data("kongzue","create")); 43 | list.add(new Data("version","1.0.0")); 44 | list.add(new Data("github","kongzue/Runner")); 45 | list.add(new Data("license","Apache License 2.0")); 46 | } 47 | 48 | class Data{ 49 | public Data(String title, String tip) { 50 | this.title = title; 51 | this.tip = tip; 52 | } 53 | String title; 54 | String tip; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/util/LoginInfo.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo.util; 2 | 3 | import com.kongzue.runner.interfaces.BaseModel; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author: Kongzue 10 | * @github: https://github.com/kongzue/ 11 | * @homepage: http://kongzue.com/ 12 | * @mail: myzcxhh@live.cn 13 | * @createTime: 2022/10/21 10:39 14 | */ 15 | public class LoginInfo extends BaseModel { 16 | 17 | private String username; 18 | private String password; 19 | private boolean isRememberLogin; 20 | 21 | public LoginInfo(String username, String password) { 22 | this.username = username; 23 | this.password = password; 24 | } 25 | 26 | public String getUsername() { 27 | return username; 28 | } 29 | 30 | public LoginInfo setUsername(String username) { 31 | this.username = username; 32 | refreshUI(); 33 | return this; 34 | } 35 | 36 | public boolean isRememberLogin() { 37 | return isRememberLogin; 38 | } 39 | 40 | public LoginInfo setIsRememberLogin(boolean rememberLogin) { 41 | isRememberLogin = rememberLogin; 42 | refreshUI(); 43 | return this; 44 | } 45 | 46 | public String getPassword() { 47 | return password; 48 | } 49 | 50 | public LoginInfo setPassword(String password) { 51 | this.password = password; 52 | refreshUI(); 53 | return this; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "LoginInfo{" + 59 | "username='" + username + '\'' + 60 | ", password='" + password + '\'' + 61 | ", isRememberLogin=" + isRememberLogin + 62 | '}'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/util/User.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo.util; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.kongzue.runner.Runner; 6 | import com.kongzue.runner.interfaces.SenderTarget; 7 | 8 | /** 9 | * @author: Kongzue 10 | * @github: https://github.com/kongzue/ 11 | * @homepage: http://kongzue.com/ 12 | * @mail: myzcxhh@live.cn 13 | * @createTime: 2022/5/8 11:13 14 | */ 15 | public class User { 16 | 17 | public User() { 18 | Runner.bindAnyObject(this); 19 | } 20 | 21 | private String name; 22 | 23 | private int age; 24 | 25 | @SenderTarget("avatar") 26 | private Bitmap bitmap; 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public User setName(String name) { 33 | this.name = name; 34 | return this; 35 | } 36 | 37 | public Bitmap getAvatar() { 38 | return bitmap; 39 | } 40 | 41 | public User setAvatar(Bitmap avatar) { 42 | this.bitmap = avatar; 43 | return this; 44 | } 45 | 46 | public int getAge() { 47 | return age; 48 | } 49 | 50 | public User setAge(int age) { 51 | this.age = age; 52 | return this; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "User{\n" + 58 | "name='" + name + '\'' + 59 | ", \nage=" + age + 60 | ", \navatar(byteCount)=" + (bitmap == null ? 0 : bitmap.getByteCount()) + 61 | "\n}"; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/kongzue/messagebusdemo/views/AutoCreateListView.java: -------------------------------------------------------------------------------- 1 | package com.kongzue.messagebusdemo.views; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ListView; 6 | 7 | import com.kongzue.messagebusdemo.R; 8 | import com.kongzue.runner.interfaces.AutoCreateListViewInterface; 9 | 10 | /** 11 | * @author: Kongzue 12 | * @github: https://github.com/kongzue/ 13 | * @homepage: http://kongzue.com/ 14 | * @mail: myzcxhh@live.cn 15 | * @createTime: 2022/10/21 18:03 16 | */ 17 | public class AutoCreateListView extends ListView implements AutoCreateListViewInterface { 18 | 19 | public AutoCreateListView(Context context) { 20 | super(context); 21 | } 22 | 23 | public AutoCreateListView(Context context, AttributeSet attrs) { 24 | super(context, attrs); 25 | } 26 | 27 | public AutoCreateListView(Context context, AttributeSet attrs, int defStyleAttr) { 28 | super(context, attrs, defStyleAttr); 29 | } 30 | 31 | @Override 32 | public int itemLayoutRes() { 33 | return R.layout.item_list_test; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 25 | 26 |