├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kunminx │ │ └── puremusic │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── java2kotlin.html │ ├── java │ │ └── com │ │ │ └── kunminx │ │ │ └── puremusic │ │ │ ├── App.java │ │ │ ├── data │ │ │ ├── bean │ │ │ │ └── GridItem.java │ │ │ └── repository │ │ │ │ ├── DataRepository.java │ │ │ │ ├── ILocalRequest.java │ │ │ │ └── IRemoteRequest.java │ │ │ ├── domain │ │ │ └── request │ │ │ │ ├── GridItemRequest.java │ │ │ │ └── Request.java │ │ │ └── ui │ │ │ ├── adapter │ │ │ └── GridItemAdapter.java │ │ │ ├── page │ │ │ └── MainActivity.java │ │ │ └── state │ │ │ └── MainActivityViewModel.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ ├── bg_album_default.png │ │ └── ic_launcher.png │ │ ├── drawable-xxxhdpi │ │ └── ic_launcher.png │ │ ├── drawable │ │ ├── bg_home.png │ │ ├── ic_launcher_background.xml │ │ ├── ic_menu_black_48dp.xml │ │ ├── ic_music_note_black_48dp.xml │ │ └── ic_search_black_48dp.xml │ │ ├── layout-land │ │ └── activity_main.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── adapter_grid_item.xml │ │ ├── mipmap-anydpi-v26 │ │ └── ic_launcher.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 │ │ ├── navigation │ │ └── nav_main.xml │ │ ├── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimen.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── network_security_config.xml │ └── test │ └── java │ └── com │ └── kunminx │ └── puremusic │ └── ExampleUnitTest.java ├── architecture ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kunminx │ │ └── architecture │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ ├── androidx │ │ │ └── navigation │ │ │ │ └── fragment │ │ │ │ ├── DialogFragmentNavigator.java │ │ │ │ ├── FragmentNavigator.java │ │ │ │ └── NavHostFragment.java │ │ └── com │ │ │ └── kunminx │ │ │ └── architecture │ │ │ ├── BaseApplication.kt │ │ │ ├── data │ │ │ ├── manager │ │ │ │ ├── NetState.java │ │ │ │ ├── NetworkStateManager.java │ │ │ │ └── NetworkStateReceive.java │ │ │ └── usecase │ │ │ │ ├── UseCase.java │ │ │ │ ├── UseCaseHandler.java │ │ │ │ ├── UseCaseScheduler.java │ │ │ │ └── UseCaseThreadPoolScheduler.java │ │ │ ├── kotlin │ │ │ ├── Event.kt │ │ │ └── WrapperLiveData.kt │ │ │ ├── ui │ │ │ ├── BaseActivity.java │ │ │ ├── BaseFragment.java │ │ │ ├── adapter │ │ │ │ ├── BaseBindingAdapter.java │ │ │ │ ├── CommonViewPagerAdapter.java │ │ │ │ └── SimpleBindingAdapter.java │ │ │ ├── binding_adapter │ │ │ │ ├── CommonBindingAdapter.java │ │ │ │ ├── DrawablesBindingAdapter.java │ │ │ │ ├── RecyclerViewBindingAdapter.java │ │ │ │ ├── TabPageBindingAdapter.java │ │ │ │ └── WebViewBindingAdapter.java │ │ │ └── layout_manager │ │ │ │ ├── WrapContentGridLayoutManager.java │ │ │ │ ├── WrapContentLinearLayoutManager.java │ │ │ │ └── WrapContentStaggeredGridLayoutManager.java │ │ │ └── utils │ │ │ ├── AdaptScreenUtils.java │ │ │ ├── BarUtils.java │ │ │ ├── ClickUtils.java │ │ │ ├── CompatUtils.java │ │ │ ├── DisplayUtils.java │ │ │ ├── Etx.kt │ │ │ ├── FileIOUtils.java │ │ │ ├── FileUtils.java │ │ │ ├── ImageUtils.java │ │ │ ├── NetworkUtils.java │ │ │ ├── SPUtils.java │ │ │ ├── ScreenUtils.java │ │ │ ├── ShellUtils.java │ │ │ └── Utils.java │ └── res │ │ ├── values │ │ ├── ids.xml │ │ ├── strings.xml │ │ └── values.xml │ │ └── xml │ │ └── file_paths.xml │ └── test │ └── java │ └── com │ └── kunminx │ └── architecture │ └── ExampleUnitTest.java ├── build.gradle ├── common_res ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── res │ ├── anim │ ├── h_fragment_enter.xml │ ├── h_fragment_exit.xml │ ├── h_fragment_pop_enter.xml │ └── h_fragment_pop_exit.xml │ ├── drawable-anydpi │ ├── ic_add.xml │ ├── ic_back.xml │ ├── ic_menu_save.xml │ └── round_solid_gray.xml │ ├── drawable-hdpi │ ├── ic_add.png │ ├── ic_back.png │ └── ic_menu_save.png │ ├── drawable-mdpi │ ├── ic_add.png │ ├── ic_back.png │ └── ic_menu_save.png │ ├── drawable-xhdpi │ ├── ic_add.png │ ├── ic_back.png │ └── ic_menu_save.png │ ├── drawable-xxhdpi │ ├── ic_add.png │ ├── ic_back.png │ └── ic_menu_save.png │ ├── drawable │ ├── ripple_click.xml │ └── round_stroke_blue.xml │ ├── menu │ └── editor_menu.xml │ └── values │ ├── colors.xml │ └── strings.xml ├── gradle.properties ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jetpack_java ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kunminx │ │ └── jetpack_java │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── best_practice.html │ ├── java │ │ └── com │ │ │ └── kunminx │ │ │ └── jetpack_java │ │ │ ├── common_data │ │ │ ├── APIs.java │ │ │ ├── Configs.java │ │ │ └── bean │ │ │ │ ├── LocationBean.java │ │ │ │ └── Moment.java │ │ │ ├── common_ui │ │ │ └── adapter │ │ │ │ ├── DiffUtilCallbacks.java │ │ │ │ ├── LocationAdapter.java │ │ │ │ └── MomentAdapter.java │ │ │ ├── sample_01_lifecycles │ │ │ ├── domain │ │ │ │ └── LifecycleLocationManager.java │ │ │ └── ui │ │ │ │ ├── LifecycleEditorActivity.java │ │ │ │ └── LifecycleLocationActivity.java │ │ │ ├── sample_02_livedata │ │ │ ├── domain │ │ │ │ └── LiveDataLocationManager.java │ │ │ └── ui │ │ │ │ ├── LiveDataEditorActivity.java │ │ │ │ └── LiveDataLocationActivity.java │ │ │ ├── sample_03_viewmodel │ │ │ ├── data │ │ │ │ └── DataRepository.java │ │ │ ├── domain │ │ │ │ ├── BaseRequest.java │ │ │ │ └── MomentRequest.java │ │ │ └── ui │ │ │ │ ├── ViewModelListActivity.java │ │ │ │ └── state │ │ │ │ └── ListViewModel.java │ │ │ ├── sample_04_databinding │ │ │ └── ui │ │ │ │ ├── DataBindingDetailActivity.java │ │ │ │ ├── DataBindingEditorActivity.java │ │ │ │ ├── DataBindingListActivity.java │ │ │ │ ├── DataBindingLocationActivity.java │ │ │ │ ├── adapter │ │ │ │ ├── DataBindingLocationAdapter.java │ │ │ │ └── DataBindingMomentAdapter.java │ │ │ │ └── state │ │ │ │ ├── DetailViewModel.java │ │ │ │ ├── EditorViewModel.java │ │ │ │ ├── ListViewModel.java │ │ │ │ └── LocationViewModel.java │ │ │ ├── sample_05_navigation │ │ │ └── ui │ │ │ │ ├── NavigationDetailFragment.java │ │ │ │ ├── NavigationEditorFragment.java │ │ │ │ ├── NavigationListFragment.java │ │ │ │ ├── NavigationLocationFragment.java │ │ │ │ ├── NavigationMainActivity.java │ │ │ │ └── callback │ │ │ │ └── SharedViewModel.java │ │ │ └── sample_one_more_thing │ │ │ └── ui │ │ │ ├── OneMoreThingActivity.java │ │ │ └── state │ │ │ └── OneMoreThingViewModel.java │ └── res │ │ ├── layout │ │ ├── activity_detail_databinding.xml │ │ ├── activity_editor_databinding.xml │ │ ├── activity_editor_lifecycle.xml │ │ ├── activity_editor_livedata.xml │ │ ├── activity_list_databinding.xml │ │ ├── activity_list_viewmodel.xml │ │ ├── activity_location_databinding.xml │ │ ├── activity_location_lifecycles.xml │ │ ├── activity_main_navigation.xml │ │ ├── activity_one_more_thing.xml │ │ ├── adapter_location.xml │ │ ├── adapter_location_databinding.xml │ │ ├── adapter_moment.xml │ │ ├── adapter_moment_databinding.xml │ │ ├── fragment_detail_navigation.xml │ │ ├── fragment_editor_navigation.xml │ │ ├── fragment_list_navigation.xml │ │ └── fragment_location_navigation.xml │ │ ├── navigation │ │ └── nav_graph.xml │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── kunminx │ └── jetpack_java │ └── ExampleUnitTest.java ├── jetpack_kotlin ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── flywith24 │ │ └── jetpack_kotlin │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── use_jetpack.html │ ├── java │ │ └── com │ │ │ └── flywith24 │ │ │ └── jetpack_kotlin │ │ │ ├── common_data │ │ │ ├── APIs.kt │ │ │ ├── Configs.kt │ │ │ └── bean │ │ │ │ ├── LocationBean.kt │ │ │ │ └── Moment.kt │ │ │ ├── common_ui │ │ │ └── adapter │ │ │ │ ├── DiffUtil.kt │ │ │ │ ├── LocationAdapter.kt │ │ │ │ └── MomentAdapter.kt │ │ │ ├── sample_01_lifecycles │ │ │ ├── domain │ │ │ │ └── LifecycleLocationManager.kt │ │ │ └── ui │ │ │ │ ├── LifecycleEditorActivity.kt │ │ │ │ └── LifecycleLocationActivity.kt │ │ │ ├── sample_02_livedata │ │ │ ├── domain │ │ │ │ └── LiveDataLocationManager.kt │ │ │ └── ui │ │ │ │ ├── LiveDataEditorActivity.kt │ │ │ │ └── LiveDataLocationActivity.kt │ │ │ ├── sample_03_viewmodel │ │ │ ├── data │ │ │ │ └── DataRepository.kt │ │ │ ├── domain │ │ │ │ ├── MomentRequest.kt │ │ │ │ └── Request.kt │ │ │ └── ui │ │ │ │ ├── ViewModelListActivity.kt │ │ │ │ └── state │ │ │ │ └── ListViewModel.kt │ │ │ ├── sample_04_databinding │ │ │ └── ui │ │ │ │ ├── DataBindingDetailActivity.kt │ │ │ │ ├── DataBindingEditorActivity.kt │ │ │ │ ├── DataBindingListActivity.kt │ │ │ │ ├── DataBindingLocationActivity.kt │ │ │ │ ├── adapter │ │ │ │ ├── DataBindingLocationAdapter.kt │ │ │ │ └── DataBindingMomentAdapter.kt │ │ │ │ └── state │ │ │ │ ├── DetailViewModel.kt │ │ │ │ ├── EditorViewModel.kt │ │ │ │ ├── ListViewModel.kt │ │ │ │ └── LocationViewModel.kt │ │ │ ├── sample_05_navigation │ │ │ └── ui │ │ │ │ ├── NavigationDetailFragment.kt │ │ │ │ ├── NavigationEditorFragment.kt │ │ │ │ ├── NavigationListFragment.kt │ │ │ │ ├── NavigationLocationFragment.kt │ │ │ │ ├── NavigationMainActivity.kt │ │ │ │ └── callback │ │ │ │ └── SharedViewModel.kt │ │ │ └── sample_one_more_thing │ │ │ └── ui │ │ │ ├── OneMoreThingActivity.kt │ │ │ └── state │ │ │ └── OneMoreThingViewModel.kt │ └── res │ │ ├── layout │ │ ├── kotlin_activity_detail_databinding.xml │ │ ├── kotlin_activity_editor_databinding.xml │ │ ├── kotlin_activity_editor_livedata.xml │ │ ├── kotlin_activity_lifecycles_detail.xml │ │ ├── kotlin_activity_lifecycles_location.xml │ │ ├── kotlin_activity_list_databinding.xml │ │ ├── kotlin_activity_list_viewmodel.xml │ │ ├── kotlin_activity_livedata_editor.xml │ │ ├── kotlin_activity_livedata_list.xml │ │ ├── kotlin_activity_location_databinding.xml │ │ ├── kotlin_activity_main_navigation.xml │ │ ├── kotlin_activity_one_more_thing.xml │ │ ├── kotlin_adapter_location.xml │ │ ├── kotlin_adapter_location_databinding.xml │ │ ├── kotlin_adapter_moment.xml │ │ ├── kotlin_adapter_moment_databinding.xml │ │ ├── kotlin_fragment_detail_navigation.xml │ │ ├── kotlin_fragment_editor_navigation.xml │ │ ├── kotlin_fragment_location_navigation.xml │ │ └── kottlin_fragment_list_navigation.xml │ │ ├── navigation │ │ └── kotlin_nav_graph.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── flywith24 │ └── jetpack_kotlin │ └── ExampleUnitTest.kt ├── settings.gradle └── version_config ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── proguard-rules.pro ├── settings.gradle └── src └── main └── java └── com └── flywith24 └── version_config ├── BuildConfig.kt ├── VersionConfigPlugin.kt └── dependencies ├── AndroidX.kt ├── Google.kt ├── Testing.kt └── ThirdParty.kt /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .DS_Store 3 | .externalNativeBuild 4 | .project 5 | .gradle 6 | .idea 7 | .mtj.tmp 8 | .vscode 9 | .settings 10 | 11 | local.properties 12 | maven-repository 13 | mvn-clone 14 | build 15 | captures 16 | objectbox-models 17 | gen 18 | out 19 | target 20 | 21 | *.class 22 | *.ctxt 23 | *.ear 24 | *.iml 25 | *.jar 26 | *.keystore 27 | *.log 28 | *.nar 29 | *.rar 30 | *.tar.gz 31 | *.war 32 | *.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://i.loli.net/2021/09/11/UhivcfX7VNeM4r3.png) 2 | 3 |   4 | 5 | ## 项目简介 6 | 7 | 很高兴见到你! 8 | 9 | 本项目 **专注于提供** Jetpack 核心组件 从 Java 到 Kotlin 的 **对照示例**, 10 | 11 | 换言之,通过本项目 精心设计的场景 和 精简的代码,你可迅速了解到 在引入了 Jetpack 的项目中 **"到底写了什么"**,以及 Kotlin 相较 Java **写法的差异之所在**, 12 | 13 | 在简单感受一下项目源码后,如你开始对 **"具体该怎么写"、"为什么要这样写"** 产生了一丝好奇心,想要继续深入探索,那我们的愿望也就达到了 😉 14 |   15 | 16 | | 组件示例入口 | 列表 - 详情 | 列表 - 编辑 - 定位 | 17 | | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | 18 | | ![Untitled.gif](https://i.loli.net/2020/06/09/2ThFWwMtV4rlUby.gif) | ![Untitled3.gif](https://i.loli.net/2020/06/09/sHEzaIo2WihBkPd.gif) | ![Untitled2.gif](https://i.loli.net/2020/06/09/wHvqG5TOQYSVnLg.gif) | 19 | 20 |   21 | 22 | ## 后置进阶 23 | 24 | 在了解完本项目后,若你觉得胃口大开,别着急 😉 25 | 26 | 以下是两位作者分别长期维护的 Jetpack 进阶项目: 27 | 28 | [《Jetpack MVVM 最佳实践》](https://github.com/KunMinX/Jetpack-MVVM-Best-Practice): 29 | 30 | 该项目专注于解析 Jetpack 高频核心组件,**曾被某对标阿里 P7 架构师拿去给 2300 名学员讲课**,通过它你可迅速理解状况并应用于工作或面试中。 31 | 32 | [《Kotlin Jetpack 背包》](https://github.com/Flywith24/Flywith24-Jetpack-Demo): 33 | 34 | 该项目专注于跟进 Jetpack kotlin 最新技术动向,**目前已点到为止地提供数十个技术点示例代码**, 通过它你可在要求使用 kotlin 的工作中随时查阅、随取随用。 35 | 36 |   37 | 38 | ## 版权声明 39 | 40 | 本项目的场景、外观、代码设计,由作者 [KunMinX](https://github.com/KunMinX) 和 [Flywith24](https://github.com/Flywith24) 完成,作者对此享有著作权,任何个人或组织,未经作者本人授权,不得将该项目的设计用于写书、卖课等商业用途。 41 | 42 | Copyright © 2020-present KunMinX & Flywith24 43 | 44 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .DS_Store 3 | .externalNativeBuild 4 | .project 5 | .gradle 6 | .idea 7 | .mtj.tmp 8 | .vscode 9 | .settings 10 | 11 | local.properties 12 | maven-repository 13 | mvn-clone 14 | build 15 | captures 16 | objectbox-models 17 | gen 18 | out 19 | target 20 | 21 | *.class 22 | *.ctxt 23 | *.ear 24 | *.iml 25 | *.jar 26 | *.keystore 27 | *.log 28 | *.nar 29 | *.rar 30 | *.tar.gz 31 | *.war 32 | *.zip -------------------------------------------------------------------------------- /app/src/androidTest/java/com/kunminx/puremusic/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.kunminx.puremusic; 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 | 25 | assertEquals("com.kunminx.puremusic", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/App.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.puremusic; 4 | 5 | import android.app.Activity; 6 | import android.app.Application; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.fragment.app.Fragment; 10 | import androidx.lifecycle.ViewModelProvider; 11 | import androidx.lifecycle.ViewModelStore; 12 | import androidx.lifecycle.ViewModelStoreOwner; 13 | 14 | import com.kunminx.architecture.BaseApplication; 15 | import com.kunminx.architecture.utils.Utils; 16 | 17 | /** 18 | * Create by KunMinX at 19/10/29 19 | */ 20 | public class App extends BaseApplication implements ViewModelStoreOwner { 21 | 22 | private ViewModelStore mAppViewModelStore; 23 | 24 | private ViewModelProvider.Factory mFactory; 25 | 26 | @Override 27 | public void onCreate() { 28 | super.onCreate(); 29 | 30 | mAppViewModelStore = new ViewModelStore(); 31 | 32 | Utils.init(this); 33 | } 34 | 35 | @NonNull 36 | @Override 37 | public ViewModelStore getViewModelStore() { 38 | return mAppViewModelStore; 39 | } 40 | 41 | public ViewModelProvider getAppViewModelProvider(Activity activity) { 42 | return new ViewModelProvider((App) activity.getApplicationContext(), 43 | ((App) activity.getApplicationContext()).getAppFactory(activity)); 44 | } 45 | 46 | private ViewModelProvider.Factory getAppFactory(Activity activity) { 47 | Application application = checkApplication(activity); 48 | if (mFactory == null) { 49 | mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); 50 | } 51 | return mFactory; 52 | } 53 | 54 | private Application checkApplication(Activity activity) { 55 | Application application = activity.getApplication(); 56 | if (application == null) { 57 | throw new IllegalStateException("Your activity/fragment is not yet attached to " 58 | + "Application. You can't request ViewModel before onCreate call."); 59 | } 60 | return application; 61 | } 62 | 63 | private Activity checkActivity(Fragment fragment) { 64 | Activity activity = fragment.getActivity(); 65 | if (activity == null) { 66 | throw new IllegalStateException("Can't create ViewModelProvider for detached fragment"); 67 | } 68 | return activity; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/data/bean/GridItem.java: -------------------------------------------------------------------------------- 1 | package com.kunminx.puremusic.data.bean; 2 | 3 | /** 4 | * Create by KunMinX at 2020/5/27 5 | */ 6 | public class GridItem { 7 | 8 | private String uuid; 9 | private String title; 10 | private int drawable; 11 | private String packageName; 12 | private String activityPath; 13 | 14 | public GridItem() { 15 | } 16 | 17 | public GridItem(String uuid, String title, int drawable, String packageName, String activityPath) { 18 | this.uuid = uuid; 19 | this.title = title; 20 | this.drawable = drawable; 21 | this.packageName = packageName; 22 | this.activityPath = activityPath; 23 | } 24 | 25 | public String getUuid() { 26 | return uuid; 27 | } 28 | 29 | public void setUuid(String uuid) { 30 | this.uuid = uuid; 31 | } 32 | 33 | public String getTitle() { 34 | return title; 35 | } 36 | 37 | public void setTitle(String title) { 38 | this.title = title; 39 | } 40 | 41 | public int getDrawable() { 42 | return drawable; 43 | } 44 | 45 | public void setDrawable(int drawable) { 46 | this.drawable = drawable; 47 | } 48 | 49 | public String getPackageName() { 50 | return packageName; 51 | } 52 | 53 | public void setPackageName(String packageName) { 54 | this.packageName = packageName; 55 | } 56 | 57 | public String getActivityPath() { 58 | return activityPath; 59 | } 60 | 61 | public void setActivityPath(String activityPath) { 62 | this.activityPath = activityPath; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/data/repository/ILocalRequest.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.puremusic.data.repository; 4 | 5 | /** 6 | * Create by KunMinX at 19/10/29 7 | */ 8 | public interface ILocalRequest { 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/data/repository/IRemoteRequest.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.puremusic.data.repository; 4 | 5 | import androidx.lifecycle.MutableLiveData; 6 | 7 | import com.kunminx.puremusic.data.bean.GridItem; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Create by KunMinX at 19/10/29 13 | */ 14 | public interface IRemoteRequest { 15 | 16 | void getJavaItems(MutableLiveData> liveData); 17 | 18 | void getKotlinItems(MutableLiveData> liveData); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/domain/request/GridItemRequest.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.puremusic.domain.request; 4 | 5 | import androidx.lifecycle.LiveData; 6 | import androidx.lifecycle.MutableLiveData; 7 | 8 | import com.kunminx.puremusic.data.bean.GridItem; 9 | import com.kunminx.puremusic.data.repository.DataRepository; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * 音乐资源 Request 15 | *

16 | * TODO tip:Request 通常按业务划分 17 | * 一个项目中通常存在多个 Request 18 | *

19 | * request 的职责仅限于 数据请求,不建议在此处理 UI 逻辑, 20 | * UI 逻辑只适合在 Activity/Fragment 等视图控制器中完成,是 “数据驱动” 的一部分, 21 | * 将来升级到 Jetpack Compose 更是如此。 22 | *

23 | * 如果这样说还不理解的话,详见 https://xiaozhuanlan.com/topic/6257931840 24 | *

25 | * Create by KunMinX at 19/10/29 26 | */ 27 | public class GridItemRequest implements Request.IGridItemRequest { 28 | 29 | private MutableLiveData> mJavaItemsLiveData; 30 | private MutableLiveData> mKotlinItemsLiveData; 31 | 32 | //TODO tip 向 ui 层提供的 request LiveData,使用抽象的 LiveData 而不是 MutableLiveData 33 | // 如此是为了来自数据层的数据,在 ui 层中只读,以避免团队新手不可预期的误用 34 | 35 | @Override 36 | public LiveData> getJavaItemsLiveData() { 37 | if (mJavaItemsLiveData == null) { 38 | mJavaItemsLiveData = new MutableLiveData<>(); 39 | } 40 | return mJavaItemsLiveData; 41 | } 42 | 43 | @Override 44 | public LiveData> getKotlinItemsLiveData() { 45 | if (mKotlinItemsLiveData == null) { 46 | mKotlinItemsLiveData = new MutableLiveData<>(); 47 | } 48 | return mKotlinItemsLiveData; 49 | } 50 | 51 | @Override 52 | public void requestJavaItems() { 53 | DataRepository.getInstance().getJavaItems(mJavaItemsLiveData); 54 | } 55 | 56 | @Override 57 | public void requestKotlinItems() { 58 | DataRepository.getInstance().getKotlinItems(mKotlinItemsLiveData); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/domain/request/Request.java: -------------------------------------------------------------------------------- 1 | package com.kunminx.puremusic.domain.request; 2 | 3 | import androidx.lifecycle.LiveData; 4 | 5 | import com.kunminx.puremusic.data.bean.GridItem; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Create by KunMinX at 2020/5/21 11 | */ 12 | public class Request { 13 | 14 | public interface IGridItemRequest { 15 | 16 | LiveData> getJavaItemsLiveData(); 17 | 18 | LiveData> getKotlinItemsLiveData(); 19 | 20 | void requestJavaItems(); 21 | 22 | void requestKotlinItems(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/ui/adapter/GridItemAdapter.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.puremusic.ui.adapter; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.DiffUtil; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.kunminx.architecture.ui.adapter.SimpleBindingAdapter; 12 | import com.kunminx.puremusic.R; 13 | import com.kunminx.puremusic.data.bean.GridItem; 14 | import com.kunminx.puremusic.databinding.AdapterGridItemBinding; 15 | 16 | /** 17 | * Create by KunMinX at 20/4/19 18 | */ 19 | public class GridItemAdapter extends SimpleBindingAdapter { 20 | 21 | public GridItemAdapter(Context context) { 22 | super(context, R.layout.adapter_grid_item, new DiffUtil.ItemCallback() { 23 | @Override 24 | public boolean areItemsTheSame(@NonNull GridItem oldItem, @NonNull GridItem newItem) { 25 | return oldItem.equals(newItem); 26 | } 27 | 28 | @Override 29 | public boolean areContentsTheSame(@NonNull GridItem oldItem, @NonNull GridItem newItem) { 30 | return oldItem.getUuid().equals(newItem.getUuid()); 31 | } 32 | }); 33 | } 34 | 35 | @Override 36 | protected void onBindItem(AdapterGridItemBinding binding, GridItem item, RecyclerView.ViewHolder holder) { 37 | binding.setItem(item); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/ui/page/MainActivity.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.puremusic.ui.page; 4 | 5 | import android.content.ComponentName; 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | 9 | import androidx.databinding.DataBindingUtil; 10 | 11 | import com.kunminx.architecture.ui.BaseActivity; 12 | import com.kunminx.puremusic.R; 13 | import com.kunminx.puremusic.databinding.ActivityMainBinding; 14 | import com.kunminx.puremusic.ui.adapter.GridItemAdapter; 15 | import com.kunminx.puremusic.ui.state.MainActivityViewModel; 16 | 17 | /** 18 | * Create by KunMinX at 19/10/16 19 | */ 20 | 21 | public class MainActivity extends BaseActivity { 22 | 23 | private MainActivityViewModel mMainActivityViewModel; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | mMainActivityViewModel = getActivityScopeViewModel(MainActivityViewModel.class); 29 | 30 | ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); 31 | binding.setVm(mMainActivityViewModel); 32 | 33 | GridItemAdapter adapterJava = new GridItemAdapter(getApplicationContext()); 34 | adapterJava.setOnItemClickListener((item, position) -> { 35 | Intent intent = new Intent(); 36 | intent.setComponent(new ComponentName(item.getPackageName(), item.getActivityPath())); 37 | startActivity(intent); 38 | }); 39 | binding.setAdapterJava(adapterJava); 40 | 41 | GridItemAdapter adapterKotlin = new GridItemAdapter(getApplicationContext()); 42 | adapterKotlin.setOnItemClickListener(((item, position) -> { 43 | Intent intent = new Intent(); 44 | intent.setComponent(new ComponentName(item.getPackageName(), item.getActivityPath())); 45 | startActivity(intent); 46 | })); 47 | binding.setAdapterKotlin(adapterKotlin); 48 | 49 | mMainActivityViewModel.getJavaItemsLiveData().observe(this, gridItems -> { 50 | mMainActivityViewModel.javaList.setValue(gridItems); 51 | }); 52 | 53 | mMainActivityViewModel.getKotlinItemsLiveData().observe(this, gridItems -> { 54 | mMainActivityViewModel.kotlinList.setValue(gridItems); 55 | }); 56 | 57 | mMainActivityViewModel.requestJavaItems(); 58 | mMainActivityViewModel.requestKotlinItems(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/kunminx/puremusic/ui/state/MainActivityViewModel.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.puremusic.ui.state; 4 | 5 | import androidx.databinding.ObservableBoolean; 6 | import androidx.databinding.ObservableField; 7 | import androidx.lifecycle.LiveData; 8 | import androidx.lifecycle.MutableLiveData; 9 | import androidx.lifecycle.ViewModel; 10 | 11 | import com.kunminx.puremusic.data.bean.GridItem; 12 | import com.kunminx.puremusic.domain.request.GridItemRequest; 13 | import com.kunminx.puremusic.domain.request.Request; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * Create by KunMinX at 19/10/29 19 | */ 20 | public class MainActivityViewModel extends ViewModel implements Request.IGridItemRequest { 21 | 22 | public final ObservableBoolean initTabAndPage = new ObservableBoolean(); 23 | 24 | public final ObservableField pageAssetPath = new ObservableField<>(); 25 | 26 | public final ObservableField homeImg = new ObservableField<>(); 27 | 28 | public final MutableLiveData> javaList = new MutableLiveData<>(); 29 | public final MutableLiveData> kotlinList = new MutableLiveData<>(); 30 | 31 | private GridItemRequest mGridItemRequest = new GridItemRequest(); 32 | 33 | { 34 | initTabAndPage.set(true); 35 | pageAssetPath.set("java2kotlin.html"); 36 | homeImg.set("https://i.loli.net/2020/06/09/rLzKlThf5pQvtCj.jpg"); 37 | } 38 | 39 | @Override 40 | public LiveData> getJavaItemsLiveData() { 41 | return mGridItemRequest.getJavaItemsLiveData(); 42 | } 43 | 44 | @Override 45 | public LiveData> getKotlinItemsLiveData() { 46 | return mGridItemRequest.getKotlinItemsLiveData(); 47 | } 48 | 49 | @Override 50 | public void requestJavaItems() { 51 | mGridItemRequest.requestJavaItems(); 52 | } 53 | 54 | @Override 55 | public void requestKotlinItems() { 56 | mGridItemRequest.requestKotlinItems(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/bg_album_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/drawable-xxhdpi/bg_album_default.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/drawable/bg_home.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_black_48dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_music_note_black_48dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_black_48dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_grid_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 22 | 23 | 36 | 37 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/navigation/nav_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | 31 | 32 | 33 | 34 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | #fff 8 | #000 9 | #666 10 | #999 11 | #00000000 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 55dp 5 | 200dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Jetpack from Java to Kotlin 3 | Java 4 | Kotlin 5 | About 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/test/java/com/kunminx/puremusic/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.kunminx.puremusic; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /architecture/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /architecture/build.gradle: -------------------------------------------------------------------------------- 1 | import com.flywith24.version_config.BuildConfig 2 | import com.flywith24.version_config.dependencies.AndroidX 3 | import com.flywith24.version_config.dependencies.Google 4 | import com.flywith24.version_config.dependencies.Testing 5 | import com.flywith24.version_config.dependencies.ThirdParty 6 | 7 | 8 | plugins { 9 | id "com.flywith24.version" 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | apply plugin: 'kotlin-android' 14 | 15 | android { 16 | compileSdkVersion BuildConfig.compileSdkVersion 17 | buildToolsVersion BuildConfig.buildToolsVersion 18 | 19 | defaultConfig { 20 | minSdkVersion BuildConfig.minSdkVersion 21 | targetSdkVersion BuildConfig.targetSdkVersion 22 | versionCode BuildConfig.versionCode 23 | versionName BuildConfig.versionName 24 | 25 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 26 | consumerProguardFiles 'consumer-rules.pro' 27 | } 28 | 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 33 | } 34 | } 35 | 36 | lintOptions { 37 | checkReleaseBuilds false 38 | abortOnError false 39 | } 40 | 41 | compileOptions { 42 | sourceCompatibility JavaVersion.VERSION_1_8 43 | targetCompatibility JavaVersion.VERSION_1_8 44 | } 45 | 46 | dataBinding { 47 | enabled = true 48 | } 49 | 50 | } 51 | 52 | dependencies { 53 | implementation fileTree(dir: 'libs', include: ['*.jar']) 54 | 55 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 56 | 57 | testImplementation(Testing.jUnit) 58 | androidTestImplementation(Testing.androidJunit) 59 | androidTestImplementation(Testing.androidRunner) 60 | androidTestImplementation(Testing.espresso) 61 | 62 | implementation(AndroidX.appcompat) 63 | implementation(AndroidX.constraintlayout) 64 | implementation(AndroidX.recyclerView) 65 | implementation(AndroidX.Fragment.fragment) 66 | implementation(Google.material) 67 | 68 | implementation(AndroidX.Lifecycle.lifecycleRuntime) 69 | implementation(AndroidX.Lifecycle.commonJava8) 70 | implementation(AndroidX.Lifecycle.extensions) 71 | implementation(AndroidX.Lifecycle.viewModel) 72 | implementation(AndroidX.Lifecycle.liveData) 73 | 74 | implementation(ThirdParty.Archi.unPeekLiveData) 75 | 76 | implementation(AndroidX.Navigation.runtime) 77 | 78 | implementation(ThirdParty.Glide.glide) 79 | 80 | } 81 | -------------------------------------------------------------------------------- /architecture/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/architecture/consumer-rules.pro -------------------------------------------------------------------------------- /architecture/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 22 | -------------------------------------------------------------------------------- /architecture/src/androidTest/java/com/kunminx/architecture/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.test.platform.app.InstrumentationRegistry; 8 | import androidx.test.ext.junit.runners.AndroidJUnit4; 9 | 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | 13 | import static org.junit.Assert.*; 14 | 15 | /** 16 | * Instrumented test, which will execute on an Android device. 17 | * 18 | * @see Testing documentation 19 | */ 20 | @RunWith(AndroidJUnit4.class) 21 | public class ExampleInstrumentedTest { 22 | @Test 23 | public void useAppContext() { 24 | // Context of the app under test. 25 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 26 | 27 | assertEquals("com.kunminx.architecture.test", appContext.getPackageName()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /architecture/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/BaseApplication.kt: -------------------------------------------------------------------------------- 1 | package com.kunminx.architecture 2 | 3 | import android.app.Application 4 | 5 | /** 6 | * @author Flywith24 7 | * @date 2020/5/30 8 | * time 20:43 9 | * description 10 | */ 11 | open class BaseApplication : Application() { 12 | override fun onCreate() { 13 | super.onCreate() 14 | instance = this 15 | } 16 | 17 | companion object { 18 | @JvmStatic 19 | lateinit var instance: Application 20 | } 21 | } -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/data/manager/NetState.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.data.manager; 4 | 5 | /** 6 | * Create by KunMinX at 19/10/11 7 | */ 8 | public class NetState { 9 | 10 | private String responseCode; 11 | private boolean success = true; 12 | 13 | public String getResponseCode() { 14 | return responseCode; 15 | } 16 | 17 | public void setResponseCode(String responseCode) { 18 | this.responseCode = responseCode; 19 | } 20 | 21 | public boolean isSuccess() { 22 | return success; 23 | } 24 | 25 | public void setSuccess(boolean success) { 26 | this.success = success; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/data/manager/NetworkStateManager.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.data.manager; 4 | 5 | import android.content.IntentFilter; 6 | import android.net.ConnectivityManager; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.lifecycle.DefaultLifecycleObserver; 10 | import androidx.lifecycle.LifecycleOwner; 11 | 12 | import com.kunminx.architecture.ui.callback.ProtectedUnPeekLiveData; 13 | import com.kunminx.architecture.ui.callback.UnPeekLiveData; 14 | import com.kunminx.architecture.utils.Utils; 15 | 16 | /** 17 | * Create by KunMinX at 19/10/11 18 | */ 19 | public class NetworkStateManager implements DefaultLifecycleObserver { 20 | 21 | private static final NetworkStateManager S_MANAGER = new NetworkStateManager(); 22 | private UnPeekLiveData networkStateCallback; 23 | private NetworkStateReceive mNetworkStateReceive; 24 | 25 | private NetworkStateManager() { 26 | } 27 | 28 | public static NetworkStateManager getInstance() { 29 | return S_MANAGER; 30 | } 31 | 32 | public ProtectedUnPeekLiveData getNetworkStateCallback() { 33 | if (networkStateCallback == null) networkStateCallback = new UnPeekLiveData<>(); 34 | return networkStateCallback; 35 | } 36 | 37 | @Override 38 | public void onResume(@NonNull LifecycleOwner owner) { 39 | mNetworkStateReceive = new NetworkStateReceive(); 40 | IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); 41 | Utils.getApp().getApplicationContext().registerReceiver(mNetworkStateReceive, filter); 42 | } 43 | 44 | @Override 45 | public void onPause(@NonNull LifecycleOwner owner) { 46 | if (mNetworkStateReceive != null) { 47 | Utils.getApp().getApplicationContext().unregisterReceiver(mNetworkStateReceive); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/data/manager/NetworkStateReceive.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.data.manager; 4 | 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.net.ConnectivityManager; 9 | import android.widget.Toast; 10 | 11 | import com.kunminx.architecture.R; 12 | import com.kunminx.architecture.utils.NetworkUtils; 13 | 14 | import java.util.Objects; 15 | 16 | /** 17 | * Create by KunMinX at 19/8/5 18 | */ 19 | public class NetworkStateReceive extends BroadcastReceiver { 20 | 21 | @Override 22 | public void onReceive(Context context, Intent intent) { 23 | if (Objects.equals(intent.getAction(), ConnectivityManager.CONNECTIVITY_ACTION)) { 24 | if (!NetworkUtils.isConnected()) { 25 | Toast.makeText(context, context.getString(R.string.network_not_good), Toast.LENGTH_SHORT).show(); 26 | } 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/data/usecase/UseCase.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.data.usecase; 4 | 5 | /** 6 | * Use cases are the entry points to the domain layer. 7 | * 8 | * @param the request type 9 | * @param

the response type 10 | */ 11 | public abstract class UseCase { 12 | 13 | private Q mRequestValues; 14 | 15 | private UseCaseCallback

mUseCaseCallback; 16 | 17 | public Q getRequestValues() { 18 | return mRequestValues; 19 | } 20 | 21 | public void setRequestValues(Q requestValues) { 22 | mRequestValues = requestValues; 23 | } 24 | 25 | public UseCaseCallback

getUseCaseCallback() { 26 | return mUseCaseCallback; 27 | } 28 | 29 | public void setUseCaseCallback(UseCaseCallback

useCaseCallback) { 30 | mUseCaseCallback = useCaseCallback; 31 | } 32 | 33 | void run() { 34 | executeUseCase(mRequestValues); 35 | } 36 | 37 | protected abstract void executeUseCase(Q requestValues); 38 | 39 | /** 40 | * Data passed to a request. 41 | */ 42 | public interface RequestValues { 43 | } 44 | 45 | /** 46 | * Data received from a request. 47 | */ 48 | public interface ResponseValue { 49 | } 50 | 51 | public interface UseCaseCallback { 52 | void onSuccess(R response); 53 | 54 | void onError(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/data/usecase/UseCaseScheduler.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.data.usecase; 4 | 5 | /** 6 | * Interface for schedulers, see {@link UseCaseThreadPoolScheduler}. 7 | */ 8 | public interface UseCaseScheduler { 9 | 10 | void execute(Runnable runnable); 11 | 12 | void notifyResponse(final V response, 13 | final UseCase.UseCaseCallback useCaseCallback); 14 | 15 | void onError( 16 | final UseCase.UseCaseCallback useCaseCallback); 17 | } 18 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/data/usecase/UseCaseThreadPoolScheduler.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.data.usecase; 4 | 5 | import android.os.Handler; 6 | 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.LinkedBlockingQueue; 9 | import java.util.concurrent.ThreadPoolExecutor; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * Executes asynchronous tasks using a {@link ThreadPoolExecutor}. 14 | *

15 | * See also {@link Executors} for a list of factory methods to create common 16 | * {@link java.util.concurrent.ExecutorService}s for different scenarios. 17 | */ 18 | public class UseCaseThreadPoolScheduler implements UseCaseScheduler { 19 | 20 | public static final int POOL_SIZE = 2; 21 | public static final int MAX_POOL_SIZE = 4 * 2; 22 | public static final int FIXED_POOL_SIZE = 4; 23 | public static final int TIMEOUT = 30; 24 | final ThreadPoolExecutor mThreadPoolExecutor; 25 | private final Handler mHandler = new Handler(); 26 | 27 | /** 28 | * 固定线程数的无界线程池 29 | */ 30 | public UseCaseThreadPoolScheduler() { 31 | mThreadPoolExecutor = new ThreadPoolExecutor(FIXED_POOL_SIZE, FIXED_POOL_SIZE, TIMEOUT, 32 | TimeUnit.SECONDS, new LinkedBlockingQueue<>()); 33 | } 34 | 35 | @Override 36 | public void execute(Runnable runnable) { 37 | mThreadPoolExecutor.execute(runnable); 38 | } 39 | 40 | @Override 41 | public void notifyResponse(final V response, 42 | final UseCase.UseCaseCallback useCaseCallback) { 43 | mHandler.post(() -> { 44 | if (null != useCaseCallback) { 45 | useCaseCallback.onSuccess(response); 46 | } 47 | }); 48 | } 49 | 50 | @Override 51 | public void onError( 52 | final UseCase.UseCaseCallback useCaseCallback) { 53 | mHandler.post(useCaseCallback::onError); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/kotlin/Event.kt: -------------------------------------------------------------------------------- 1 | package com.kunminx.architecture.kotlin 2 | 3 | import androidx.lifecycle.ViewModelStore 4 | 5 | /** 6 | * @author Flywith24 7 | * @date 2020/6/4 8 | * time 21:10 9 | * description 10 | * 使用 包装类 解决 LiveData 粘性事件的问题 11 | * 详见 https://juejin.im/post/5b2b1b2cf265da5952314b63 12 | */ 13 | open class Event(private val content: T) { 14 | 15 | var hasBeenHandled = false 16 | private set // Allow external read but not write 17 | 18 | private var map = HashMap() 19 | 20 | /** 21 | * Returns the content and prevents its use again. 22 | */ 23 | fun getContentIfNotHandled(): T? { 24 | return if (hasBeenHandled) { 25 | null 26 | } else { 27 | hasBeenHandled = true 28 | content 29 | } 30 | } 31 | 32 | /** 33 | * 根据同观察者判断事件是否消费 34 | * 如果该观察者已消费数据,则返回null 35 | * 否则标记已消费并返回数据 36 | */ 37 | fun getContentIfNotHandled(viewModelStore: ViewModelStore): T? { 38 | return if (map.contains(viewModelStore)) { 39 | null 40 | } else { 41 | map[viewModelStore] = true 42 | content 43 | } 44 | } 45 | 46 | /** 47 | * Returns the content, even if it's already been handled. 48 | */ 49 | fun peekContent(): T = content 50 | } -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/kotlin/WrapperLiveData.kt: -------------------------------------------------------------------------------- 1 | package com.kunminx.architecture.kotlin 2 | 3 | import androidx.annotation.MainThread 4 | import androidx.lifecycle.* 5 | 6 | /** 7 | * @author Flywith24 8 | * @date 2020/6/4 9 | * time 21:13 10 | * description 11 | * 12 | * LiveData 包装类 13 | */ 14 | 15 | //为 LiveData>提供类型别名,使用 EventLiveData 即可 16 | typealias EventMutableLiveData = MutableLiveData> 17 | typealias EventLiveData = LiveData> 18 | 19 | /** 20 | * 事件只能被唯一观察者消费 21 | */ 22 | @MainThread 23 | inline fun EventMutableLiveData.observeEvent( 24 | owner: LifecycleOwner, 25 | crossinline onChanged: (T) -> Unit 26 | ): Observer> { 27 | val wrappedObserver = Observer> { t -> 28 | //数据没有被使用过则发送给调用者,否则不处理 29 | t.getContentIfNotHandled()?.let { data -> 30 | onChanged.invoke(data) 31 | } 32 | } 33 | observe(owner, wrappedObserver) 34 | return wrappedObserver 35 | } 36 | 37 | /** 38 | * 事件可被多个观察者消费,且每个观察者仅能消费一次 39 | */ 40 | @MainThread 41 | inline fun EventMutableLiveData.observeEvent( 42 | owner: LifecycleOwner, 43 | viewModelStore: ViewModelStore, 44 | crossinline onChanged: (T) -> Unit 45 | ): Observer> { 46 | val wrappedObserver = Observer> { t -> 47 | //数据没有被使用过则发送给调用者,否则不处理 48 | t.getContentIfNotHandled(viewModelStore)?.let { data -> 49 | onChanged.invoke(data) 50 | } 51 | } 52 | observe(owner, wrappedObserver) 53 | return wrappedObserver 54 | } 55 | 56 | fun EventMutableLiveData.postEventValue(value: T) { 57 | postValue(Event(value)) 58 | } 59 | 60 | fun EventMutableLiveData.setEventValue(value: T) { 61 | setValue(Event(value)) 62 | 63 | } -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/ui/adapter/CommonViewPagerAdapter.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.ui.adapter; 4 | 5 | 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.annotation.Nullable; 11 | import androidx.viewpager.widget.PagerAdapter; 12 | 13 | /** 14 | * Create by KunMinX at 19/6/15 15 | */ 16 | public class CommonViewPagerAdapter extends PagerAdapter { 17 | 18 | private final int count; 19 | private final boolean enableDestroyItem; 20 | private final String[] title; 21 | 22 | public CommonViewPagerAdapter(int count, boolean enableDestroyItem, String[] title) { 23 | this.count = count; 24 | this.enableDestroyItem = enableDestroyItem; 25 | this.title = title; 26 | } 27 | 28 | @Override 29 | public int getCount() { 30 | return count; 31 | } 32 | 33 | @Override 34 | public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { 35 | return view == object; 36 | } 37 | 38 | @NonNull 39 | @Override 40 | public Object instantiateItem(@NonNull ViewGroup container, int position) { 41 | return container.getChildAt(position); 42 | } 43 | 44 | @Override 45 | public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 46 | if (enableDestroyItem) { 47 | container.removeView((View) object); 48 | } 49 | } 50 | 51 | @Nullable 52 | @Override 53 | public CharSequence getPageTitle(int position) { 54 | return title[position]; 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/ui/adapter/SimpleBindingAdapter.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.ui.adapter; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.LayoutRes; 8 | import androidx.annotation.NonNull; 9 | import androidx.databinding.ViewDataBinding; 10 | import androidx.recyclerview.widget.DiffUtil; 11 | import androidx.recyclerview.widget.RecyclerView; 12 | 13 | /** 14 | * @author KunMinX 15 | * Create at 2018/6/30 16 | */ 17 | public abstract class SimpleBindingAdapter extends BaseBindingAdapter { 18 | 19 | private final int layout; 20 | 21 | public SimpleBindingAdapter(Context context, int layout, @NonNull DiffUtil.ItemCallback diffCallback) { 22 | super(context, diffCallback); 23 | this.layout = layout; 24 | } 25 | 26 | @Override 27 | protected @LayoutRes 28 | int getLayoutResId(int viewType) { 29 | return this.layout; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/ui/binding_adapter/TabPageBindingAdapter.java: -------------------------------------------------------------------------------- 1 | package com.kunminx.architecture.ui.binding_adapter; 2 | 3 | import androidx.databinding.BindingAdapter; 4 | import androidx.viewpager.widget.ViewPager; 5 | 6 | import com.google.android.material.tabs.TabLayout; 7 | import com.kunminx.architecture.R; 8 | import com.kunminx.architecture.ui.adapter.CommonViewPagerAdapter; 9 | 10 | /** 11 | * Create by KunMinX at 2020/3/13 12 | */ 13 | public class TabPageBindingAdapter { 14 | 15 | @BindingAdapter(value = {"initTabAndPage"}, requireAll = false) 16 | public static void initTabAndPage(TabLayout tabLayout, boolean initTabAndPage) { 17 | int count = tabLayout.getTabCount(); 18 | String[] title = new String[count]; 19 | for (int i = 0; i < count; i++) { 20 | TabLayout.Tab tab = tabLayout.getTabAt(i); 21 | if (tab != null && tab.getText() != null) { 22 | title[i] = tab.getText().toString(); 23 | } 24 | } 25 | ViewPager viewPager = (tabLayout.getRootView()).findViewById(R.id.view_pager); 26 | if (viewPager != null) { 27 | viewPager.setAdapter(new CommonViewPagerAdapter(count, false, title)); 28 | tabLayout.setupWithViewPager(viewPager); 29 | } 30 | } 31 | 32 | @BindingAdapter(value = {"tabSelectedListener"}, requireAll = false) 33 | public static void tabSelectedListener(TabLayout tabLayout, TabLayout.OnTabSelectedListener listener) { 34 | tabLayout.addOnTabSelectedListener(listener); 35 | } 36 | 37 | @BindingAdapter(value = {"setOffsetLimit"}) 38 | public static void setOffsetLimit(ViewPager viewPager, int count) { 39 | viewPager.setOffscreenPageLimit(count); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/ui/layout_manager/WrapContentGridLayoutManager.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.ui.layout_manager; 4 | 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | 8 | import androidx.recyclerview.widget.GridLayoutManager; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | /** 12 | * Create by KunMinX at 2020/6/13 13 | */ 14 | public class WrapContentGridLayoutManager extends GridLayoutManager { 15 | 16 | public WrapContentGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 17 | super(context, attrs, defStyleAttr, defStyleRes); 18 | } 19 | 20 | public WrapContentGridLayoutManager(Context context, int spanCount) { 21 | super(context, spanCount); 22 | } 23 | 24 | public WrapContentGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { 25 | super(context, spanCount, orientation, reverseLayout); 26 | } 27 | 28 | @Override 29 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 30 | try { 31 | super.onLayoutChildren(recycler, state); 32 | } catch (IndexOutOfBoundsException e) { 33 | e.printStackTrace(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/ui/layout_manager/WrapContentLinearLayoutManager.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.ui.layout_manager; 4 | 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | 8 | import androidx.recyclerview.widget.LinearLayoutManager; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | /** 12 | * Create by KunMinX at 2020/6/13 13 | */ 14 | public class WrapContentLinearLayoutManager extends LinearLayoutManager { 15 | public WrapContentLinearLayoutManager(Context context) { 16 | super(context); 17 | } 18 | 19 | public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 20 | super(context, orientation, reverseLayout); 21 | } 22 | 23 | public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 24 | super(context, attrs, defStyleAttr, defStyleRes); 25 | } 26 | 27 | @Override 28 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 29 | try { 30 | super.onLayoutChildren(recycler, state); 31 | } catch (IndexOutOfBoundsException e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/ui/layout_manager/WrapContentStaggeredGridLayoutManager.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.ui.layout_manager; 4 | 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | 8 | import androidx.recyclerview.widget.RecyclerView; 9 | import androidx.recyclerview.widget.StaggeredGridLayoutManager; 10 | 11 | /** 12 | * Create by KunMinX at 2020/6/13 13 | */ 14 | public class WrapContentStaggeredGridLayoutManager extends StaggeredGridLayoutManager { 15 | 16 | public WrapContentStaggeredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 17 | super(context, attrs, defStyleAttr, defStyleRes); 18 | } 19 | 20 | public WrapContentStaggeredGridLayoutManager(int spanCount, int orientation) { 21 | super(spanCount, orientation); 22 | } 23 | 24 | @Override 25 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 26 | try { 27 | super.onLayoutChildren(recycler, state); 28 | } catch (IndexOutOfBoundsException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/utils/DisplayUtils.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture.utils; 4 | 5 | /** 6 | * Create by KunMinX at 19/7/20 7 | */ 8 | 9 | public class DisplayUtils { 10 | 11 | /** 12 | * convert px to its equivalent dp 13 | *

14 | * 将px转换为与之相等的dp 15 | */ 16 | public static int px2dp(float pxValue) { 17 | final float scale = Utils.getApp().getResources().getDisplayMetrics().density; 18 | return (int) (pxValue / scale + 0.5f); 19 | } 20 | 21 | 22 | /** 23 | * convert dp to its equivalent px 24 | *

25 | * 将dp转换为与之相等的px 26 | */ 27 | public static int dp2px(float dipValue) { 28 | final float scale = Utils.getApp().getResources().getDisplayMetrics().density; 29 | return (int) (dipValue * scale + 0.5f); 30 | } 31 | 32 | 33 | /** 34 | * convert px to its equivalent sp 35 | *

36 | * 将px转换为sp 37 | */ 38 | public static int px2sp(float pxValue) { 39 | final float fontScale = Utils.getApp().getResources().getDisplayMetrics().scaledDensity; 40 | return (int) (pxValue / fontScale + 0.5f); 41 | } 42 | 43 | 44 | /** 45 | * convert sp to its equivalent px 46 | *

47 | * 将sp转换为px 48 | */ 49 | public static int sp2px(float spValue) { 50 | final float fontScale = Utils.getApp().getResources().getDisplayMetrics().scaledDensity; 51 | return (int) (spValue * fontScale + 0.5f); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /architecture/src/main/java/com/kunminx/architecture/utils/Etx.kt: -------------------------------------------------------------------------------- 1 | package com.kunminx.architecture.utils 2 | 3 | import android.widget.ImageView 4 | import com.bumptech.glide.Glide 5 | 6 | /** 7 | * @author Flywith24 8 | * @date 2020/5/30 9 | * time 20:53 10 | * description 11 | * 扩展函数 12 | */ 13 | 14 | fun ImageView.loadImage(url: String) { 15 | Glide.with(context) 16 | .load(url) 17 | .into(this) 18 | } -------------------------------------------------------------------------------- /architecture/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /architecture/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 网络不给力 6 | 7 | 8 | -------------------------------------------------------------------------------- /architecture/src/main/res/values/values.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /architecture/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /architecture/src/test/java/com/kunminx/architecture/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.architecture; 4 | 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | /** 10 | * Example local unit test, which will execute on the development machine (host). 11 | * 12 | * @see Testing documentation 13 | */ 14 | public class ExampleUnitTest { 15 | @Test 16 | public void addition_isCorrect() { 17 | assertEquals(4, 2 + 2); 18 | } 19 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | kotlin_version = '1.4.0' 6 | } 7 | repositories { 8 | google() 9 | maven { url 'https://maven.aliyun.com/repository/jcenter' } 10 | } 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:4.0.1' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | maven { url 'https://maven.aliyun.com/repository/jcenter' } 21 | } 22 | } 23 | 24 | task clean(type: Delete) { 25 | delete rootProject.buildDir 26 | } 27 | -------------------------------------------------------------------------------- /common_res/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /common_res/build.gradle: -------------------------------------------------------------------------------- 1 | import com.flywith24.version_config.BuildConfig 2 | import com.flywith24.version_config.dependencies.AndroidX 3 | import com.flywith24.version_config.dependencies.Google 4 | 5 | plugins { 6 | id "com.flywith24.version" 7 | } 8 | apply plugin: 'com.android.library' 9 | apply plugin: 'kotlin-android' 10 | 11 | android { 12 | compileSdkVersion BuildConfig.compileSdkVersion 13 | buildToolsVersion BuildConfig.buildToolsVersion 14 | 15 | defaultConfig { 16 | minSdkVersion BuildConfig.minSdkVersion 17 | targetSdkVersion BuildConfig.targetSdkVersion 18 | versionCode BuildConfig.versionCode 19 | versionName BuildConfig.versionName 20 | 21 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 22 | consumerProguardFiles "consumer-rules.pro" 23 | } 24 | 25 | buildTypes { 26 | release { 27 | minifyEnabled false 28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 29 | } 30 | } 31 | } 32 | 33 | dependencies { 34 | implementation fileTree(dir: "libs", include: ["*.jar"]) 35 | implementation(AndroidX.constraintlayout) 36 | implementation(AndroidX.recyclerView) 37 | implementation(AndroidX.appcompat) 38 | implementation(Google.material) 39 | 40 | } -------------------------------------------------------------------------------- /common_res/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/consumer-rules.pro -------------------------------------------------------------------------------- /common_res/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 -------------------------------------------------------------------------------- /common_res/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /common_res/src/main/res/anim/h_fragment_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /common_res/src/main/res/anim/h_fragment_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /common_res/src/main/res/anim/h_fragment_pop_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /common_res/src/main/res/anim/h_fragment_pop_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-anydpi/ic_add.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-anydpi/ic_back.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-anydpi/ic_menu_save.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-anydpi/round_solid_gray.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-hdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-hdpi/ic_add.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-hdpi/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-hdpi/ic_back.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-hdpi/ic_menu_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-hdpi/ic_menu_save.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-mdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-mdpi/ic_add.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-mdpi/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-mdpi/ic_back.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-mdpi/ic_menu_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-mdpi/ic_menu_save.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-xhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-xhdpi/ic_add.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-xhdpi/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-xhdpi/ic_back.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-xhdpi/ic_menu_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-xhdpi/ic_menu_save.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-xxhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-xxhdpi/ic_add.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-xxhdpi/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-xxhdpi/ic_back.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable-xxhdpi/ic_menu_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/common_res/src/main/res/drawable-xxhdpi/ic_menu_save.png -------------------------------------------------------------------------------- /common_res/src/main/res/drawable/ripple_click.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /common_res/src/main/res/drawable/round_stroke_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /common_res/src/main/res/menu/editor_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |

5 | 10 | -------------------------------------------------------------------------------- /common_res/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #000 5 | #ccc 6 | #55eeeeee 7 | #1E90FF 8 | #00000000 9 | #505b91 10 | #fff 11 | -------------------------------------------------------------------------------- /common_res/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 测试 Lifecycles,请点击 \'添加定位\' 4 | 测试 LiveData,请点击 \'添加定位\' 5 | 添加定位 6 | 选择位置 7 | image 8 | 位置 9 | 动态列表 10 | 刚刚在B站发表了最新一期的视频讲解,感兴趣的小伙伴可前往查阅 11 | 12 | 请输入动态 13 | 发布动态 14 | ViewModel 组件示例 item 点击不提供跳转,下一个组件示例(DataBinding)提供跳转 15 | 保存 16 | Lifecycle 组件示例不提供保存功能,具体会在 DataBinding 组件示例开始提供 17 | liveData 组件示例不提供保存功能,具体会在 DataBinding 组件示例开始提供 18 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | android.injected.testOnly=false 21 | android.databinding.incremental=true 22 | android.lifecycleProcessor.incremental=true 23 | kapt.incremental.apt=true 24 | kapt.use.worker.api=true 25 | kapt.include.compile.classpath=false 26 | org.gradle.parallel=true 27 | org.gradle.caching=true 28 | org.gradle.configureondemand=true 29 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 16 14:42:29 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /jetpack_java/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /jetpack_java/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/jetpack_java/consumer-rules.pro -------------------------------------------------------------------------------- /jetpack_java/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 22 | -------------------------------------------------------------------------------- /jetpack_java/src/androidTest/java/com/kunminx/jetpack_java/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.kunminx.jetpack_java; 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 | 25 | assertEquals("com.example.jetpack_java.test", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jetpack_java/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/common_data/APIs.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.common_data; 4 | 5 | /** 6 | * TODO:本示例专注于提供 Jetpack 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 7 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 8 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 9 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 10 | *

11 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 12 | *

13 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 14 | *

15 | *

16 | * Create by KunMinX at 2020/5/29 17 | */ 18 | public class APIs { 19 | 20 | public static final String KUNMINX_URL = "https://upload.jianshu.io/users/upload_avatars/57036/3e7ae7bc-9b9b-46c8-8082-bb2481d979dc.jpg"; 21 | 22 | public static final String FLYWITH24_URL = "https://upload-images.jianshu.io/upload_images/57036-48e9886afe74ea9b.jpeg"; 23 | 24 | public static final String SCENE_URL = "https://upload-images.jianshu.io/upload_images/57036-99344035bfce65b8.jpeg"; 25 | 26 | public static final String ADD_PIC_TIP_URL = "https://upload-images.jianshu.io/upload_images/57036-0c120ced543d506a.png"; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/common_data/Configs.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.common_data; 4 | 5 | /** 6 | * TODO:本示例专注于提供 Jetpack 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 7 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 8 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 9 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 10 | *

11 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 12 | *

13 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 14 | *

15 | *

16 | * Create by KunMinX at 2020/5/30 17 | */ 18 | public class Configs { 19 | 20 | public final static int REQUEST_LOCATION_INFO = 0x00001; 21 | public final static int REQUEST_NEW_MOMENT = 0x00002; 22 | public final static String NEW_MOMENT = "NEW_MOMENT"; 23 | public final static String LOCATION_RESULT = "LOCATION_RESULT"; 24 | public final static String THIS_MOMENT = "THIS_MOMENT"; 25 | } 26 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/common_data/bean/LocationBean.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.common_data.bean; 4 | 5 | 6 | /** 7 | * TODO:本示例专注于提供 Jetpack 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 8 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 9 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 10 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 11 | *

12 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 13 | *

14 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 15 | *

16 | *

17 | * Create by KunMinX at 2020/5/29 18 | */ 19 | public class LocationBean { 20 | 21 | private String locationName; 22 | 23 | public LocationBean(String locationName) { 24 | this.locationName = locationName; 25 | } 26 | 27 | public String getLocationName() { 28 | return locationName; 29 | } 30 | 31 | public void setLocationName(String locationName) { 32 | this.locationName = locationName; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/common_ui/adapter/DiffUtilCallbacks.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.common_ui.adapter; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.recyclerview.widget.DiffUtil; 7 | 8 | import com.kunminx.jetpack_java.common_data.bean.LocationBean; 9 | import com.kunminx.jetpack_java.common_data.bean.Moment; 10 | 11 | /** 12 | * TODO:本示例专注于提供 Jetpack 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 13 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 14 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 15 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 16 | *

17 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 18 | *

19 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 20 | *

21 | *

22 | * Create by KunMinX at 2020/6/1 23 | */ 24 | public class DiffUtilCallbacks { 25 | 26 | public DiffUtil.ItemCallback getLocationBeanItemCallback() { 27 | return new DiffUtil.ItemCallback() { 28 | @Override 29 | public boolean areItemsTheSame(@NonNull LocationBean oldItem, @NonNull LocationBean newItem) { 30 | return oldItem.equals(newItem); 31 | } 32 | 33 | @Override 34 | public boolean areContentsTheSame(@NonNull LocationBean oldItem, @NonNull LocationBean newItem) { 35 | return oldItem.getLocationName().equals(newItem.getLocationName()); 36 | } 37 | }; 38 | } 39 | 40 | public DiffUtil.ItemCallback getMomentItemCallback() { 41 | return new DiffUtil.ItemCallback() { 42 | @Override 43 | public boolean areItemsTheSame(@NonNull Moment oldItem, @NonNull Moment newItem) { 44 | return oldItem.equals(newItem); 45 | } 46 | 47 | @Override 48 | public boolean areContentsTheSame(@NonNull Moment oldItem, @NonNull Moment newItem) { 49 | return oldItem.getUuid().equals(newItem.getUuid()); 50 | } 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_01_lifecycles/ui/LifecycleLocationActivity.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_01_lifecycles.ui; 4 | 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | 8 | import androidx.appcompat.widget.Toolbar; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.kunminx.architecture.ui.BaseActivity; 12 | import com.kunminx.architecture.ui.layout_manager.WrapContentLinearLayoutManager; 13 | import com.kunminx.jetpack_java.R; 14 | import com.kunminx.jetpack_java.common_data.Configs; 15 | import com.kunminx.jetpack_java.common_ui.adapter.LocationAdapter; 16 | import com.kunminx.jetpack_java.sample_01_lifecycles.domain.LifecycleLocationManager; 17 | 18 | /** 19 | * TODO:本示例专注于提供 Lifecycle 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 20 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 21 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 22 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 23 | *

24 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 25 | *

26 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 27 | *

28 | *

29 | * Create by KunMinX at 19/10/16 30 | */ 31 | 32 | public class LifecycleLocationActivity extends BaseActivity { 33 | 34 | private RecyclerView mRecyclerView; 35 | private Toolbar mToolbar; 36 | private LocationAdapter mLocationAdapter; 37 | 38 | @Override 39 | protected void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | 42 | setContentView(R.layout.activity_location_lifecycles); 43 | mToolbar = findViewById(R.id.toolbar); 44 | mToolbar.setNavigationOnClickListener(v -> finish()); 45 | 46 | mRecyclerView = findViewById(R.id.rv); 47 | mRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(getApplicationContext())); 48 | 49 | mRecyclerView.setAdapter(mLocationAdapter = new LocationAdapter(getApplicationContext(), locationBean -> { 50 | Intent intent = new Intent(); 51 | intent.putExtra(Configs.LOCATION_RESULT, locationBean.getLocationName()); 52 | setResult(RESULT_OK, intent); 53 | finish(); 54 | })); 55 | 56 | getLifecycle().addObserver(LifecycleLocationManager.getInstance()); 57 | 58 | LifecycleLocationManager.getInstance().setILocationCallback(list -> { 59 | runOnUiThread(() -> { 60 | mLocationAdapter.submitList(list); 61 | }); 62 | }); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_02_livedata/domain/LiveDataLocationManager.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_02_livedata.domain; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.lifecycle.DefaultLifecycleObserver; 7 | import androidx.lifecycle.LifecycleOwner; 8 | import androidx.lifecycle.LiveData; 9 | import androidx.lifecycle.MutableLiveData; 10 | 11 | import com.kunminx.jetpack_java.common_data.bean.LocationBean; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Timer; 16 | import java.util.TimerTask; 17 | 18 | /** 19 | * TODO:本示例专注于提供 LiveData 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 20 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 21 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 22 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 23 | *

24 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 25 | *

26 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 27 | *

28 | *

29 | * 30 | * Create by KunMinX at 2020/5/30 31 | */ 32 | public class LiveDataLocationManager implements DefaultLifecycleObserver { 33 | 34 | private static LiveDataLocationManager sManager = new LiveDataLocationManager(); 35 | 36 | private Timer mTimer; 37 | 38 | public static LiveDataLocationManager getInstance() { 39 | return sManager; 40 | } 41 | 42 | private LiveDataLocationManager() { 43 | } 44 | 45 | private MutableLiveData> mLocationBeans = new MutableLiveData<>(); 46 | 47 | private List mList = new ArrayList<>(); 48 | 49 | public LiveData> getLocationBeans() { 50 | return mLocationBeans; 51 | } 52 | 53 | @Override 54 | public void onResume(@NonNull LifecycleOwner owner) { 55 | //TODO 我是获取附近位置列表信息的后台定位服务,我耗电巨大,我随着页面的 onResume 开启了 56 | 57 | mTimer = new Timer(); 58 | 59 | TimerTask task = new TimerTask() { 60 | @Override 61 | public void run() { 62 | 63 | //模拟定位,假设开启了 GPS 并且每秒获取若干条新的位置信息 64 | 65 | mList.add(new LocationBean("台北夜市 " + System.currentTimeMillis() + " 号")); 66 | mLocationBeans.postValue(mList); 67 | 68 | onResume(owner); 69 | } 70 | }; 71 | 72 | mTimer.schedule(task, 200); 73 | 74 | } 75 | 76 | @Override 77 | public void onPause(@NonNull LifecycleOwner owner) { 78 | //TODO 定位服务随着页面的 onPause 而关闭了 79 | 80 | mTimer.cancel(); 81 | mTimer = null; 82 | 83 | mList.clear(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_02_livedata/ui/LiveDataLocationActivity.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_02_livedata.ui; 4 | 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | 8 | import androidx.appcompat.widget.Toolbar; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.kunminx.architecture.ui.BaseActivity; 12 | import com.kunminx.architecture.ui.layout_manager.WrapContentLinearLayoutManager; 13 | import com.kunminx.jetpack_java.R; 14 | import com.kunminx.jetpack_java.common_data.Configs; 15 | import com.kunminx.jetpack_java.common_ui.adapter.LocationAdapter; 16 | import com.kunminx.jetpack_java.sample_02_livedata.domain.LiveDataLocationManager; 17 | 18 | /** 19 | * TODO:本示例专注于提供 LiveData 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 20 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 21 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 22 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 23 | *

24 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 25 | *

26 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 27 | *

28 | *

29 | * Create by KunMinX at 19/10/16 30 | */ 31 | 32 | public class LiveDataLocationActivity extends BaseActivity { 33 | 34 | private RecyclerView mRecyclerView; 35 | private Toolbar mToolbar; 36 | 37 | private LocationAdapter mLocationAdapter; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | 43 | setContentView(R.layout.activity_location_lifecycles); 44 | mToolbar = findViewById(R.id.toolbar); 45 | mToolbar.setNavigationOnClickListener(v -> finish()); 46 | 47 | mRecyclerView = findViewById(R.id.rv); 48 | mRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(getApplicationContext())); 49 | 50 | mRecyclerView.setAdapter(mLocationAdapter = new LocationAdapter(getApplicationContext(), locationBean -> { 51 | Intent intent = new Intent(); 52 | intent.putExtra(Configs.LOCATION_RESULT, locationBean.getLocationName()); 53 | setResult(RESULT_OK, intent); 54 | finish(); 55 | })); 56 | 57 | getLifecycle().addObserver(LiveDataLocationManager.getInstance()); 58 | 59 | LiveDataLocationManager.getInstance().getLocationBeans().observe(this, locationBeans -> { 60 | mLocationAdapter.submitList(locationBeans); 61 | }); 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_03_viewmodel/domain/BaseRequest.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_03_viewmodel.domain; 4 | 5 | import androidx.lifecycle.LiveData; 6 | 7 | import com.kunminx.jetpack_java.common_data.bean.Moment; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * TODO:本示例专注于提供 ViewModel 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 13 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 14 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 15 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 16 | *

17 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 18 | *

19 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 20 | *

21 | *

22 | * Create by KunMinX at 2020/5/30 23 | */ 24 | public class BaseRequest { 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_03_viewmodel/domain/MomentRequest.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_03_viewmodel.domain; 4 | 5 | import androidx.lifecycle.LiveData; 6 | import androidx.lifecycle.MutableLiveData; 7 | 8 | import com.kunminx.jetpack_java.sample_03_viewmodel.data.DataRepository; 9 | import com.kunminx.jetpack_java.common_data.bean.Moment; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * TODO:本示例专注于提供 ViewModel 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 15 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 16 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 17 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 18 | *

19 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 20 | *

21 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 22 | *

23 | *

24 | * Create by KunMinX at 2020/5/30 25 | */ 26 | public class MomentRequest extends BaseRequest { 27 | 28 | private MutableLiveData> mListMutableLiveData; 29 | 30 | public LiveData> getListMutableLiveData() { 31 | if (mListMutableLiveData == null) { 32 | mListMutableLiveData = new MutableLiveData<>(); 33 | } 34 | return mListMutableLiveData; 35 | } 36 | 37 | public void requestList() { 38 | DataRepository.getInstance().requestList(mListMutableLiveData); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_03_viewmodel/ui/ViewModelListActivity.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_03_viewmodel.ui; 4 | 5 | import android.os.Bundle; 6 | 7 | import androidx.appcompat.widget.Toolbar; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import com.kunminx.architecture.ui.BaseActivity; 11 | import com.kunminx.architecture.ui.layout_manager.WrapContentLinearLayoutManager; 12 | import com.kunminx.jetpack_java.R; 13 | import com.kunminx.jetpack_java.common_ui.adapter.MomentAdapter; 14 | import com.kunminx.jetpack_java.sample_03_viewmodel.ui.state.ListViewModel; 15 | 16 | /** 17 | * TODO:本示例专注于提供 ViewModel 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 18 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 19 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 20 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 21 | *

22 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 23 | *

24 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 25 | *

26 | *

27 | * Create by KunMinX at 19/10/16 28 | */ 29 | 30 | public class ViewModelListActivity extends BaseActivity { 31 | 32 | private ListViewModel mListViewModel; 33 | private RecyclerView mRecyclerView; 34 | private Toolbar mToolbar; 35 | private MomentAdapter mMomentAdapter; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | mListViewModel = getActivityScopeViewModel(ListViewModel.class); 41 | 42 | setContentView(R.layout.activity_list_viewmodel); 43 | mToolbar = findViewById(R.id.toolbar); 44 | mToolbar.setNavigationOnClickListener(v -> finish()); 45 | 46 | mRecyclerView = findViewById(R.id.rv); 47 | mRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(getApplicationContext())); 48 | 49 | mRecyclerView.setAdapter(mMomentAdapter = new MomentAdapter(getApplicationContext(), moment -> { 50 | showLongToast(getString(R.string.viewmodel_item_click_tip)); 51 | })); 52 | 53 | mListViewModel.momentRequest.getListMutableLiveData().observe(this, moments -> { 54 | mMomentAdapter.submitList(moments); 55 | }); 56 | 57 | mListViewModel.momentRequest.requestList(); 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_03_viewmodel/ui/state/ListViewModel.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_03_viewmodel.ui.state; 4 | 5 | import androidx.lifecycle.LiveData; 6 | import androidx.lifecycle.ViewModel; 7 | 8 | import com.kunminx.jetpack_java.common_data.bean.Moment; 9 | import com.kunminx.jetpack_java.sample_03_viewmodel.domain.MomentRequest; 10 | import com.kunminx.jetpack_java.sample_03_viewmodel.domain.BaseRequest; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * TODO:本示例专注于提供 ViewModel 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 16 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 17 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 18 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 19 | *

20 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 21 | *

22 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 23 | *

24 | *

25 | * Create by KunMinX at 2020/5/30 26 | */ 27 | public class ListViewModel extends ViewModel { 28 | 29 | public final MomentRequest momentRequest = new MomentRequest(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_04_databinding/ui/DataBindingDetailActivity.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_04_databinding.ui; 4 | 5 | import android.os.Bundle; 6 | 7 | import androidx.databinding.DataBindingUtil; 8 | 9 | import com.kunminx.architecture.ui.BaseActivity; 10 | import com.kunminx.jetpack_java.R; 11 | import com.kunminx.jetpack_java.common_data.Configs; 12 | import com.kunminx.jetpack_java.common_data.bean.Moment; 13 | import com.kunminx.jetpack_java.databinding.ActivityDetailDatabindingBinding; 14 | import com.kunminx.jetpack_java.sample_04_databinding.ui.state.DetailViewModel; 15 | 16 | /** 17 | * TODO:本示例专注于提供 DataBinding 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 18 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 19 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 20 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 21 | *

22 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 23 | *

24 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 25 | *

26 | *

27 | * Create by KunMinX at 19/10/16 28 | */ 29 | 30 | public class DataBindingDetailActivity extends BaseActivity { 31 | 32 | private DetailViewModel mDetailViewModel; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | mDetailViewModel = getActivityScopeViewModel(DetailViewModel.class); 38 | 39 | ActivityDetailDatabindingBinding binding = 40 | DataBindingUtil.setContentView(this, R.layout.activity_detail_databinding); 41 | binding.setLifecycleOwner(this); 42 | binding.setVm(mDetailViewModel); 43 | binding.setClick(new ClickProxy()); 44 | 45 | Moment moment = (Moment) getIntent().getParcelableExtra(Configs.THIS_MOMENT); 46 | mDetailViewModel.initState(moment); 47 | 48 | } 49 | 50 | public class ClickProxy { 51 | public void back() { 52 | finish(); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_04_databinding/ui/adapter/DataBindingLocationAdapter.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_04_databinding.ui.adapter; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.DiffUtil; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.kunminx.jetpack_java.R; 12 | import com.kunminx.jetpack_java.common_data.bean.LocationBean; 13 | import com.kunminx.jetpack_java.common_ui.adapter.DiffUtilCallbacks; 14 | import com.kunminx.jetpack_java.databinding.AdapterLocationDatabindingBinding; 15 | import com.kunminx.architecture.ui.adapter.SimpleBindingAdapter; 16 | 17 | /** 18 | * TODO:本示例专注于提供 DataBinding 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 19 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 20 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 21 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 22 | *

23 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 24 | *

25 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 26 | *

27 | *

28 | * Create by KunMinX at 2020/5/31 29 | */ 30 | public class DataBindingLocationAdapter extends SimpleBindingAdapter { 31 | 32 | public DataBindingLocationAdapter(Context context) { 33 | super(context, R.layout.adapter_location_databinding, new DiffUtilCallbacks().getLocationBeanItemCallback()); 34 | } 35 | 36 | @Override 37 | protected void onBindItem(AdapterLocationDatabindingBinding binding, LocationBean item, RecyclerView.ViewHolder holder) { 38 | binding.setBean(item); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_04_databinding/ui/adapter/DataBindingMomentAdapter.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_04_databinding.ui.adapter; 4 | 5 | import android.content.Context; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.DiffUtil; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.kunminx.jetpack_java.R; 12 | import com.kunminx.jetpack_java.common_data.bean.Moment; 13 | import com.kunminx.jetpack_java.common_ui.adapter.DiffUtilCallbacks; 14 | import com.kunminx.jetpack_java.databinding.AdapterMomentDatabindingBinding; 15 | import com.kunminx.architecture.ui.adapter.SimpleBindingAdapter; 16 | 17 | /** 18 | * TODO:本示例专注于提供 DataBinding 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 19 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 20 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 21 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 22 | *

23 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 24 | *

25 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 26 | *

27 | *

28 | * Create by KunMinX at 2020/5/31 29 | */ 30 | public class DataBindingMomentAdapter extends SimpleBindingAdapter { 31 | 32 | public DataBindingMomentAdapter(Context context) { 33 | super(context, R.layout.adapter_moment_databinding, new DiffUtilCallbacks().getMomentItemCallback()); 34 | } 35 | 36 | @Override 37 | protected void onBindItem(AdapterMomentDatabindingBinding binding, Moment item, RecyclerView.ViewHolder holder) { 38 | binding.setMoment(item); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_04_databinding/ui/state/DetailViewModel.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_04_databinding.ui.state; 4 | 5 | import androidx.databinding.ObservableField; 6 | import androidx.lifecycle.ViewModel; 7 | 8 | import com.kunminx.jetpack_java.common_data.bean.Moment; 9 | 10 | /** 11 | * TODO:本示例专注于提供 DataBinding 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 12 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 13 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 14 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 15 | *

16 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 17 | *

18 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 19 | *

20 | *

21 | * Create by KunMinX at 2020/5/30 22 | */ 23 | public class DetailViewModel extends ViewModel { 24 | 25 | public final ObservableField imgUrl = new ObservableField<>(); 26 | public final ObservableField name = new ObservableField<>(); 27 | public final ObservableField content = new ObservableField<>(); 28 | public final ObservableField location = new ObservableField<>(); 29 | public final ObservableField avatar = new ObservableField<>(); 30 | 31 | public void initState(Moment moment) { 32 | avatar.set(moment.getUserAvatar()); 33 | name.set(moment.getUserName()); 34 | content.set(moment.getContent()); 35 | imgUrl.set(moment.getImgUrl()); 36 | location.set(moment.getLocation()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_04_databinding/ui/state/EditorViewModel.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_04_databinding.ui.state; 4 | 5 | import androidx.databinding.ObservableField; 6 | import androidx.lifecycle.ViewModel; 7 | 8 | import com.kunminx.jetpack_java.common_data.APIs; 9 | 10 | /** 11 | * TODO:本示例专注于提供 DataBinding 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 12 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 13 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 14 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 15 | *

16 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 17 | *

18 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 19 | *

20 | *

21 | * Create by KunMinX at 2020/5/30 22 | */ 23 | public class EditorViewModel extends ViewModel { 24 | 25 | public final ObservableField imgUrl = new ObservableField<>(); 26 | public final ObservableField content = new ObservableField<>(); 27 | public final ObservableField location = new ObservableField<>(); 28 | 29 | { 30 | location.set("添加定位"); 31 | content.set(""); 32 | imgUrl.set(APIs.ADD_PIC_TIP_URL); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_04_databinding/ui/state/ListViewModel.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_04_databinding.ui.state; 4 | 5 | import androidx.lifecycle.LiveData; 6 | import androidx.lifecycle.MutableLiveData; 7 | import androidx.lifecycle.ViewModel; 8 | 9 | import com.kunminx.jetpack_java.common_data.bean.Moment; 10 | import com.kunminx.jetpack_java.sample_03_viewmodel.domain.MomentRequest; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * TODO:本示例专注于提供 DataBinding 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 16 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 17 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 18 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 19 | *

20 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 21 | *

22 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 23 | *

24 | *

25 | * Create by KunMinX at 2020/5/30 26 | */ 27 | public class ListViewModel extends ViewModel { 28 | 29 | public final MutableLiveData> list = new MutableLiveData<>(); 30 | 31 | public final MutableLiveData autoScrollToTopWhenInsert = new MutableLiveData<>(true); 32 | 33 | public final MomentRequest momentRequest = new MomentRequest(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_04_databinding/ui/state/LocationViewModel.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_04_databinding.ui.state; 4 | 5 | import androidx.lifecycle.MutableLiveData; 6 | import androidx.lifecycle.ViewModel; 7 | 8 | import com.kunminx.jetpack_java.common_data.bean.LocationBean; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * TODO:本示例专注于提供 DataBinding 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 14 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 15 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 16 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 17 | *

18 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 19 | *

20 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 21 | *

22 | *

23 | * Create by KunMinX at 2020/5/30 24 | */ 25 | public class LocationViewModel extends ViewModel { 26 | 27 | public final MutableLiveData> list = new MutableLiveData<>(); 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_05_navigation/ui/NavigationDetailFragment.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_05_navigation.ui; 4 | 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.annotation.Nullable; 12 | 13 | import com.kunminx.jetpack_java.R; 14 | import com.kunminx.jetpack_java.common_data.Configs; 15 | import com.kunminx.jetpack_java.common_data.bean.Moment; 16 | import com.kunminx.jetpack_java.databinding.FragmentDetailNavigationBinding; 17 | import com.kunminx.jetpack_java.sample_04_databinding.ui.state.DetailViewModel; 18 | import com.kunminx.architecture.ui.BaseFragment; 19 | 20 | /** 21 | * TODO:本示例专注于提供 Navigation 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 22 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 23 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 24 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 25 | *

26 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 27 | *

28 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 29 | *

30 | *

31 | * Create by KunMinX at 2020/5/30 32 | */ 33 | public class NavigationDetailFragment extends BaseFragment { 34 | 35 | private DetailViewModel mDetailState; 36 | 37 | @Override 38 | public void onCreate(@Nullable Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | mDetailState = getFragmentScopeViewModel(DetailViewModel.class); 41 | } 42 | 43 | @Nullable 44 | @Override 45 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 46 | View view = inflater.inflate(R.layout.fragment_detail_navigation, container, false); 47 | FragmentDetailNavigationBinding binding = FragmentDetailNavigationBinding.bind(view); 48 | binding.setLifecycleOwner(this); 49 | binding.setVm(mDetailState); 50 | binding.setClick(new ClickProxy()); 51 | return view; 52 | } 53 | 54 | @Override 55 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 56 | super.onViewCreated(view, savedInstanceState); 57 | 58 | Moment moment = (Moment) getArguments().getParcelable(Configs.THIS_MOMENT); 59 | mDetailState.initState(moment); 60 | } 61 | 62 | public class ClickProxy { 63 | public void back() { 64 | nav().navigateUp(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_05_navigation/ui/NavigationMainActivity.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_05_navigation.ui; 4 | 5 | import android.os.Bundle; 6 | 7 | import androidx.databinding.DataBindingUtil; 8 | 9 | import com.kunminx.architecture.ui.BaseActivity; 10 | import com.kunminx.jetpack_java.R; 11 | import com.kunminx.jetpack_java.sample_05_navigation.ui.callback.SharedViewModel; 12 | 13 | /** 14 | * TODO:本示例专注于提供 Navigation 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 15 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 16 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 17 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 18 | *

19 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 20 | *

21 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 22 | *

23 | *

24 | * Create by KunMinX at 19/10/16 25 | */ 26 | 27 | public class NavigationMainActivity extends BaseActivity { 28 | 29 | private SharedViewModel mPageCallback; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | 35 | mPageCallback = getActivityScopeViewModel(SharedViewModel.class); 36 | 37 | DataBindingUtil.setContentView(this, R.layout.activity_main_navigation); 38 | 39 | mPageCallback.getCloseActivity().observeInActivity(this, aBoolean -> { 40 | finish(); 41 | }); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_05_navigation/ui/callback/SharedViewModel.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_05_navigation.ui.callback; 4 | 5 | import androidx.lifecycle.ViewModel; 6 | 7 | import com.kunminx.architecture.ui.callback.ProtectedUnPeekLiveData; 8 | import com.kunminx.architecture.ui.callback.UnPeekLiveData; 9 | import com.kunminx.jetpack_java.common_data.bean.Moment; 10 | 11 | /** 12 | * TODO:本示例专注于提供 Navigation 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 13 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 14 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 15 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 16 | *

17 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 18 | *

19 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 20 | *

21 | *

22 | * Create by KunMinX at 2020/5/30 23 | */ 24 | public class SharedViewModel extends ViewModel { 25 | 26 | private UnPeekLiveData location; 27 | private UnPeekLiveData moment; 28 | private UnPeekLiveData closeActivity; 29 | 30 | public ProtectedUnPeekLiveData getLocation() { 31 | if (location == null) location = new UnPeekLiveData<>(); 32 | return location; 33 | } 34 | 35 | public ProtectedUnPeekLiveData getMoment() { 36 | if (moment == null) moment = new UnPeekLiveData<>(); 37 | return moment; 38 | } 39 | 40 | public ProtectedUnPeekLiveData getCloseActivity() { 41 | if (closeActivity == null) closeActivity = new UnPeekLiveData<>(); 42 | return closeActivity; 43 | } 44 | 45 | public void requestAddMoment(Moment moment) { 46 | this.moment.setValue(moment); 47 | } 48 | 49 | public void requestCloseActivity() { 50 | this.closeActivity.setValue(true); 51 | } 52 | 53 | public void requestAddLocation(String locationName) { 54 | this.location.setValue(locationName); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_one_more_thing/ui/OneMoreThingActivity.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_one_more_thing.ui; 4 | 5 | import android.os.Bundle; 6 | 7 | import androidx.databinding.DataBindingUtil; 8 | 9 | import com.kunminx.architecture.ui.BaseActivity; 10 | import com.kunminx.jetpack_java.R; 11 | import com.kunminx.jetpack_java.databinding.ActivityOneMoreThingBinding; 12 | import com.kunminx.jetpack_java.sample_one_more_thing.ui.state.OneMoreThingViewModel; 13 | 14 | /** 15 | * TODO:本示例专注于提供 Jetpack 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 16 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 17 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 18 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 19 | *

20 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 21 | *

22 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 23 | *

24 | *

25 | * Create by KunMinX at 19/10/16 26 | */ 27 | 28 | public class OneMoreThingActivity extends BaseActivity { 29 | 30 | private OneMoreThingViewModel mOneMoreThingViewModel; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | 36 | mOneMoreThingViewModel = getActivityScopeViewModel(OneMoreThingViewModel.class); 37 | 38 | ActivityOneMoreThingBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_one_more_thing); 39 | binding.setLifecycleOwner(this); 40 | binding.setVm(mOneMoreThingViewModel); 41 | binding.setClick(new ClickProxy()); 42 | } 43 | 44 | public class ClickProxy { 45 | public void back() { 46 | finish(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /jetpack_java/src/main/java/com/kunminx/jetpack_java/sample_one_more_thing/ui/state/OneMoreThingViewModel.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.kunminx.jetpack_java.sample_one_more_thing.ui.state; 4 | 5 | import androidx.databinding.ObservableField; 6 | import androidx.lifecycle.ViewModel; 7 | 8 | /** 9 | * TODO:本示例专注于提供 Jetpack 组件的使用场景和示例,因而其他内容均保持 Android 引入 Jetpack 前的模样, 10 | * kotlin 模块提供同样的场景和基于 Kotlin 的写法,可对照查阅。 11 | * 并且本项目的示例从 sample_01 到 sample_05 是循序渐进地 Jetpack 化, 12 | * 如看完对 Jetpack 高频核心组件 "为什么要用"、"为什么要这样用" 有了一丝丝好奇心,可前往《Jetpack MVVM 精讲》和《Jetpack MVVM 最佳实践》项目查阅深度解析。 13 | *

14 | * https://juejin.im/post/5dafc49b6fb9a04e17209922 15 | *

16 | * https://github.com/KunMinX/Jetpack-MVVM-Best-Practice 17 | *

18 | *

19 | * Create by KunMinX at 2020/6/1 20 | */ 21 | public class OneMoreThingViewModel extends ViewModel { 22 | 23 | public final ObservableField pageAssetPath = new ObservableField<>(); 24 | 25 | { 26 | pageAssetPath.set("best_practice.html"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/activity_editor_livedata.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 18 | 19 | 33 | 34 | 45 | 46 | 60 | 61 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/activity_list_viewmodel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 18 | 19 | 27 | 28 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/activity_location_databinding.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 18 | 19 | 20 | 23 | 24 | 35 | 36 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/activity_location_lifecycles.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 26 | 27 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/activity_main_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/activity_one_more_thing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | 18 | 21 | 22 | 33 | 34 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/adapter_location.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/adapter_location_databinding.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 18 | 19 | 29 | 30 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/layout/fragment_location_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 18 | 19 | 20 | 24 | 25 | 36 | 37 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | One More Thing 7 | Jetpack MVVM 最佳实践 8 | -------------------------------------------------------------------------------- /jetpack_java/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /jetpack_java/src/test/java/com/kunminx/jetpack_java/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.kunminx.jetpack_java; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /jetpack_kotlin/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /jetpack_kotlin/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/jetpack_kotlin/consumer-rules.pro -------------------------------------------------------------------------------- /jetpack_kotlin/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 22 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/androidTest/java/com/flywith24/jetpack_kotlin/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("com.flywith24.jetpack_kotlin.test", appContext.packageName) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/common_data/APIs.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.common_data 2 | 3 | /** 4 | * @author Flywith24 5 | * @date 2020/5/30 6 | * time 12:22 7 | * description 8 | */ 9 | object APIs { 10 | const val PIC_URL = "https://i.loli.net/2020/05/29/Dynh3KrQ7m8Oz4A.jpg" 11 | const val KUNMINX_URL = "https://upload.jianshu.io/users/upload_avatars/57036/3e7ae7bc-9b9b-46c8-8082-bb2481d979dc.jpg" 12 | 13 | const val FLYWITH24_URL = "https://upload-images.jianshu.io/upload_images/57036-48e9886afe74ea9b.jpeg" 14 | 15 | const val SCENE_URL = "https://upload-images.jianshu.io/upload_images/57036-99344035bfce65b8.jpeg" 16 | 17 | const val ADD_PIC_TIP_URL = "https://upload-images.jianshu.io/upload_images/57036-0c120ced543d506a.png" 18 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/common_data/Configs.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.common_data 2 | 3 | /** 4 | * @author Flywith24 5 | * @date 2020/5/30 6 | * time 12:16 7 | * description 8 | */ 9 | object Configs { 10 | const val REQUEST_LOCATION_INFO = 0x00001 11 | const val REQUEST_NEW_MOMENT = 0x00002 12 | const val NEW_MOMENT = "NEW_MOMENT" 13 | const val LOCATION_RESULT = "LOCATION_RESULT" 14 | const val THIS_MOMENT = "THIS_MOMENT" 15 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/common_data/bean/LocationBean.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.common_data.bean 2 | 3 | /** 4 | * @author Flywith24 5 | * @date 2020/5/30 6 | * time 11:48 7 | * description 8 | */ 9 | data class LocationBean(val locationName: String) -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/common_data/bean/Moment.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.common_data.bean 2 | 3 | import android.os.Parcelable 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | /** 7 | * @author Flywith24 8 | * @date 2020/5/30 9 | * time 20:02 10 | * description 11 | */ 12 | @Parcelize 13 | data class Moment( 14 | var uuid: String, 15 | val content: String?, 16 | val location: String?, 17 | val imgUrl: String, 18 | var username: String, 19 | var userAvatar: String 20 | ) : Parcelable -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/common_ui/adapter/DiffUtil.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.common_ui.adapter 2 | 3 | import androidx.recyclerview.widget.DiffUtil 4 | import com.flywith24.jetpack_kotlin.common_data.bean.LocationBean 5 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 6 | 7 | /** 8 | * @author Flywith24 9 | * @date 2020/5/31 10 | * time 23:00 11 | * description 12 | */ 13 | object LocationDiffCallback : DiffUtil.ItemCallback() { 14 | override fun areItemsTheSame(oldItem: LocationBean, newItem: LocationBean): Boolean = 15 | oldItem == newItem 16 | 17 | 18 | override fun areContentsTheSame(oldItem: LocationBean, newItem: LocationBean): Boolean = 19 | oldItem.locationName == newItem.locationName 20 | } 21 | 22 | object MomentDiffCallback : DiffUtil.ItemCallback() { 23 | override fun areItemsTheSame(oldItem: Moment, newItem: Moment): Boolean { 24 | return oldItem.uuid == newItem.uuid 25 | } 26 | 27 | override fun areContentsTheSame(oldItem: Moment, newItem: Moment): Boolean { 28 | return oldItem.content == newItem.content && 29 | oldItem.imgUrl == newItem.imgUrl && 30 | oldItem.location == newItem.location && 31 | oldItem.username == newItem.username && 32 | oldItem.userAvatar == newItem.userAvatar 33 | } 34 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/common_ui/adapter/LocationAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.common_ui.adapter 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import android.widget.TextView 7 | import androidx.recyclerview.widget.ListAdapter 8 | import androidx.recyclerview.widget.RecyclerView 9 | import com.flywith24.jetpack_kotlin.R 10 | import com.flywith24.jetpack_kotlin.common_data.bean.LocationBean 11 | 12 | /** 13 | * @author Flywith24 14 | * @date 2020/5/30 15 | * time 11:47 16 | * description 17 | * ListAdapter 强制使用 DiffUtil 比较数据变化,开发者无需手动调用各种 notify 方法亦可使用 recyclerView 的动画 18 | */ 19 | class LocationAdapter(private val onClick: (LocationBean) -> Unit) : 20 | ListAdapter(LocationDiffCallback) { 21 | 22 | class ViewHolder(itemView: View, val onClick: (LocationBean) -> Unit) : RecyclerView.ViewHolder(itemView) { 23 | private var mTvTitle: TextView = itemView.findViewById(R.id.tv_title) 24 | private var currentLocation: LocationBean? = null 25 | 26 | init { 27 | itemView.setOnClickListener { 28 | currentLocation?.let { 29 | onClick(it) 30 | } 31 | } 32 | } 33 | 34 | fun bind(item: LocationBean) { 35 | currentLocation = item 36 | mTvTitle.text = item.locationName 37 | } 38 | } 39 | 40 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 41 | val view = LayoutInflater.from(parent.context).inflate(R.layout.kotlin_adapter_location, parent, false) 42 | return ViewHolder(view, onClick) 43 | } 44 | 45 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 46 | holder.bind(getItem(position)) 47 | } 48 | 49 | override fun submitList(list: List?) { 50 | super.submitList(list) { 51 | submitList(if (list == null) emptyList() else ArrayList(list)) 52 | } 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_01_lifecycles/domain/LifecycleLocationManager.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_01_lifecycles.domain 2 | 3 | import androidx.lifecycle.DefaultLifecycleObserver 4 | import androidx.lifecycle.LifecycleOwner 5 | import com.flywith24.jetpack_kotlin.common_data.bean.LocationBean 6 | import java.util.* 7 | import kotlin.collections.ArrayList 8 | import kotlin.concurrent.timerTask 9 | 10 | /** 11 | * @author Flywith24 12 | * @date 2020/5/30 13 | * time 12:23 14 | * description 15 | */ 16 | class LifecycleLocationManager private constructor() : DefaultLifecycleObserver { 17 | private var mTimer: Timer? = null 18 | private var mLocationBeans = ArrayList() 19 | 20 | private var mILocationCallback: ILocationCallback? = null 21 | 22 | fun setILocationCallback(callback: ((List) -> Unit)?) { 23 | mILocationCallback = object : ILocationCallback { 24 | override fun onListChanged(list: List) { 25 | callback?.invoke(list) 26 | } 27 | } 28 | } 29 | 30 | override fun onResume(owner: LifecycleOwner) { 31 | //TODO 我是获取附近位置列表信息的后台定位服务,我耗电巨大,我随着页面的 onResume 开启了 32 | mTimer = Timer() 33 | val task = timerTask { 34 | //模拟定位,假设开启了 GPS 并且每秒获取若干条新的位置信息 35 | 36 | mLocationBeans.add(LocationBean("台北夜市 ${System.currentTimeMillis()} 号")) 37 | 38 | mILocationCallback?.onListChanged(mLocationBeans) 39 | onResume(owner) 40 | } 41 | 42 | mTimer?.schedule(task, 250) 43 | } 44 | 45 | override fun onPause(owner: LifecycleOwner) { 46 | //TODO 我随着页面的 onPause 而关闭了 47 | 48 | mTimer?.cancel() 49 | mTimer = null 50 | 51 | mLocationBeans.clear() 52 | } 53 | 54 | companion object { 55 | private val sManager = LifecycleLocationManager() 56 | fun getInstance(): LifecycleLocationManager = sManager 57 | } 58 | 59 | interface ILocationCallback { 60 | fun onListChanged(list: List) 61 | } 62 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_01_lifecycles/ui/LifecycleEditorActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_01_lifecycles.ui 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.widget.ImageView 6 | import android.widget.TextView 7 | import androidx.activity.result.contract.ActivityResultContracts 8 | import androidx.appcompat.widget.Toolbar 9 | import com.flywith24.jetpack_kotlin.R 10 | import com.flywith24.jetpack_kotlin.common_data.APIs 11 | import com.flywith24.jetpack_kotlin.common_data.Configs 12 | import com.kunminx.architecture.ui.BaseActivity 13 | import com.kunminx.architecture.utils.loadImage 14 | 15 | /** 16 | * @author Flywith24 17 | * @date 2020/5/30 18 | * time 11:39 19 | * description 20 | */ 21 | class LifecycleEditorActivity : BaseActivity(R.layout.kotlin_activity_lifecycles_detail) { 22 | /** 23 | * 不推荐使用 Kotlin Synthetics 24 | * 可以使用 ViewBinding 和 功能更强大的 DataBinding 来替换 findViewById 25 | * 26 | * 本示例尽量只演示单个组件的使用,因此没有使用 ViewBinding 或 DataBinding 27 | * 28 | * 详情参考 https://juejin.im/post/5e8ef0bc518825736b749705#heading-17 29 | */ 30 | private lateinit var mTvLocation: TextView 31 | private lateinit var mImageView: ImageView 32 | private lateinit var mToolbar: Toolbar 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | 37 | mTvLocation = findViewById(R.id.tv_locate) 38 | mImageView = findViewById(R.id.iv) 39 | mToolbar = findViewById(R.id.toolbar) 40 | mToolbar.apply { 41 | setNavigationOnClickListener { finish() } 42 | inflateMenu(R.menu.editor_menu) 43 | setOnMenuItemClickListener { item -> 44 | if (item.itemId == R.id.menu_save) { 45 | showLongToast(getString(R.string.lifecycle_save_tip)) 46 | } 47 | return@setOnMenuItemClickListener true 48 | } 49 | } 50 | 51 | mImageView.loadImage(APIs.SCENE_URL) 52 | 53 | mTvLocation.setOnClickListener { 54 | /** 55 | * startActivityForResult API 已弃用,可以使用新的 ActivityResult API 56 | * 详情见 https://github.com/Flywith24/Flywith24-ActivityResultRequest 57 | */ 58 | registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { 59 | val location = it.data?.getStringExtra(Configs.LOCATION_RESULT) 60 | mTvLocation.text = location 61 | }.launch(Intent(this, LifecycleLocationActivity::class.java)) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_01_lifecycles/ui/LifecycleLocationActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_01_lifecycles.ui 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.widget.Toolbar 7 | import androidx.recyclerview.widget.RecyclerView 8 | import com.flywith24.jetpack_kotlin.R 9 | import com.flywith24.jetpack_kotlin.common_data.Configs 10 | import com.flywith24.jetpack_kotlin.common_data.bean.LocationBean 11 | import com.flywith24.jetpack_kotlin.common_ui.adapter.LocationAdapter 12 | import com.flywith24.jetpack_kotlin.sample_01_lifecycles.domain.LifecycleLocationManager 13 | import com.kunminx.architecture.ui.BaseActivity 14 | 15 | /** 16 | * @author Flywith24 17 | * @date 2020/5/30 18 | * time 11:20 19 | * description 20 | */ 21 | class LifecycleLocationActivity : BaseActivity(R.layout.kotlin_activity_lifecycles_location) { 22 | /** 23 | * 不推荐使用 Kotlin Synthetics 24 | * 可以使用 ViewBinding 和 功能更强大的 DataBinding 来替换 findViewById 25 | * 26 | * 本示例尽量只演示单个组件的使用,因此没有使用 ViewBinding 或 DataBinding 27 | * 28 | * 详情参考 https://juejin.im/post/5e8ef0bc518825736b749705#heading-17 29 | */ 30 | private lateinit var mRecyclerView: RecyclerView 31 | private lateinit var mToolbar: Toolbar 32 | 33 | private val mAdapter by lazy { LocationAdapter { adapterClick(it) } } 34 | 35 | private fun adapterClick(locationBean: LocationBean) { 36 | setResult(Activity.RESULT_OK, Intent().putExtra(Configs.LOCATION_RESULT, locationBean.locationName)) 37 | finish() 38 | } 39 | 40 | override fun onCreate(savedInstanceState: Bundle?) { 41 | super.onCreate(savedInstanceState) 42 | 43 | mToolbar = findViewById(R.id.toolbar) 44 | mToolbar.setNavigationOnClickListener { finish() } 45 | 46 | mRecyclerView = findViewById(R.id.rv) 47 | mRecyclerView.adapter = mAdapter 48 | 49 | lifecycle.addObserver(LifecycleLocationManager.getInstance()) 50 | 51 | LifecycleLocationManager.getInstance().setILocationCallback { list -> 52 | runOnUiThread { 53 | mAdapter.submitList(list) 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_02_livedata/domain/LiveDataLocationManager.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_02_livedata.domain 2 | 3 | import androidx.lifecycle.DefaultLifecycleObserver 4 | import androidx.lifecycle.LifecycleOwner 5 | import androidx.lifecycle.LiveData 6 | import androidx.lifecycle.MutableLiveData 7 | import com.flywith24.jetpack_kotlin.common_data.bean.LocationBean 8 | import java.util.* 9 | import kotlin.collections.ArrayList 10 | import kotlin.concurrent.timerTask 11 | 12 | /** 13 | * @author Flywith24 14 | * @date 2020/5/30 15 | * time 12:23 16 | * description 17 | */ 18 | class LiveDataLocationManager private constructor() : DefaultLifecycleObserver { 19 | private var mTimer: Timer? = null 20 | private val mLocationBeans = MutableLiveData>() 21 | 22 | fun getLocationBeans(): LiveData> = mLocationBeans 23 | 24 | private val mList = ArrayList() 25 | 26 | override fun onResume(owner: LifecycleOwner) { 27 | //TODO 我是获取附近位置列表信息的后台定位服务,我耗电巨大,我随着页面的 onResume 开启了 28 | 29 | mTimer = Timer() 30 | 31 | val task = timerTask { 32 | //模拟定位,假设开启了 GPS 并且每秒获取若干条新的位置信息 33 | 34 | mList.add(LocationBean("台北夜市 ${System.currentTimeMillis()} 号")) 35 | mLocationBeans.postValue(mList) 36 | onResume(owner) 37 | } 38 | 39 | mTimer?.schedule(task, 250) 40 | } 41 | 42 | override fun onPause(owner: LifecycleOwner) { 43 | //TODO 我随着页面的 onPause 而关闭了 44 | 45 | mTimer?.cancel() 46 | mTimer = null 47 | 48 | mList.clear() 49 | } 50 | 51 | companion object { 52 | private val sManager = LiveDataLocationManager() 53 | fun getInstance(): LiveDataLocationManager = sManager 54 | } 55 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_02_livedata/ui/LiveDataEditorActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_02_livedata.ui 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.widget.ImageView 6 | import android.widget.TextView 7 | import androidx.activity.result.contract.ActivityResultContracts 8 | import androidx.appcompat.widget.Toolbar 9 | import com.flywith24.jetpack_kotlin.R 10 | import com.flywith24.jetpack_kotlin.common_data.APIs 11 | import com.flywith24.jetpack_kotlin.common_data.Configs 12 | import com.kunminx.architecture.ui.BaseActivity 13 | import com.kunminx.architecture.utils.loadImage 14 | 15 | /** 16 | * @author Flywith24 17 | * @date 2020/5/30 18 | * time 20:31 19 | * description 20 | */ 21 | class LiveDataEditorActivity : BaseActivity(R.layout.kotlin_activity_livedata_editor) { 22 | /** 23 | * 不推荐使用 Kotlin Synthetics 24 | * 可以使用 ViewBinding 和 功能更强大的 DataBinding 来替换 findViewById 25 | * 26 | * 本示例尽量只演示单个组件的使用,因此没有使用 ViewBinding 或 DataBinding 27 | * 28 | * 详情参考 https://juejin.im/post/5e8ef0bc518825736b749705#heading-17 29 | */ 30 | private lateinit var mImageView: ImageView 31 | private lateinit var mTvLocation: TextView 32 | private lateinit var mToolbar: Toolbar 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | mImageView = findViewById(R.id.iv) 37 | mTvLocation = findViewById(R.id.tv_locate) 38 | 39 | mToolbar = findViewById(R.id.toolbar) 40 | mToolbar.apply { 41 | setNavigationOnClickListener { finish() } 42 | inflateMenu(R.menu.editor_menu) 43 | setOnMenuItemClickListener { item -> 44 | if (item.itemId == R.id.menu_save) { 45 | showLongToast(getString(R.string.liveData_save_tip)) 46 | } 47 | return@setOnMenuItemClickListener true 48 | } 49 | } 50 | 51 | mImageView.loadImage(APIs.SCENE_URL) 52 | 53 | mTvLocation.setOnClickListener { 54 | 55 | /** 56 | * startActivityForResult API 已弃用,可以使用新的 ActivityResult API 57 | * 详情见 https://github.com/Flywith24/Flywith24-ActivityResultRequest 58 | */ 59 | registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { 60 | val location = it.data?.getStringExtra(Configs.LOCATION_RESULT) 61 | mTvLocation.text = location 62 | }.launch(Intent(this, LiveDataLocationActivity::class.java)) 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_02_livedata/ui/LiveDataLocationActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_02_livedata.ui 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.widget.Toolbar 7 | 8 | import androidx.recyclerview.widget.RecyclerView 9 | import com.flywith24.jetpack_kotlin.R 10 | import com.flywith24.jetpack_kotlin.common_data.Configs 11 | import com.flywith24.jetpack_kotlin.common_data.bean.LocationBean 12 | import com.flywith24.jetpack_kotlin.common_ui.adapter.LocationAdapter 13 | import com.flywith24.jetpack_kotlin.sample_02_livedata.domain.LiveDataLocationManager 14 | import com.kunminx.architecture.ui.BaseActivity 15 | 16 | /** 17 | * @author Flywith24 18 | * @date 2020/5/30 19 | * time 20:31 20 | * description 21 | */ 22 | class LiveDataLocationActivity : BaseActivity(R.layout.kotlin_activity_livedata_list) { 23 | /** 24 | * 不推荐使用 Kotlin Synthetics 25 | * 可以使用 ViewBinding 和 功能更强大的 DataBinding 来替换 findViewById 26 | * 27 | * 本示例尽量只演示单个组件的使用,因此没有使用 ViewBinding 或 DataBinding 28 | * 29 | * 详情参考 https://juejin.im/post/5e8ef0bc518825736b749705#heading-17 30 | */ 31 | private lateinit var mRecyclerView: RecyclerView 32 | private lateinit var mToolbar: Toolbar 33 | 34 | private val mAdapter: LocationAdapter by lazy { LocationAdapter { adapterClick(it) } } 35 | 36 | private fun adapterClick(locationBean: LocationBean) { 37 | setResult(Activity.RESULT_OK, Intent().putExtra(Configs.LOCATION_RESULT, locationBean.locationName)) 38 | finish() 39 | } 40 | 41 | override fun onCreate(savedInstanceState: Bundle?) { 42 | super.onCreate(savedInstanceState) 43 | 44 | mToolbar = findViewById(R.id.toolbar) 45 | mToolbar.setNavigationOnClickListener { finish() } 46 | 47 | mRecyclerView = findViewById(R.id.rv) 48 | mRecyclerView.adapter = mAdapter 49 | 50 | lifecycle.addObserver(LiveDataLocationManager.getInstance()) 51 | 52 | LiveDataLocationManager.getInstance().getLocationBeans().observe(this) { list -> 53 | mAdapter.submitList(list) 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_03_viewmodel/data/DataRepository.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_03_viewmodel.data 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.flywith24.jetpack_kotlin.common_data.APIs 5 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 6 | import java.util.* 7 | 8 | /** 9 | * @author Flywith24 10 | * @date 2020/5/31 11 | * time 22:03 12 | * description 13 | */ 14 | internal class DataRepository private constructor() { 15 | 16 | fun requestList(liveData: MutableLiveData>) { 17 | val list = listOf( 18 | Moment(getUUID(), "刚刚在掘金发表了最新一期动态,感兴趣的小伙伴可前往查阅", 19 | "重庆朝天门码头", APIs.SCENE_URL, "KunMinX", APIs.KUNMINX_URL), 20 | Moment(getUUID(), "刚刚在掘金发表了最新一期动态,感兴趣的小伙伴可前往查阅", 21 | "重庆朝天门码头", APIs.SCENE_URL, "Flywith24", APIs.FLYWITH24_URL), 22 | Moment(getUUID(), "刚刚在掘金发表了最新一期动态,感兴趣的小伙伴可前往查阅", 23 | "重庆朝天门码头", APIs.SCENE_URL, "KunMinX", APIs.KUNMINX_URL), 24 | Moment(getUUID(), "刚刚在掘金发表了最新一期动态,感兴趣的小伙伴可前往查阅", 25 | "重庆朝天门码头", APIs.SCENE_URL, "Flywith24", APIs.FLYWITH24_URL), 26 | Moment(getUUID(), "刚刚在掘金发表了最新一期动态,感兴趣的小伙伴可前往查阅", 27 | "重庆朝天门码头", APIs.SCENE_URL, "KunMinX", APIs.KUNMINX_URL), 28 | Moment(getUUID(), "刚刚在掘金发表了最新一期动态,感兴趣的小伙伴可前往查阅", 29 | "重庆朝天门码头", APIs.SCENE_URL, "Flywith24", APIs.FLYWITH24_URL), 30 | Moment(getUUID(), "刚刚在掘金发表了最新一期动态,感兴趣的小伙伴可前往查阅", 31 | "重庆朝天门码头", APIs.SCENE_URL, "KunMinX", APIs.KUNMINX_URL), 32 | Moment(getUUID(), "刚刚在掘金发表了最新一期动态,感兴趣的小伙伴可前往查阅", 33 | "重庆朝天门码头", APIs.SCENE_URL, "Flywith24", APIs.FLYWITH24_URL) 34 | 35 | ) 36 | 37 | liveData.value = list 38 | 39 | } 40 | 41 | private fun getUUID(): String = UUID.randomUUID().toString().replace("-", "") 42 | 43 | companion object { 44 | private val sRepository = DataRepository() 45 | fun getInstance(): DataRepository = sRepository 46 | } 47 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_03_viewmodel/domain/MomentRequest.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_03_viewmodel.domain 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 6 | import com.flywith24.jetpack_kotlin.sample_03_viewmodel.data.DataRepository 7 | 8 | /** 9 | * @author Flywith24 10 | * @date 2020/5/31 11 | * time 22:09 12 | * description 13 | */ 14 | internal class MomentRequest : Request.IMomentRequest { 15 | private val mListMutableLiveData = MutableLiveData>() 16 | 17 | override fun getListMutableLiveData(): LiveData> = mListMutableLiveData 18 | 19 | override fun requestList() { 20 | DataRepository.getInstance().requestList(mListMutableLiveData) 21 | } 22 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_03_viewmodel/domain/Request.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_03_viewmodel.domain 2 | 3 | import androidx.lifecycle.LiveData 4 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 5 | 6 | /** 7 | * @author Flywith24 8 | * @date 2020/5/31 9 | * time 22:10 10 | * description 11 | */ 12 | internal class Request { 13 | interface IMomentRequest { 14 | 15 | fun getListMutableLiveData(): LiveData> 16 | 17 | fun requestList() 18 | } 19 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_03_viewmodel/ui/ViewModelListActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_03_viewmodel.ui 2 | 3 | import android.os.Bundle 4 | import androidx.activity.viewModels 5 | import androidx.appcompat.widget.Toolbar 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.flywith24.jetpack_kotlin.R 8 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 9 | import com.flywith24.jetpack_kotlin.common_ui.adapter.MomentAdapter 10 | import com.flywith24.jetpack_kotlin.sample_03_viewmodel.ui.state.ListViewModel 11 | import com.kunminx.architecture.ui.BaseActivity 12 | 13 | /** 14 | * @author Flywith24 15 | * @date 2020/5/31 16 | * time 22:02 17 | * description 18 | */ 19 | class ViewModelListActivity : BaseActivity(R.layout.kotlin_activity_list_viewmodel) { 20 | 21 | /** 22 | * activity 级别共享 ViewModel 23 | * 24 | * activity-ktx 扩展函数 25 | * 26 | * ViewModel 如何控制作用域,请参考 27 | * https://juejin.im/post/5e786d415188255e00661a4e#heading-10 28 | */ 29 | private val mListViewModel by viewModels() 30 | 31 | /** 32 | * 不推荐使用 Kotlin Synthetics 33 | * 可以使用 ViewBinding 和 功能更强大的 DataBinding 来替换 findViewById 34 | * 35 | * 本示例尽量只演示单个组件的使用,因此没有使用 ViewBinding 或 DataBinding 36 | * 37 | * 详情参考 https://juejin.im/post/5e8ef0bc518825736b749705#heading-17 38 | */ 39 | private lateinit var mRecyclerView: RecyclerView 40 | private lateinit var mToolbar: Toolbar 41 | 42 | private val mAdapter by lazy { MomentAdapter { adapterClick(it) } } 43 | 44 | private fun adapterClick(moment: Moment) { 45 | showLongToast(getString(R.string.viewmodel_item_click_tip)) 46 | } 47 | 48 | override fun onCreate(savedInstanceState: Bundle?) { 49 | super.onCreate(savedInstanceState) 50 | mToolbar = findViewById(R.id.toolbar) 51 | mToolbar.setNavigationOnClickListener { finish() } 52 | 53 | mRecyclerView = findViewById(R.id.rv) 54 | 55 | mRecyclerView.adapter = mAdapter 56 | 57 | mListViewModel.getListMutableLiveData().observe(this) { list -> 58 | mAdapter.submitList(list) 59 | } 60 | 61 | mListViewModel.requestList() 62 | } 63 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_03_viewmodel/ui/state/ListViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_03_viewmodel.ui.state 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.ViewModel 5 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 6 | import com.flywith24.jetpack_kotlin.sample_03_viewmodel.domain.MomentRequest 7 | import com.flywith24.jetpack_kotlin.sample_03_viewmodel.domain.Request 8 | 9 | /** 10 | * @author Flywith24 11 | * @date 2020/5/31 12 | * time 22:03 13 | * description 14 | */ 15 | internal class ListViewModel : ViewModel(), Request.IMomentRequest { 16 | 17 | private val mMomentRequest by lazy { MomentRequest() } 18 | 19 | override fun getListMutableLiveData(): LiveData> = mMomentRequest.getListMutableLiveData() 20 | 21 | override fun requestList() { 22 | mMomentRequest.requestList() 23 | } 24 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_04_databinding/ui/DataBindingDetailActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_04_databinding.ui 2 | 3 | import android.os.Bundle 4 | import androidx.activity.viewModels 5 | import androidx.databinding.DataBindingUtil 6 | import com.flywith24.jetpack_kotlin.R 7 | import com.flywith24.jetpack_kotlin.common_data.Configs 8 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 9 | import com.flywith24.jetpack_kotlin.databinding.KotlinActivityDetailDatabindingBinding 10 | import com.flywith24.jetpack_kotlin.sample_04_databinding.ui.state.DetailViewModel 11 | import com.kunminx.architecture.ui.BaseActivity 12 | 13 | /** 14 | * @author Flywith24 15 | * @date 2020/5/31 16 | * time 23:30 17 | * description 18 | */ 19 | class DataBindingDetailActivity : BaseActivity() { 20 | 21 | /** 22 | * activity 级别共享 ViewModel 23 | * 24 | * activity-ktx 扩展函数 25 | * 26 | * ViewModel 如何控制作用域,请参考 27 | * https://juejin.im/post/5e786d415188255e00661a4e#heading-10 28 | */ 29 | private val mDetailViewModel by viewModels() 30 | 31 | override fun onCreate(savedInstanceState: Bundle?) { 32 | super.onCreate(savedInstanceState) 33 | 34 | val binding = DataBindingUtil.setContentView(this, R.layout.kotlin_activity_detail_databinding) 35 | binding.lifecycleOwner = this 36 | binding.vm = mDetailViewModel 37 | binding.click = ClickProxy() 38 | 39 | val moment = intent.getParcelableExtra(Configs.THIS_MOMENT) 40 | moment?.let { 41 | mDetailViewModel.initState(it) 42 | } 43 | } 44 | 45 | inner class ClickProxy { 46 | fun back() { 47 | finish() 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_04_databinding/ui/DataBindingLocationActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_04_databinding.ui 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.activity.viewModels 7 | import androidx.databinding.DataBindingUtil 8 | 9 | import com.flywith24.jetpack_kotlin.R 10 | import com.flywith24.jetpack_kotlin.common_data.Configs 11 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 12 | import com.flywith24.jetpack_kotlin.databinding.KotlinActivityLocationDatabindingBinding 13 | import com.flywith24.jetpack_kotlin.sample_02_livedata.domain.LiveDataLocationManager 14 | import com.flywith24.jetpack_kotlin.sample_04_databinding.ui.adapter.DataBindingLocationAdapter 15 | import com.flywith24.jetpack_kotlin.sample_04_databinding.ui.state.LocationViewModel 16 | import com.kunminx.architecture.ui.BaseActivity 17 | 18 | /** 19 | * @author Flywith24 20 | * @date 2020/5/31 21 | * time 23:14 22 | * description 23 | */ 24 | class DataBindingLocationActivity : BaseActivity() { 25 | /** 26 | * activity 级别共享 ViewModel 27 | * 28 | * activity-ktx 扩展函数 29 | * 30 | * ViewModel 如何控制作用域,请参考 31 | * https://juejin.im/post/5e786d415188255e00661a4e#heading-10 32 | */ 33 | private val mLocationViewModel by viewModels() 34 | 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | super.onCreate(savedInstanceState) 37 | 38 | val binding = DataBindingUtil.setContentView(this, R.layout.kotlin_activity_location_databinding) 39 | binding.lifecycleOwner = this 40 | binding.vm = mLocationViewModel 41 | binding.click = ClickProxy() 42 | binding.adapter = DataBindingLocationAdapter(applicationContext).apply { 43 | setOnItemClickListener { item, _ -> 44 | setResult(Activity.RESULT_OK, 45 | Intent().putExtra(Configs.LOCATION_RESULT, item.locationName)) 46 | finish() 47 | } 48 | } 49 | 50 | lifecycle.addObserver(LiveDataLocationManager.getInstance()) 51 | 52 | LiveDataLocationManager.getInstance().getLocationBeans().observe(this) { list -> 53 | mLocationViewModel.list.value = list 54 | } 55 | } 56 | 57 | inner class ClickProxy { 58 | fun back() { 59 | finish() 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_04_databinding/ui/adapter/DataBindingLocationAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_04_databinding.ui.adapter 2 | 3 | import android.content.Context 4 | import androidx.recyclerview.widget.RecyclerView 5 | import com.flywith24.jetpack_kotlin.R 6 | import com.flywith24.jetpack_kotlin.common_data.bean.LocationBean 7 | import com.flywith24.jetpack_kotlin.common_ui.adapter.LocationDiffCallback 8 | import com.flywith24.jetpack_kotlin.databinding.KotlinAdapterLocationDatabindingBinding 9 | import com.kunminx.architecture.ui.adapter.SimpleBindingAdapter 10 | 11 | /** 12 | * @author Flywith24 13 | * @date 2020/5/31 14 | * time 22:56 15 | * description 16 | */ 17 | class DataBindingLocationAdapter(context: Context) : SimpleBindingAdapter(context, R.layout.kotlin_adapter_location_databinding, LocationDiffCallback) { 18 | override fun onBindItem(binding: KotlinAdapterLocationDatabindingBinding?, item: LocationBean?, holder: RecyclerView.ViewHolder?) { 19 | binding?.bean = item 20 | } 21 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_04_databinding/ui/adapter/DataBindingMomentAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_04_databinding.ui.adapter 2 | 3 | import android.content.Context 4 | import androidx.recyclerview.widget.RecyclerView 5 | import com.flywith24.jetpack_kotlin.R 6 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 7 | import com.flywith24.jetpack_kotlin.common_ui.adapter.MomentDiffCallback 8 | import com.flywith24.jetpack_kotlin.databinding.KotlinAdapterMomentDatabindingBinding 9 | import com.kunminx.architecture.ui.adapter.SimpleBindingAdapter 10 | 11 | /** 12 | * @author Flywith24 13 | * @date 2020/5/31 14 | * time 22:56 15 | * description 16 | */ 17 | class DataBindingMomentAdapter(context: Context) : SimpleBindingAdapter(context, R.layout.kotlin_adapter_moment_databinding, MomentDiffCallback) { 18 | override fun onBindItem(binding: KotlinAdapterMomentDatabindingBinding?, item: Moment?, holder: RecyclerView.ViewHolder?) { 19 | binding?.moment = item 20 | } 21 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_04_databinding/ui/state/DetailViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_04_databinding.ui.state 2 | 3 | import androidx.databinding.ObservableField 4 | import androidx.lifecycle.ViewModel 5 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 6 | 7 | /** 8 | * @author Flywith24 9 | * @date 2020/5/31 10 | * time 23:11 11 | * description 12 | */ 13 | class DetailViewModel : ViewModel() { 14 | val imgUrl = ObservableField() 15 | val name = ObservableField() 16 | val content = ObservableField() 17 | val location = ObservableField() 18 | val avatar = ObservableField() 19 | 20 | fun initState(moment: Moment) { 21 | avatar.set(moment.userAvatar) 22 | name.set(moment.username) 23 | content.set(moment.content) 24 | imgUrl.set(moment.imgUrl) 25 | location.set(moment.location) 26 | } 27 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_04_databinding/ui/state/EditorViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_04_databinding.ui.state 2 | 3 | import androidx.databinding.ObservableField 4 | import androidx.lifecycle.ViewModel 5 | import com.flywith24.jetpack_kotlin.common_data.APIs 6 | 7 | /** 8 | * @author Flywith24 9 | * @date 2020/5/31 10 | * time 23:11 11 | * description 12 | */ 13 | class EditorViewModel : ViewModel() { 14 | val imgUrl = ObservableField(APIs.ADD_PIC_TIP_URL) 15 | val content = ObservableField("") 16 | val location = ObservableField("点击添加定位") 17 | 18 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_04_databinding/ui/state/ListViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_04_databinding.ui.state 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 7 | import com.flywith24.jetpack_kotlin.sample_03_viewmodel.domain.MomentRequest 8 | import com.flywith24.jetpack_kotlin.sample_03_viewmodel.domain.Request 9 | 10 | /** 11 | * @author Flywith24 12 | * @date 2020/5/31 13 | * time 22:03 14 | * description 15 | */ 16 | internal class ListViewModel : ViewModel(), Request.IMomentRequest { 17 | 18 | val list = MutableLiveData>(emptyList()) 19 | val autoScrollToTopWhenInsert = MutableLiveData(true) 20 | 21 | private val mMomentRequest by lazy { MomentRequest() } 22 | 23 | override fun getListMutableLiveData(): LiveData> = mMomentRequest.getListMutableLiveData() 24 | 25 | override fun requestList() { 26 | mMomentRequest.requestList() 27 | } 28 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_04_databinding/ui/state/LocationViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_04_databinding.ui.state 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | import com.flywith24.jetpack_kotlin.common_data.bean.LocationBean 6 | 7 | /** 8 | * @author Flywith24 9 | * @date 2020/5/31 10 | * time 23:13 11 | * description 12 | */ 13 | class LocationViewModel : ViewModel() { 14 | val list = MutableLiveData>() 15 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_05_navigation/ui/NavigationDetailFragment.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_05_navigation.ui 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.viewModels 8 | import com.flywith24.jetpack_kotlin.R 9 | import com.flywith24.jetpack_kotlin.common_data.Configs 10 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 11 | import com.flywith24.jetpack_kotlin.databinding.KotlinFragmentDetailNavigationBinding 12 | import com.flywith24.jetpack_kotlin.sample_04_databinding.ui.state.DetailViewModel 13 | import com.kunminx.architecture.ui.BaseFragment 14 | 15 | /** 16 | * @author Flywith24 17 | * @date 2020/6/1 18 | * time 22:06 19 | * description 20 | */ 21 | class NavigationDetailFragment : BaseFragment() { 22 | /** 23 | * fragment-ktx 扩展函数 24 | */ 25 | private val mDetailViewModel by viewModels() 26 | 27 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 28 | val view = inflater.inflate(R.layout.kotlin_fragment_detail_navigation, container, false) 29 | val binding = KotlinFragmentDetailNavigationBinding.bind(view) 30 | binding.lifecycleOwner = viewLifecycleOwner 31 | binding.vm = mDetailViewModel 32 | binding.click = ClickProxy() 33 | return view 34 | } 35 | 36 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 37 | super.onViewCreated(view, savedInstanceState) 38 | 39 | val moment = arguments?.getParcelable(Configs.THIS_MOMENT) 40 | moment?.let { 41 | mDetailViewModel.initState(it) 42 | } 43 | } 44 | 45 | inner class ClickProxy { 46 | fun back() { 47 | nav().navigateUp() 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_05_navigation/ui/NavigationMainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_05_navigation.ui 2 | 3 | import android.os.Bundle 4 | import androidx.activity.viewModels 5 | import com.flywith24.jetpack_kotlin.R 6 | import com.flywith24.jetpack_kotlin.sample_05_navigation.ui.callback.SharedViewModel 7 | import com.kunminx.architecture.kotlin.observeEvent 8 | import com.kunminx.architecture.ui.BaseActivity 9 | 10 | /** 11 | * @author Flywith24 12 | * @date 2020/6/1 13 | * time 21:56 14 | * description 15 | */ 16 | class NavigationMainActivity : BaseActivity(R.layout.kotlin_activity_main_navigation) { 17 | private val mSharedViewModel by viewModels() 18 | 19 | override fun onCreate(savedInstanceState: Bundle?) { 20 | super.onCreate(savedInstanceState) 21 | mSharedViewModel.closeActivity.observeEvent(this) { 22 | finish() 23 | } 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_05_navigation/ui/callback/SharedViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_05_navigation.ui.callback 2 | 3 | import androidx.lifecycle.ViewModel 4 | import com.flywith24.jetpack_kotlin.common_data.bean.Moment 5 | import com.kunminx.architecture.kotlin.EventMutableLiveData 6 | 7 | /** 8 | * @author Flywith24 9 | * @date 2020/6/1 10 | * time 21:54 11 | * description 12 | */ 13 | class SharedViewModel : ViewModel() { 14 | /** 15 | * 使用 包装类 解决 LiveData 粘性事件的问题 16 | * 详见 17 | * https://juejin.im/post/5ed9c92ce51d45789b35afa9 (kotlin 扩展函数和 typealias 封装 LiveData) 18 | * 19 | * https://juejin.im/post/5b2b1b2cf265da5952314b63 (粘性事件) 20 | */ 21 | val location = EventMutableLiveData() 22 | val moment = EventMutableLiveData() 23 | val closeActivity = EventMutableLiveData() 24 | 25 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_one_more_thing/ui/OneMoreThingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_one_more_thing.ui 2 | 3 | import android.os.Bundle 4 | import androidx.activity.viewModels 5 | import androidx.databinding.DataBindingUtil 6 | import com.flywith24.jetpack_kotlin.R 7 | import com.flywith24.jetpack_kotlin.databinding.KotlinActivityOneMoreThingBinding 8 | import com.flywith24.jetpack_kotlin.sample_one_more_thing.ui.state.OneMoreThingViewModel 9 | import com.kunminx.architecture.ui.BaseActivity 10 | 11 | /** 12 | * @author Flywith24 13 | * @date 2020/6/10 14 | * time 00:31 15 | * description 16 | */ 17 | class OneMoreThingActivity : BaseActivity() { 18 | 19 | /** 20 | * activity 级别共享 ViewModel 21 | * 22 | * activity-ktx 扩展函数 23 | * 24 | * ViewModel 如何控制作用域,请参考 25 | * https://juejin.im/post/5e786d415188255e00661a4e#heading-10 26 | */ 27 | private val mOneMoreThingViewModel by viewModels() 28 | 29 | override fun onCreate(savedInstanceState: Bundle?) { 30 | super.onCreate(savedInstanceState) 31 | 32 | with(DataBindingUtil.setContentView(this, R.layout.kotlin_activity_one_more_thing)) { 33 | lifecycleOwner = this@OneMoreThingActivity 34 | vm = mOneMoreThingViewModel 35 | click = ClickProxy() 36 | } 37 | } 38 | 39 | inner class ClickProxy { 40 | fun back() { 41 | finish() 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/java/com/flywith24/jetpack_kotlin/sample_one_more_thing/ui/state/OneMoreThingViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin.sample_one_more_thing.ui.state 2 | 3 | import androidx.databinding.ObservableField 4 | import androidx.lifecycle.ViewModel 5 | 6 | /** 7 | * @author Flywith24 8 | * @date 2020/6/10 9 | * time 00:35 10 | * description 11 | */ 12 | class OneMoreThingViewModel : ViewModel() { 13 | val pageAssetPath = ObservableField("use_jetpack.html") 14 | } -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_editor_livedata.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 31 | 32 | 42 | 43 | 57 | 58 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_lifecycles_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 31 | 32 | 42 | 43 | 57 | 58 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_lifecycles_location.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 27 | 28 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_list_viewmodel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 18 | 19 | 28 | 29 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_livedata_editor.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 31 | 32 | 42 | 43 | 57 | 58 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_livedata_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 18 | 19 | 28 | 29 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_location_databinding.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 12 | 13 | 16 | 17 | 20 | 21 | 22 | 23 | 26 | 27 | 38 | 39 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_main_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_activity_one_more_thing.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 17 | 20 | 21 | 32 | 33 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_adapter_location.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 17 | 18 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_adapter_location_databinding.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 15 | 16 | 24 | 25 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/layout/kotlin_fragment_location_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 18 | 19 | 20 | 23 | 24 | 35 | 36 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/navigation/kotlin_nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 12 | 15 | 18 | 19 | 20 | 24 | 27 | 28 | 29 | 30 | 34 | 35 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jetpack_kotlin/src/test/java/com/flywith24/jetpack_kotlin/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.jetpack_kotlin 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Test 5 | 6 | /** 7 | * Example local unit test, which will execute on the development machine (host). 8 | * 9 | * See [testing documentation](http://d.android.com/tools/testing). 10 | */ 11 | class ExampleUnitTest { 12 | @Test 13 | fun addition_isCorrect() { 14 | assertEquals(4, 2 + 2) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':common_res' 2 | includeBuild('version_config') 3 | include ':app', ':architecture' 4 | rootProject.name = 'PureMusic' 5 | include ':jetpack_java' 6 | include ':jetpack_kotlin' 7 | -------------------------------------------------------------------------------- /version_config/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /version_config/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | google() 5 | } 6 | dependencies { 7 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0" 8 | } 9 | } 10 | 11 | apply plugin: 'kotlin' 12 | apply plugin: 'java-gradle-plugin' 13 | 14 | repositories { 15 | jcenter() 16 | google() 17 | } 18 | 19 | dependencies { 20 | implementation gradleApi() 21 | implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0" 22 | } 23 | 24 | compileTestKotlin { 25 | kotlinOptions { 26 | jvmTarget = "1.8" 27 | } 28 | } 29 | 30 | gradlePlugin { 31 | plugins { 32 | version { 33 | id = 'com.flywith24.version' 34 | implementationClass = 'com.flywith24.version_config.VersionConfigPlugin' 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /version_config/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/version_config/consumer-rules.pro -------------------------------------------------------------------------------- /version_config/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jul 22 08:52:21 CST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip 7 | -------------------------------------------------------------------------------- /version_config/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 22 | -------------------------------------------------------------------------------- /version_config/settings.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jetpack-Missionary/Jetpack-From-Java-To-Kotlin/1836ce1d4435b34164045d8ec582a65f1e0aa895/version_config/settings.gradle -------------------------------------------------------------------------------- /version_config/src/main/java/com/flywith24/version_config/BuildConfig.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.version_config 2 | 3 | /** 4 | * @author Flywith24 5 | * @date 2020/5/27 6 | * time 10:59 7 | * description 8 | */ 9 | object BuildConfig { 10 | const val compileSdkVersion = 29 11 | const val buildToolsVersion = "29.0.3" 12 | const val minSdkVersion = 23 13 | const val targetSdkVersion = 29 14 | const val versionCode = 1 15 | const val versionName = "1.0" 16 | } 17 | -------------------------------------------------------------------------------- /version_config/src/main/java/com/flywith24/version_config/VersionConfigPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.version_config 2 | 3 | import org.gradle.api.Plugin 4 | import org.gradle.api.Project 5 | 6 | /** 7 | * @author Flywith24 8 | * @date 2020/5/28 9 | * time 9:02 10 | * description 11 | * 依赖版本控制插件 12 | */ 13 | class VersionConfigPlugin : Plugin { 14 | override fun apply(project: Project) { 15 | //公共配置 16 | } 17 | } -------------------------------------------------------------------------------- /version_config/src/main/java/com/flywith24/version_config/dependencies/Google.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("SpellCheckingInspection") 2 | 3 | package com.flywith24.version_config.dependencies 4 | 5 | /** 6 | * @author Flywith24 7 | * @date 2020/3/5 8 | * time 21:09 9 | * description 10 | * google dependencis 11 | */ 12 | object Google { 13 | const val material = "com.google.android.material:material:1.2.0-alpha05" 14 | const val gson = "com.google.code.gson:gson:2.8.6" 15 | } -------------------------------------------------------------------------------- /version_config/src/main/java/com/flywith24/version_config/dependencies/Testing.kt: -------------------------------------------------------------------------------- 1 | package com.flywith24.version_config.dependencies 2 | 3 | /** 4 | * @author Flywith24 5 | * @date 2020/1/14 6 | * time 8:39 7 | * description 8 | * test dependencies 9 | */ 10 | object Testing { 11 | const val jUnit = "junit:junit:4.12" 12 | const val androidJunit = "androidx.test.ext:junit:1.1.1" 13 | const val androidRunner = "androidx.test:runner:1.2.0" 14 | const val espresso = "androidx.test.espresso:espresso-core:3.2.0" 15 | } -------------------------------------------------------------------------------- /version_config/src/main/java/com/flywith24/version_config/dependencies/ThirdParty.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("SpellCheckingInspection") 2 | 3 | package com.flywith24.version_config.dependencies 4 | 5 | /** 6 | * @author Flywith24 7 | * @date 2020/5/28 8 | * time 9:43 9 | * description 10 | * third party dependencies 11 | */ 12 | object ThirdParty { 13 | const val materialiconlib = "net.steamcrafted:materialiconlib:1.1.5" 14 | const val permission = "com.yanzhenjie.permission:x:2.0.1" 15 | 16 | object Glide { 17 | private const val glide_version = "4.11.0" 18 | const val glide = "com.github.bumptech.glide:glide:$glide_version" 19 | const val compiler = "com.github.bumptech.glide:compiler:$glide_version" 20 | } 21 | 22 | object Archi { 23 | const val unPeekLiveData = "com.kunminx.archi:unpeek-livedata:4.4.1-beta1" 24 | } 25 | 26 | const val roundedImageView = "com.makeramen:roundedimageview:2.3.0" 27 | 28 | } --------------------------------------------------------------------------------