├── .gitignore ├── README.MD ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── abc.html │ ├── java │ └── com │ │ └── example │ │ └── siyehua │ │ └── myanotation │ │ ├── ExecutorServiceManager.java │ │ ├── MainActivity.java │ │ ├── custom │ │ ├── Main2Activity.java │ │ ├── MyLifeData.java │ │ ├── MyLifecycle.java │ │ └── MyObserver.java │ │ ├── lifecycle │ │ ├── Main4Activity.java │ │ ├── User.java │ │ └── UserViewModel.java │ │ └── mvp │ │ ├── IPresenter.java │ │ ├── IView.java │ │ ├── Main3Activity.java │ │ ├── Person.java │ │ └── PersonPresenter.java │ └── res │ ├── layout │ ├── activity_main.xml │ ├── activity_main2.xml │ ├── activity_main3.xml │ └── activity_main4.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── Android_Architecture_Components.png ├── Architecture_Components.png ├── Lifecly_status.png ├── ViewModel_status.png ├── arch-hero-mobile.png ├── arch-hero.png ├── class.png ├── desktoplifecycles-2x.png └── desktoproom-2x.png ├── processorlib ├── .gitignore ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── example │ │ ├── AutoParcelProcessor.java │ │ ├── Count.java │ │ ├── CountRunable.java │ │ ├── MyClass.java │ │ ├── NotifyRunnable.java │ │ ├── PrintMethodName.java │ │ └── WaitRunnable.java │ └── resources │ └── META-INF │ └── services │ └── javax.annotation.processing.Processor └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | .idea -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # 浅谈 Android Architecture Components 使用和原理 2 | ![ Android Architecture Components](./img/arch-hero-mobile.png) 3 | 4 | ## 阅读 5 | 本文适合对 Android 开发,以及架构有一定了解的人阅读,实践性较强,最好结合项目运行了解. 6 | 7 | 本文阅读时长 20 ~ 30 分钟. 8 | 9 | ## 定义 10 | ``` 11 | A new collection of libraries that help you design robust, 12 | testable, and maintainable apps. 13 | Start with classes for managing your UI component lifecycle and 14 | handling data persistence. 15 | ``` 16 | Android Architecture Components,简称 AAC, 17 | 意思就是一个处理 UI 的生命周期 与数据的持久化更加牛逼的架构 18 | 19 | ## 其他架构 20 | 我们比较熟悉的的架构有: MVC,MVP, 以及 MVVM. 21 | 关于这些架构的介绍网上有许多文章,这里不展开说明,对这些不是很熟悉的同学可以参考 22 | [链接](http://www.jianshu.com/p/3010760035e0) 23 | 24 | 这些结构有各自的优缺点, 以现在比较流行的 MVP 为例, 它将不是关于界面的操作分发到 Presenter 中操作,再将结果通知给 View 接口的实现(通常是 Activity/Fragment). 25 | 26 | ### 存在问题 27 | MVP 架构,当异步获取结果时,可能 UI 已经销毁,而 Presenter 还持有 UI 的引用,从而导致内存泄漏 28 | 29 | ```java 30 | @Override 31 | public void getName() { 32 | ExecutorServiceManager.getInstance().execute(new Runnable() { 33 | @Override 34 | public void run() { 35 | try { 36 | TimeUnit.SECONDS.sleep(5); 37 | } catch (InterruptedException e) { 38 | e.printStackTrace(); 39 | } 40 | 41 | if (iView != null) { 42 | iView.setName("siyehua"); 43 | } 44 | } 45 | }); 46 | } 47 | ``` 48 | 49 | 以上代码, iView 的具体实现是 Activity, 当 Activity 已经执行了 onDestroy() 方法, 此时 Runnable 还在获取数据, 就会导致内存泄漏. 50 | 51 | 通常的做法是在给 Presenter 定义一个方法,当 Activity 销毁的时候同时移除对 iView 的引用,完整代码如下: 52 | 53 | ```java 54 | public class PersonPresenter implements IPresenter { 55 | private IView iView; 56 | 57 | public PersonPresenter(IView iView) { 58 | this.iView = iView; 59 | } 60 | 61 | @Override 62 | public void getName() { 63 | ExecutorServiceManager.getInstance().execute(new Runnable() { 64 | @Override 65 | public void run() { 66 | try { 67 | TimeUnit.SECONDS.sleep(5); 68 | } catch (InterruptedException e) { 69 | e.printStackTrace(); 70 | } 71 | 72 | if (iView != null) { 73 | iView.setName("siyehua"); 74 | } 75 | } 76 | }); 77 | } 78 | 79 | public void removeView() { 80 | iView = null; 81 | } 82 | } 83 | 84 | ``` 85 | 86 | 在 Activity 中,代码调用如下: 87 | 88 | ```java 89 | @Override 90 | protected void onDestroy() { 91 | //不移除 View 有可能导致内存泄漏 92 | personPresenter.removeView(); 93 | super.onDestroy(); 94 | } 95 | ``` 96 | 97 | 至此,即可解决 MVP 内存泄漏的问题,详细代码可看项目中的 [mvp](./app/src/main/java/com/example/siyehua/myanotation/mvp) 目录代码. 98 | 99 | 这么做不够优雅,需要手动管理 Presenter, 当然可以定义基类写入到 BaseActivity 中. 100 | 101 | 除了有可能引发内存泄漏的风险, 数据持久化也是一个经常困扰我们的问题.通常在屏幕旋转后, UI 的对象都会被销毁重建,这将导致原来的对象数据不得不重新创建和获取,浪费资源的同时也会影响用户的体验. 102 | 103 | 通常的解决方法是,通过 SavedInstanceState 来存取数据, 但 SavedInstanceState 存储的数据一般比较小,且数据对象还是必须重新构建. 104 | 105 | ### 使用 Android Architecture Components 106 | 107 | ![ Android Architecture Components](./img/arch-hero.png) 108 | 109 | 上述两个问题可以通过使用 AAC 架构解决. 110 | 111 | ## 介绍 112 | AAC 的核心是: Lifecycle, LiveData, ViewModel 以及 Room, 通过它可以非常优雅的让数据与界面交互,并做一些持久化的东西,高度解耦,自动管理生命周期, 而且不用担心内存泄漏的问题. 113 | 114 | ![Android Architecture Components](./img/Architecture_Components.png) 115 | 116 | 下面就一一介绍它们 117 | 118 | ### Lifecycle 119 | ![ Android Architecture Components](./img/desktoplifecycles-2x.png) 120 | 121 | Lifecycle 主要用 State 和 Event 这两个枚举类来表达 Activity/Fragment 的生命周期和状态. LifecycleRegistry 是它的主要实现类,用于分发生命周期的变化. 122 | 123 | State 和 Event 之间的关系用下图表示: 124 | 125 | ![ Android Architecture Components](./img/Lifecly_status.png) 126 | 127 | ### LiveData 128 | LiveData 主要用于接受/更新数据, Lifecycle 的具体实现会将生命周期的变化传给 LiveData,LiveData 通过状态判断要不要刷新数据,假设要刷新数据,则通过 LifecycleObserver 将得到数据的变分发给对应的监听者(Activity/Fragment). 129 | 130 | ### ViewModel 131 | 用于管理数据,它持有 LiveData. 处理数据持久化,存取等具体逻辑, 相当于 MVP 中的 Presenter. 132 | 133 | ![ Android Architecture Components](./img/ViewModel_status.png) 134 | 135 | ### Room 136 | 通过注解将数据持久化(数据库管理) 137 | 138 | ![ Android Architecture Components](./img/desktoproom-2x.png) 139 | 140 | 141 | ## 简单使用 142 | ### 配置 143 | 根目录gradle文件中添加Google Maven Repository 144 | 145 | ``` 146 | allprojects { 147 | repositories { 148 | jcenter() 149 | maven { url 'https://maven.google.com' } 150 | } 151 | } 152 | ``` 153 | 154 | 155 | 如使用Lifecycle, LiveData、ViewModel,添加如下依赖。 156 | 157 | ``` 158 | compile "android.arch.lifecycle:runtime:1.0.0-alpha1" 159 | compile "android.arch.lifecycle:extensions:1.0.0-alpha1" 160 | annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha1" 161 | ``` 162 | 163 | 如使用Room功能,添加如下依赖。 164 | 165 | ``` 166 | compile "android.arch.persistence.room:runtime:1.0.0-alpha1" 167 | annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1" 168 | 169 | // For testing Room migrations, add: 170 | testCompile "android.arch.persistence.room:testing:1.0.0-alpha1" 171 | 172 | // For Room RxJava support, add: 173 | compile "android.arch.persistence.room:rxjava2:1.0.0-alpha1" 174 | 175 | ``` 176 | 177 | ### 代码 178 | Activity: 179 | 180 | ```java 181 | public class Main4Activity extends LifecycleActivity { 182 | 183 | private Button btButton; 184 | 185 | @Override 186 | protected void onCreate(Bundle savedInstanceState) { 187 | super.onCreate(savedInstanceState); 188 | setContentView(R.layout.activity_main); 189 | btButton = (Button) findViewById(R.id.bt_click); 190 | 191 | UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class); 192 | userViewModel.getUserLiveData().observe(this, new Observer() { 193 | @Override 194 | public void onChanged(@Nullable User user) { 195 | if (user != null) { 196 | btButton.setText(user.getName()); 197 | } 198 | } 199 | }); 200 | } 201 | 202 | } 203 | ``` 204 | 205 | 其中 UserViewModel 的实现: 206 | 207 | ```java 208 | public class UserViewModel extends ViewModel { 209 | private String id = ""; 210 | private LiveData userLiveData; 211 | 212 | public String getId() { 213 | return id; 214 | } 215 | 216 | public void setId(String id) { 217 | this.id = id; 218 | } 219 | 220 | public LiveData getUserLiveData() { 221 | final MutableLiveData data = new MutableLiveData<>(); 222 | ExecutorServiceManager.getInstance().execute(new Runnable() { 223 | @Override 224 | public void run() { 225 | try { 226 | TimeUnit.SECONDS.sleep(5); 227 | } catch (InterruptedException e) { 228 | e.printStackTrace(); 229 | } 230 | User user = new User(); 231 | user.setName("siyehua"); 232 | user.setPassword("123456"); 233 | Log.e("siyehua", "child thread..."); 234 | data.postValue(user); 235 | 236 | } 237 | }); 238 | 239 | return userLiveData = data; 240 | } 241 | 242 | public void setUserLiveData(LiveData userLiveData) { 243 | this.userLiveData = userLiveData; 244 | } 245 | } 246 | ``` 247 | 248 | 249 | 这样就完成了, LiveData 在 "data.postValue(user)" 后,获取到了 user 这个数据,分发到它的监听器,因为 Activity 监听了,所以 button 的 text 就自动改变了. 250 | 251 | 当 Activity 销毁了(本文所有的销毁,如果没有特别指明,指的都是 Activity 正常关闭,而不是其他因素导致的销毁重建),会自动将对应的 ViewModel 移除,这样就不会导致内存泄漏.同时,当 Activity 处于不可见的状态时,也不会去修改 UI. 252 | 253 | 关于代码的详细请看项目中的 [lifecycle](./app/src/main/java/com/example/siyehua/myanotation/lifecycle) 目录下的实现. 254 | 255 | ## 原理 256 | 讲原理之前先看一下这个架构的对应的 UML 类图,可以更好的帮助我们理解架构是怎样工作的 257 | 258 | ![ Android Architecture Components](./img/class.png) 259 | 260 | 上文例子中,Activity 继承的是一个 LifecycleActivity,实际上它是 LifecycleOwner 的实现,这个接口的主要作用是返回一个 Lifecycle, 这个类前面介绍过了,它主要是作用是用来表达 UI 的 状态和过程,而 Lifecycle 的主要实现是 LifecycleRegistry. 261 | 262 | ```java 263 | public class Main2Activity extends AppCompatActivity implements LifecycleRegistryOwner { 264 | 265 | //LifecycleFragment 与 LifecycleActivity 实际上的实现 266 | final LifecycleRegistry mRegistry = new LifecycleRegistry(new LifecycleOwner() { 267 | @Override 268 | public Lifecycle getLifecycle() { 269 | return getLifecycle(); 270 | } 271 | }); 272 | 273 | @Override 274 | public LifecycleRegistry getLifecycle() { 275 | return mRegistry; 276 | } 277 | } 278 | ``` 279 | 280 | Activity 除了为 Lifecycle 提供生命周期的变化事件之外,它还持有 ViewModel 的引用, ViewModel 这个类在前面介绍过,主要是用来与 Activity 交互,处理数据,而它处理数据主要是通过 LiveData 来实现的. 281 | 282 | LiveData 这个类根据之前的介绍,它主要是分发生命周期的事件,在上述代码,具体的实现是 MutableLiveData. 它持有 LifecycleRegistry(可监听/获取 UI 生命周期的状态), Model(具体的对象类 User), 以及 LifecycleObserver(观察者). 283 | 284 | ### 事件传递 285 | ![ Android Architecture Components](./img/Android_Architecture_Components.png) 286 | 287 | 架构的事件分两种,一种是 Activity/Fragment 的生命周期变化事件,还有一种是数据的变化事件. 288 | 289 | ### 生命周期变化分发过程 290 | 架构首先通过 APT 注解,在 AndroidManifest.xml 注册一个 LifecycleRuntimeTrojanProvider, 它是一个 ContentProvider, 用来管理初始化当前 Application 的监听进程. 291 | 292 | 可通过反编译 APK 包查看 AndroidManifest.xml 文件: 293 | 294 | ```xml 295 | 301 | 302 | ``` 303 | 304 | 305 | 306 | 当创建 Activity 的时候, Application 会调用 dispatchActivityCreated() 方法: 307 | 308 | ```java 309 | void dispatchActivityCreated(Activity activity, Bundle savedInstanceState) { 310 | Object[] callbacks = collectActivityLifecycleCallbacks(); 311 | if (callbacks != null) { 312 | for (int i=0; i生命周期变化分发这个过程 327 | 328 | ### 数据变化事件分发过程 329 | ![ Android Architecture Components](./img/Android_Architecture_Components.png) 330 | 331 | 还是刚刚那个图,数据的变化事件更加简单, Model 得到了数据,通过 LiveData 的 postData() 方法设置数据, LiveData 的处理,之前已经说了, LiveData 根据生命周期的状态来决定要不要刷新数据,假设要刷新,就通知观察者刷新即可. 332 | 333 | ### ViewModel 的持久化 334 | ![ Android Architecture Components](./img/ViewModel_status.png) 335 | 336 | ViewModel 之所以能在 Activity/Fragment 重建的时候依旧能保持,主要是通过 ViewModelProviders 创建ViewModel,而不是 new 一个 ViewModel. 337 | 338 | 之前的代码: 339 | 340 | ```java 341 | UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class); 342 | ``` 343 | ViewModelProviders 通过 ViewModelStore 来管理 ViewModel, 344 | ViewModelStore 的一个 map 容器存储 ViewModel,通过 Activity 作为 key 区分,假设是同一个 Activity(哪怕不是同一个对象),就返回同一个 ViewModel, 直到 Activity 销毁则移除. 345 | 346 | 原理:通过给 Activity 添加一个,HolderFragment ,设置 setRetainInstance(true);(屏幕旋转时,保持数据的状态) 347 | 348 | 349 | ## 数据持久化之数据库 Room 350 | 数据的持久化是通过 Room 这个类库的注解来实现创建,以及增删改查,比较简单,详细可以看[官方文档](https://developer.android.com/topic/libraries/architecture/room.html) 351 | 352 | ```java 353 | @Entity 354 | public class User { 355 | @PrimaryKey 356 | private int uid; 357 | 358 | @ColumnInfo(name = "first_name") 359 | private String firstName; 360 | 361 | @ColumnInfo(name = "last_name") 362 | private String lastName; 363 | 364 | // Getters and setters are ignored for brevity, 365 | // but they're required for Room to work. 366 | } 367 | ``` 368 | 369 | 370 | ## AAC 的特点 371 | * 数据驱动型编程:变化的永远是数据,界面无需更改.
我们通常的编程类型是:业务驱动型,即通过编写业务逻辑代码来实现,代码通常放在 Activity, 使用 MVP 之后放在 Presenter.

数据驱动型与业务驱动型最大的不同是:数据驱动型认为通常的变化大多是在数据层面上的变化,且它将数据的变化放在了数据层,
将 UI 372 | 的变化放在的 UI, 分离了变化,遵循"单一职责,一个类只有一个变化"的设计原则.
而业务驱动型的编程是根据业务的变化,修改获取到的数据,即获取到的数据还需要再根据业务需求处理一遍. 373 | 374 | * 感知生命周期,防止内存泄漏
原理与 Glide 一样,通过给 Activity 添加一个碎片来监听生命周期的变化 375 | 376 | * 高度解耦
数据,界面高度分离, library 分离,可仅使用其中一个功能,例如不使用数据库功能 377 | 378 | * 数据持久化
数据 ViewModel 不与 UI 的生命周期挂钩,不会因为界面的重建而销毁 379 | 380 | ## 参考链接 381 | [Android Architecture Components](https://developer.android.com/topic/libraries/architecture/index.html) 382 | 383 | 384 | 385 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.example.siyehua.myanotation" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | compileOptions { 20 | sourceCompatibility JavaVersion.VERSION_1_7 21 | targetCompatibility JavaVersion.VERSION_1_7 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(include: ['*.jar'], dir: 'libs') 27 | // For Lifecycles, LiveData, and ViewModel, add: 28 | // For Room, add: 29 | // For testing Room migrations, add: 30 | // For Room RxJava support, add: 31 | compile 'com.android.support:appcompat-v7:25.3.1' 32 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 33 | compile 'android.arch.lifecycle:runtime:1.0.0-alpha5' 34 | compile 'android.arch.lifecycle:extensions:1.0.0-alpha5' 35 | compile 'android.arch.persistence.room:runtime:1.0.0-alpha5' 36 | compile 'android.arch.persistence.room:rxjava2:1.0.0-alpha5' 37 | testCompile 'android.arch.persistence.room:testing:1.0.0-alpha5' 38 | annotationProcessor 'android.arch.lifecycle:compiler:1.0.0-alpha5' 39 | annotationProcessor 'android.arch.persistence.room:compiler:1.0.0-alpha5' 40 | } 41 | -------------------------------------------------------------------------------- /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/siyehua/AndroidStudio/android-sdk-macosx/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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/assets/abc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test 6 | 7 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/ExecutorServiceManager.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.ThreadFactory; 8 | 9 | /** 10 | * ExecuorService 管理器
11 | * Created by siyehua on 2017/8/8. 12 | */ 13 | public class ExecutorServiceManager { 14 | private static ExecutorServiceManager manager = new ExecutorServiceManager(); 15 | 16 | public static ExecutorServiceManager getInstance() { 17 | return manager; 18 | } 19 | 20 | private ExecutorService executorService; 21 | 22 | private ExecutorServiceManager() { 23 | executorService = Executors.newCachedThreadPool(new ThreadFactory() { 24 | @Override 25 | public Thread newThread(@NonNull Runnable r) { 26 | Thread thread = new Thread(r); 27 | thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 28 | @Override 29 | public void uncaughtException(Thread t, Throwable e) { 30 | e.printStackTrace(); 31 | } 32 | }); 33 | return thread; 34 | } 35 | }); 36 | } 37 | 38 | 39 | public void execute(Runnable runnable) { 40 | executorService.execute(runnable); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | 8 | import com.example.siyehua.myanotation.mvp.Main3Activity; 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | } 18 | 19 | 20 | public void click(View view) { 21 | //mvp 22 | startActivity(new Intent(this, Main3Activity.class)); 23 | 24 | //use 25 | // startActivity(new Intent(this, Main2Activity.class)); 26 | 27 | //原理剖析 28 | // startActivity(new Intent(this, Main2Activity.class)); 29 | 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/custom/Main2Activity.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.custom; 2 | 3 | import android.arch.lifecycle.Lifecycle; 4 | import android.arch.lifecycle.LifecycleOwner; 5 | import android.arch.lifecycle.LifecycleRegistry; 6 | import android.arch.lifecycle.LifecycleRegistryOwner; 7 | import android.arch.lifecycle.Observer; 8 | import android.arch.lifecycle.ViewModelProvider; 9 | import android.arch.lifecycle.ViewModelProviders; 10 | import android.content.Intent; 11 | import android.os.Bundle; 12 | import android.support.annotation.Nullable; 13 | import android.support.v7.app.AppCompatActivity; 14 | import android.util.Log; 15 | import android.view.View; 16 | import android.widget.Button; 17 | 18 | import com.example.siyehua.myanotation.R; 19 | import com.example.siyehua.myanotation.lifecycle.User; 20 | import com.example.siyehua.myanotation.lifecycle.UserViewModel; 21 | 22 | /** 23 | * 本质 24 | */ 25 | public class Main2Activity extends AppCompatActivity implements LifecycleRegistryOwner { 26 | 27 | //LifecycleFragment 与 LifecycleActivity 实际上的实现 28 | final LifecycleRegistry mRegistry = new LifecycleRegistry(new LifecycleOwner() { 29 | @Override 30 | public Lifecycle getLifecycle() { 31 | return Main2Activity.this.getLifecycle(); 32 | } 33 | }); 34 | 35 | @Override 36 | public LifecycleRegistry getLifecycle() { 37 | return mRegistry; 38 | } 39 | 40 | private Button btButton; 41 | 42 | private UserViewModel userViewModel; 43 | private UserViewModel userViewModel2; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.activity_main); 49 | btButton = (Button) findViewById(R.id.bt_click); 50 | 51 | ViewModelProvider viewModelProvider = ViewModelProviders.of(this); 52 | userViewModel = viewModelProvider.get(UserViewModel.class); 53 | userViewModel.getUserLiveData().observe(this, new Observer() { 54 | @Override 55 | public void onChanged(@Nullable User user) { 56 | Throwable a = new Throwable(); 57 | a.printStackTrace(); 58 | if (user != null) { 59 | Log.e("siyehua2", "update..."); 60 | btButton.setText(user.getName()); 61 | } 62 | } 63 | }); 64 | ViewModelProvider viewModelProvider2 = ViewModelProviders.of(this); 65 | 66 | userViewModel2 = viewModelProvider2.get(UserViewModel.class); 67 | //同一个 Activity 的 ViewModel 会被复用 68 | Log.e("siyehua", userViewModel.toString()); 69 | // Log.e("siyehua", userViewModel2.toString()); 70 | // Log.e("siyehua", viewModelProvider.toString()); 71 | // Log.e("siyehua", viewModelProvider2.toString()); 72 | } 73 | 74 | 75 | public void click(View view) { 76 | startActivity(new Intent(this, Main2Activity.class)); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/custom/MyLifeData.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.custom; 2 | 3 | import android.arch.lifecycle.LiveData; 4 | 5 | /** 6 | * 自定义 LiveData 7 | */ 8 | public class MyLifeData extends LiveData { 9 | @Override 10 | public void postValue(T value) { 11 | super.postValue(value); 12 | } 13 | 14 | @Override 15 | public void setValue(T value) { 16 | super.setValue(value); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/custom/MyLifecycle.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.custom; 2 | 3 | import android.arch.lifecycle.Lifecycle; 4 | import android.arch.lifecycle.LifecycleObserver; 5 | 6 | /** 7 | * Created by siyehua on 2017/8/9. 8 | */ 9 | public class MyLifecycle extends Lifecycle { 10 | @Override 11 | public void addObserver(LifecycleObserver observer) { 12 | 13 | } 14 | 15 | @Override 16 | public void removeObserver(LifecycleObserver observer) { 17 | 18 | } 19 | 20 | @Override 21 | public State getCurrentState() { 22 | return null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/custom/MyObserver.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.custom; 2 | 3 | import android.arch.lifecycle.Lifecycle; 4 | import android.arch.lifecycle.LifecycleObserver; 5 | import android.arch.lifecycle.OnLifecycleEvent; 6 | import android.util.Log; 7 | 8 | public class MyObserver implements LifecycleObserver { 9 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) 10 | public void create() { 11 | Log.e("siyehua", "create"); 12 | Throwable a = new Throwable(); 13 | a.printStackTrace(); 14 | } 15 | 16 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP) 17 | public void stop() { 18 | Log.e("siyehua", "stop"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/lifecycle/Main4Activity.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.lifecycle; 2 | 3 | import android.arch.lifecycle.LifecycleActivity; 4 | import android.arch.lifecycle.Observer; 5 | import android.arch.lifecycle.ViewModelProviders; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.widget.Button; 9 | 10 | import com.example.siyehua.myanotation.R; 11 | 12 | public class Main4Activity extends LifecycleActivity { 13 | 14 | private Button btButton; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | btButton = (Button) findViewById(R.id.bt_click); 21 | 22 | UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class); 23 | userViewModel.getUserLiveData().observe(this, new Observer() { 24 | @Override 25 | public void onChanged(@Nullable User user) { 26 | if (user != null) { 27 | btButton.setText(user.getName()); 28 | } 29 | } 30 | }); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/lifecycle/User.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.lifecycle; 2 | 3 | /** 4 | * Created by siyehua on 2017/8/10. 5 | */ 6 | 7 | public class User { 8 | private String name; 9 | private String password; 10 | 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | public void setName(String name) { 16 | this.name = name; 17 | } 18 | 19 | public String getPassword() { 20 | return password; 21 | } 22 | 23 | public void setPassword(String password) { 24 | this.password = password; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/lifecycle/UserViewModel.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.lifecycle; 2 | 3 | import android.arch.lifecycle.LiveData; 4 | import android.arch.lifecycle.MutableLiveData; 5 | import android.arch.lifecycle.ViewModel; 6 | import android.util.Log; 7 | 8 | import com.example.siyehua.myanotation.ExecutorServiceManager; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | public class UserViewModel extends ViewModel { 13 | private String id = ""; 14 | private LiveData userLiveData; 15 | 16 | public String getId() { 17 | return id; 18 | } 19 | 20 | public void setId(String id) { 21 | this.id = id; 22 | } 23 | 24 | public LiveData getUserLiveData() { 25 | final MutableLiveData data = new MutableLiveData<>(); 26 | ExecutorServiceManager.getInstance().execute(new Runnable() { 27 | @Override 28 | public void run() { 29 | try { 30 | TimeUnit.SECONDS.sleep(5); 31 | } catch (InterruptedException e) { 32 | e.printStackTrace(); 33 | } 34 | User user = new User(); 35 | user.setName("siyehua"); 36 | user.setPassword("123456"); 37 | Log.e("siyehua", "child thread..."); 38 | data.postValue(user); 39 | 40 | } 41 | }); 42 | 43 | return userLiveData = data; 44 | } 45 | 46 | public void setUserLiveData(LiveData userLiveData) { 47 | this.userLiveData = userLiveData; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/mvp/IPresenter.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.mvp; 2 | 3 | /** 4 | * Created by siyehua on 2017/8/11. 5 | */ 6 | 7 | public interface IPresenter { 8 | 9 | void getName(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/mvp/IView.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.mvp; 2 | 3 | /** 4 | * Created by siyehua on 2017/8/11. 5 | */ 6 | 7 | public interface IView { 8 | void setName(String name); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/mvp/Main3Activity.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.mvp; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.widget.TextView; 7 | 8 | import com.example.siyehua.myanotation.R; 9 | 10 | public class Main3Activity extends AppCompatActivity implements IView { 11 | private TextView textView; 12 | 13 | private PersonPresenter personPresenter; 14 | 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main3); 20 | textView = (TextView) findViewById(R.id.tv_content); 21 | personPresenter = new PersonPresenter(this); 22 | 23 | personPresenter.getName(); 24 | } 25 | 26 | @Override 27 | public void setName(String name) { 28 | Log.e(Main3Activity.class.getSimpleName(), "setName(): " + this.getClass().getSimpleName()); 29 | textView.setText(name); 30 | } 31 | 32 | @Override 33 | protected void onDestroy() { 34 | //不移除 View 有可能导致内存泄漏 35 | // personPresenter.removeView(); 36 | super.onDestroy(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/mvp/Person.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.mvp; 2 | 3 | /** 4 | * Created by siyehua on 2017/8/11. 5 | */ 6 | 7 | public class Person { 8 | private String name; 9 | private int age; 10 | 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | public void setName(String name) { 16 | this.name = name; 17 | } 18 | 19 | public int getAge() { 20 | return age; 21 | } 22 | 23 | public void setAge(int age) { 24 | this.age = age; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/siyehua/myanotation/mvp/PersonPresenter.java: -------------------------------------------------------------------------------- 1 | package com.example.siyehua.myanotation.mvp; 2 | 3 | import com.example.siyehua.myanotation.ExecutorServiceManager; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * Created by siyehua on 2017/8/11. 9 | */ 10 | 11 | public class PersonPresenter implements IPresenter { 12 | private IView iView; 13 | 14 | public PersonPresenter(IView iView) { 15 | this.iView = iView; 16 | } 17 | 18 | @Override 19 | public void getName() { 20 | ExecutorServiceManager.getInstance().execute(new Runnable() { 21 | @Override 22 | public void run() { 23 | try { 24 | TimeUnit.SECONDS.sleep(5); 25 | } catch (InterruptedException e) { 26 | e.printStackTrace(); 27 | } 28 | 29 | if (iView != null) { 30 | iView.setName("siyehua"); 31 | } 32 | } 33 | }); 34 | } 35 | 36 | public void removeView() { 37 | iView = null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |