├── .gitignore ├── ReadMe.md ├── antiDebug ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── anylife │ │ └── antidebugtest │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── AntiDebug-lib.cpp │ │ └── AntiDebug-lib.h │ └── java │ │ └── com │ │ └── anylife │ │ └── antidebug │ │ └── AntiDebugInterface.java │ └── test │ └── java │ └── com │ └── anylife │ └── antidebugtest │ └── ExampleUnitTest.java ├── archi-test ├── .gitignore ├── Archi.md ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ └── com │ │ └── architecture │ │ └── demo │ │ ├── application │ │ └── MainApplication.java │ │ ├── http │ │ ├── HttpBaseInfo.java │ │ ├── beans │ │ │ ├── AliParam.kt │ │ │ ├── BannerWithDefNPEField.kt │ │ │ ├── EuropeanaBean.kt │ │ │ ├── FakerDataBean.kt │ │ │ └── JsonBean.kt │ │ ├── myinterface │ │ │ ├── AliApi.kt │ │ │ ├── EuropeanaApi.kt │ │ │ ├── ExceptionApi.kt │ │ │ ├── FakerApi.kt │ │ │ ├── JsonApi.kt │ │ │ └── WannaAndroidApi.kt │ │ └── service │ │ │ ├── AliApiService.kt │ │ │ ├── EuropeanaApiService.kt │ │ │ ├── ExceptionApiService.kt │ │ │ ├── FakerApiService.kt │ │ │ ├── JsonApiService.kt │ │ │ └── WanAndroidApiService.kt │ │ ├── test │ │ └── socket │ │ │ ├── AndroidSocketClient.java │ │ │ ├── ServerThread.java │ │ │ └── SocketServer.java │ │ └── ui │ │ ├── archi │ │ ├── MainActivity.kt │ │ └── fragment │ │ │ ├── dashboard │ │ │ ├── DashboardFragment.kt │ │ │ └── DashboardViewModel.kt │ │ │ ├── home │ │ │ ├── HomeFragment.kt │ │ │ ├── HomeRepository.kt │ │ │ └── HomeViewModel.kt │ │ │ └── notifications │ │ │ ├── NotificationsFragment.kt │ │ │ └── NotificationsViewModel.kt │ │ ├── keepalive │ │ ├── BackGroundWork.kt │ │ ├── DozeAliveSettingActivity.kt │ │ └── H5DozeAliveGuideActivity.kt │ │ └── navi │ │ ├── NaviActivity.kt │ │ ├── NaviActivityScreen.kt │ │ ├── NaviActivityScreenViewModel.kt │ │ └── alitest │ │ ├── AliActivity.kt │ │ ├── AliRepository.kt │ │ ├── AliViewModel.kt │ │ └── test.java │ └── res │ ├── drawable │ ├── ic_dashboard_black_24dp.xml │ ├── ic_home_black_24dp.xml │ ├── ic_launcher_background.xml │ ├── ic_launcher_foreground.xml │ ├── ic_notifications_black_24dp.xml │ ├── shape_blue_btn_bg.xml │ └── shape_green_btn_bg.xml │ ├── layout │ ├── activity_ali.xml │ ├── activity_demo.xml │ ├── activity_h5_dozealive_guide.xml │ ├── activity_keep_alive_setting.xml │ ├── fragment_dashboard.xml │ ├── fragment_home.xml │ └── fragment_notifications.xml │ ├── menu │ └── bottom_nav_menu.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-mdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── navigation │ └── mobile_navigation.xml │ ├── values-night │ └── themes.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── themes.xml ├── base ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── architecture │ │ └── baselib │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── architecture │ │ │ ├── baseUI │ │ │ └── BaseActivity.kt │ │ │ └── baselib │ │ │ └── livedata │ │ │ ├── StateData.java │ │ │ └── StateLiveData.java │ └── res │ │ ├── layout │ │ └── activity_base.xml │ │ ├── values-night │ │ ├── colors.xml │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── architecture │ └── baselib │ └── ExampleUnitTest.kt ├── build.gradle ├── dozeAliveLib ├── .gitignore ├── CMakeLists.txt ├── ReadMe.md ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── anylife │ │ └── keepalive │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── dozealive_guide │ │ │ ├── css │ │ │ ├── all.css │ │ │ └── vn.css │ │ │ └── html │ │ │ ├── battery │ │ │ ├── Huawei │ │ │ │ ├── Huawei.html │ │ │ │ ├── step1.png │ │ │ │ ├── step2.png │ │ │ │ ├── step3.png │ │ │ │ └── step4.png │ │ │ └── Xiaomi │ │ │ │ ├── Xiaomi.html │ │ │ │ ├── step1.png │ │ │ │ └── step2.png │ │ │ └── daemon │ │ │ ├── Huawei │ │ │ ├── Huawei.html │ │ │ ├── step1.png │ │ │ └── step2.png │ │ │ └── Xiaomi │ │ │ ├── Xiaomi.html │ │ │ └── step1.png │ ├── cpp │ │ ├── time.cpp │ │ └── time.h │ ├── java │ │ └── com │ │ │ └── anylife │ │ │ └── keepalive │ │ │ ├── guide │ │ │ ├── DozeAliveSettingFragment.kt │ │ │ └── UploadWorker.kt │ │ │ ├── h5 │ │ │ └── H5DozeAliveGuideFragment.kt │ │ │ ├── keepalive │ │ │ ├── DozeAliveService.kt │ │ │ ├── DozeWakeUpManger.kt │ │ │ ├── MyWorker.kt │ │ │ ├── TaskImpl.kt │ │ │ ├── TaskParamObject.java │ │ │ └── WorkTaskImpl.kt │ │ │ ├── service │ │ │ ├── CancelNotifyService.java │ │ │ ├── ForegroundNF.java │ │ │ └── KeepAliveService.java │ │ │ ├── testhttp │ │ │ ├── BackGroundWork.kt │ │ │ ├── JsonApi.kt │ │ │ ├── JsonApiService.kt │ │ │ ├── JsonBean.kt │ │ │ └── TestActivity.java │ │ │ └── utils │ │ │ ├── AppUtils.java │ │ │ ├── BatteryOptimization.java │ │ │ ├── DozeServiceUtils.java │ │ │ ├── KeepCompactUtil.kt │ │ │ └── RestartSettingUtils.java │ └── res │ │ ├── drawable │ │ ├── bg_black_white_16.xml │ │ ├── bg_black_white_24.xml │ │ ├── bg_black_white_48.xml │ │ ├── progress_drawable.xml │ │ └── shape_set_btn_bg.xml │ │ ├── layout │ │ ├── activity_test.xml │ │ ├── fragment_h5_keep_alive_guide.xml │ │ └── fragment_keep_alive_setting.xml │ │ ├── mipmap │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ └── strings.xml │ │ └── 参考图 │ │ ├── 后台运行 │ │ ├── Huawei │ │ │ └── 华为不需要电池优化 │ │ ├── Samsung │ │ │ └── 三星后台.png │ │ └── Xiaomi │ │ │ └── Screenshot_后台运行_xiaomi.jpg │ │ └── 省电模式 │ │ ├── Huawei │ │ └── Screenshot_huawei.jpg │ │ ├── Samsung │ │ └── 三星省电.png │ │ └── Xiaomi │ │ └── Screenshot_省电_xiaomi.jpg │ └── test │ └── java │ └── com │ └── anylife │ └── keepalive │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── network ├── .gitignore ├── NetWork.md ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── architecture │ │ └── httplib │ │ ├── base │ │ ├── BaseHttpApiService.kt │ │ └── IHttpRequestBaseInfo.java │ │ ├── beans │ │ ├── BusinessBaseResponse.kt │ │ ├── FakerBaseResponse.kt │ │ └── HttpEmptyResponse.kt │ │ ├── core │ │ ├── HttpResponseCall.kt │ │ ├── HttpResponseCallAdapterFactory.kt │ │ ├── HttpResult.kt │ │ └── MoshiResultTypeAdapterFactory.kt │ │ ├── error │ │ ├── BusinessException.kt │ │ └── GlobalErrorHandler.kt │ │ ├── interceptor │ │ ├── CommonRequestInterceptor.java │ │ └── CommonResponseInterceptor.java │ │ └── utils │ │ └── MoshiUtils.kt │ └── res │ └── xml │ └── network_security_config.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | 13 | 14 | dbMaster/ 15 | *.hprof 16 | *.bak 17 | build/* 18 | */build/* 19 | .idea/* 20 | 21 | jni_lib/ 22 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | 2 | # Android 网络请求封装总结 3 | 4 | Android Http 网络请求封装,使用 Kotlin+Moshi+Coroutines+retrofit等封装处理Http请求,支持多个域名多态数据返回。封装要达到的目的特性就一个:简洁的同步代码风格处理网络异步请求! 5 | GitHub 封装演示代码:https://github.com/AnyLifeZLB/Android-Architecture 6 | 7 | 8 | 为什么要使用以下技术栈: 9 | 10 | - 协程 Coroutines 而不是rxjava:rxjava 是个好东西但不是官方的,学习成本也高,后期官方推荐kotlin,引入协程简洁优雅处理网络请求 11 | - Moshi 而不是Gson: Moshi 天生支持Kotlin空安全,使用CodeGen生成代码比Gson反射注解效率高 12 | - Retrofit 而不是直接OKHTTP :因为Retrofit使用注解+动态代理来优雅的封装调度OKHTTP去执行 13 | - 哪怕是使用自家的OkHttp,哪怕底层调用的始终是OkHttpClient,也需要依赖一个抽象的retrofit2.Call接口,依赖于抽象,而不是依赖于具体 14 | - 同步的方式写异步请求。简洁,简洁,目标只有一个:使用快捷方便简洁 ! 15 | 16 | ## 封装能达到的效果/目标 17 | - 1. 多域名Host,多个环境,多态返回数据处理 18 | - 2. 使用最新稳定的技术方案实现快捷稳定的请求交互 19 | - 3. 封装各种Http异常处理,服务器返回的各种异常json 数据 20 | - 4. 21 | 22 | 23 | ## 1.关于 [Retrofit](https://www.jianshu.com/p/f57b7cdb1c99) 24 | 25 | Retrofit的设计非常插件化而且轻量级,接口设计真的是非常高内聚而且低耦合,**精妙的设计是极佳的研究素材**。Retrofit底层请求 默认由OKHTTP执行, 26 | Retrofit主要负责调度;其中 Retrofit中定义了4个接口: 27 | 28 | - Callback 接口 29 | 这个接口就是retrofit请求数据返回的接口,只有两个方法 30 | * void onResponse(Response response); 31 | * void onFailure(Throwable t); 32 | 33 | - Converter 34 | 这个接口主要的作用就是将HTTP返回的数据解析成Java对象,主要有Xml、Gson、protobuf等等,你可以在创建Retrofit对象时添加你需要使用的Converter实现(看上面创建Retrofit对象的代码) 35 | 36 | - Call 37 | 这个接口主要的作用就是发送一个HTTP请求,Retrofit默认的实现是OkHttpCall,你可以根据实际情况实现你自己的Call类,这个设计和Volley的HttpStack接口设计的思想非常相似,子类可以实现基于HttpClient或HttpUrl Connection的HTTP请求工具,这种设计非常的插件化,而且灵活 38 | 39 | - CallAdapter 40 | 网络请求执行器(Call)的适配器CallAdapter用于对原始Call进行再次封装,如Call到Observable或者本SDK 中的HttpResult 41 | 42 | 43 | 44 | ## 2.[协程Coroutines](https://rengwuxian.com/kotlin-coroutines-1/) 45 | 46 | 「协程 Coroutines」源自 Simula 和 Modula-2 语言,这个术语早在 1958 年就被 Melvin Edward Conway 发明并用于构建汇编程序,说明协程是一种编程思想,并不局限于特定的语言; 协程设计的初衷是为了解决并发问题,让 「协作式多任务」 实现起来更加方便。 47 | 48 | 在Android中使用协程的环境分为下面五种环境: 49 | 50 | * 网络请求 51 | * 回调处理 52 | * 数据库操作 53 | * 文件操作 54 | * 其他耗时操作 55 | 56 | 57 | ## 3.数据返回封装 58 | 59 | 60 | 61 | | 字段 | 说明 | 62 | | :----: | -------- | 63 | | code | 业务返回状态码,注意业务状态码不要和标准Http状态码混淆 | 64 | | message | 返回补充说明信息 | 65 | | data[T] | 期待正常返回的业务数据 | 66 | 67 | 68 | 假设公司各个业务服务器返回的Http Json数据格式都差不多三个大字段code[int] + msg[str] +data[T] ,名称允许自定义不同 69 | 这里我们统一约定称含有三个类似字段为包装数据Http wrapper data定义为HttpWrapper.kt,每个Http请求正常都会含有这三个字段, 70 | data字段很自然的我们会使用范型T来表示,这也是Http 请求回来实际参与业务处理的部分 . 71 | - [code] 本字段表示业务服务是否获取了期待的数据,一般0或200 表示成功,其他值表示没有获取正常期望的业务数据如权限不足 72 | 另外,这个业务code 要和标准Http 请求响应的编码区分清除,标准Http 2xx 表示成功,4xx表示客户端错误,5xx 是服务器错误 73 | 强烈建议业务code 的返回值不要和标准Http 请求响应的编码有重合避开[2xx,5xx]范围 74 | - [msg] msg 是对业务code的补充说明,可以简单的是OK 或者对应的异常提示信息 75 | 76 | 77 | 78 | 79 | 80 | ![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f386a021023241db9adbb45610aa4b11~tplv-k3u1fbpfcp-watermark.image?) 81 | 82 | 如果你的App 请求的业务服务器返回json不包含类似这三字段结构也没关系:不是标准的HttpWrapper了,不需要实现HttpWrapper impl,相应的判断需要使用的时候进行补齐。 83 | 84 | ``` 85 | //不是标准的HttpWrapper 86 | viewModelScope.launch { 87 | when (val result = EuropeanaApiService.getService().getEuropData()) { 88 | is HttpResult.Success -> { 89 | if(result.data.success){ 90 | Log.e("Success", MoshiUtils.toJson(result.data.items)) //多一层链路.item 91 | }else{ 92 | Log.e("code is not ok","") 93 | } 94 | } 95 | 96 | is HttpResult.Failure -> { 97 | Log.e("Failure", result.message + " ----- " + result.code) 98 | } 99 | } 100 | } 101 | ``` 102 | 103 | 而有标准HttpWrapper 结构就能写法上更简洁,少了一层判断和一层数据拆箱 result.data.items 104 | ``` 105 | //标准的HttpWrapper 106 | viewModelScope.launch { 107 | when (val result = ExceptionApiService.getService().status404()) { 108 | is HttpResult.Success -> { 109 | Log.e("Success", MoshiUtils.toJson(result.data)) 110 | } 111 | 112 | is HttpResult.Failure -> { 113 | Log.e("Failure", result.message + " ----- " + result.code) 114 | } 115 | } 116 | } 117 | ``` 118 | 119 | 120 | 在 HttpResponseCall<> 类中我们根据http 请求是否成功,4xx,5xx 分别对应处理返回HttpResult中的 121 | - Success 成功获取期待的数据data范型T 122 | - Failure(msg,code) 包含了业务错误和Http 请求异常(timeout,networkerror) 123 | 124 | 125 | 更多请移步GitHub下载代码查看,欢迎建议改进。 126 | 127 | 128 | ## 4.Moshi 解析空安全处理,默认值情况 129 | 这个情况非常多,大部分的闪退和异常源于数据的异常,比如某个必有字段没有返回,导致异常 130 | 还有就是有些字段需要设置后端没有返回的时候的默认值 131 | 132 | ## 5.LiveData 还是Flow ? 133 | 134 | 为了简单演示,Demo 中使用的是LiveData,如果你的项目都用Kotlin 编写了,建议迁移到Flow 135 | 从 LiveData 迁移到 Kotlin 数据流:https://juejin.cn/post/6979008878029570055 136 | 137 | 138 | 139 | 140 | ## 参考文档 141 | - Retrofit 2.0源码分析 https://www.jianshu.com/p/0c055ad46b6c 142 | - 从架构角度看Retrofit https://www.jianshu.com/p/f57b7cdb1c99 143 | 144 | 145 | ## 感谢以下第三方Api 提供方,如果失效请查看官网进行替换 146 | * https://api.europeana.eu/record/v2/search.json 147 | * https://fakerapi.it/en 148 | * https://www.wanandroid.com 149 | 150 | 或者使用 [json-server](https://github.com/typicode/json-server) 号称环境准备好了30秒就能启动服务 151 | 简易使用教程:https://juejin.cn/spost/7371986999164960778 152 | 153 | -------------------------------------------------------------------------------- /antiDebug/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /.cxx 3 | ./.cxx -------------------------------------------------------------------------------- /antiDebug/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | 8 | # Creates and names a library, sets it as either STATIC 9 | # or SHARED, and provides the relative paths to its source code. 10 | # You can define multiple libraries, and CMake builds them for you. 11 | # Gradle automatically packages shared libraries with your APK. 12 | 13 | add_library( # Sets the name of the library. 14 | AntiDebug-lib 15 | 16 | # Sets the library as a shared library. 17 | SHARED 18 | 19 | # Provides a relative path to your source file(s). 20 | src/main/cpp/AntiDebug-lib.cpp ) 21 | 22 | # Searches for a specified prebuilt library and stores the path as a 23 | # variable. Because CMake includes system libraries in the search path by 24 | # default, you only need to specify the name of the public NDK library 25 | # you want to add. CMake verifies that the library exists before 26 | # completing its build. 27 | 28 | find_library( # Sets the name of the path variable. 29 | log-lib 30 | 31 | # Specifies the name of the NDK library that 32 | # you want CMake to locate. 33 | log ) 34 | 35 | # Specifies libraries CMake should link to your target library. You 36 | # can link multiple libraries, such as libraries you define in this 37 | # build script, prebuilt third-party libraries, or system libraries. 38 | 39 | target_link_libraries( # Specifies the target library. 40 | AntiDebug-lib 41 | 42 | # Links the target library to the log library 43 | # included in the NDK. 44 | ${log-lib} ) -------------------------------------------------------------------------------- /antiDebug/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | } 4 | 5 | android { 6 | namespace 'com.anylife.antidebugtest' 7 | compileSdk 34 8 | 9 | defaultConfig { 10 | minSdk 21 11 | 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | consumerProguardFiles "consumer-rules.pro" 14 | 15 | externalNativeBuild { 16 | cmake { 17 | cppFlags "" 18 | } 19 | } 20 | } 21 | 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | compileOptions { 29 | sourceCompatibility JavaVersion.VERSION_1_8 30 | targetCompatibility JavaVersion.VERSION_1_8 31 | } 32 | 33 | externalNativeBuild { 34 | cmake { 35 | path "CMakeLists.txt" 36 | } 37 | } 38 | 39 | } 40 | 41 | 42 | 43 | dependencies { 44 | 45 | 46 | testImplementation 'junit:junit:4.13.2' 47 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 48 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 49 | } -------------------------------------------------------------------------------- /antiDebug/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyLifeZLB/Android-Architecture/3914a2bc9749366c052a91a9bda92716f5ba427d/antiDebug/consumer-rules.pro -------------------------------------------------------------------------------- /antiDebug/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 -------------------------------------------------------------------------------- /antiDebug/src/androidTest/java/com/anylife/antidebugtest/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.anylife.antidebugtest; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.anylife.antidebugtest.test", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /antiDebug/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /antiDebug/src/main/cpp/AntiDebug-lib.h: -------------------------------------------------------------------------------- 1 | #ifndef _ANTIDEBUG 2 | #define _ANTIDEBUG 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | extern void readStatus(); 24 | 25 | extern void AntiDebug(); 26 | 27 | extern void CalcTime(int, int); 28 | 29 | void safe_attach(pid_t pid); 30 | 31 | void handle_events(); 32 | 33 | void checkDebugger(); 34 | 35 | void checkAndroidServer(); 36 | 37 | void runInotify(); 38 | 39 | void anti_ptrace(); 40 | 41 | void checkDebug(); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /antiDebug/src/main/java/com/anylife/antidebug/AntiDebugInterface.java: -------------------------------------------------------------------------------- 1 | package com.anylife.antidebug; 2 | 3 | /** 4 | * 5 | * 6 | * Created by zenglb on 2018/7/26. 7 | */ 8 | public class AntiDebugInterface { 9 | 10 | static { 11 | System.loadLibrary("AntiDebug-lib"); 12 | } 13 | 14 | /** 15 | * A native method that is implemented by the 'native-lib' native library, 16 | * which is packaged with this application. 17 | */ 18 | 19 | public static native void checkDebug(); 20 | 21 | 22 | 23 | } 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | //CPP 代码下载链接:https://download.csdn.net/download/weixin_30406497/10565565 -------------------------------------------------------------------------------- /antiDebug/src/test/java/com/anylife/antidebugtest/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.anylife.antidebugtest; 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 | } -------------------------------------------------------------------------------- /archi-test/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /archi-test/Archi.md: -------------------------------------------------------------------------------- 1 | # Google 官方App架构指南 2 | 关于Android 的架构建议:https://developer.android.com/topic/architecture/recommendations?hl=zh-cn#ui-layer 3 | 4 | 5 | - data-binding 6 | 7 | 8 | 9 | - Jetpack Compose 10 | 这是面向未来的,不要全部大规模使用先小规模用一下子,暂时还是使用Layout 吧,但是简单的页面完全可以使用Compose 了 11 | * https://developer.android.com/jetpack/compose?hl=zh-cn 12 | * https://rengwuxian.com/compose-vs-view/ 13 | * 14 | 15 | 16 | -------------------------------------------------------------------------------- /archi-test/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id("com.google.devtools.ksp").version("1.9.22-1.0.17") 5 | } 6 | 7 | android { 8 | namespace 'com.architecture.demo' 9 | compileSdk 33 10 | 11 | defaultConfig { 12 | applicationId "com.architecture.demo" 13 | minSdkVersion 23 14 | targetSdkVersion 33 15 | versionCode 1 16 | versionName "3.1.0" 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_11 28 | targetCompatibility JavaVersion.VERSION_11 29 | } 30 | 31 | kotlinOptions { 32 | jvmTarget = "11" 33 | } 34 | 35 | 36 | composeOptions { 37 | //https://developer.android.com/jetpack/androidx/releases/compose-compiler?hl=zh-cn 38 | kotlinCompilerExtensionVersion '1.5.8' 39 | } 40 | 41 | buildFeatures { 42 | compose true 43 | viewBinding true //https://developer.android.com/topic/libraries/view-binding?hl=zh-cn 44 | } 45 | 46 | } 47 | 48 | 49 | dependencies { 50 | 51 | 52 | // Kotlin + coroutines 53 | implementation("androidx.work:work-runtime-ktx:2.8.1") 54 | 55 | 56 | 57 | implementation project(":antiDebug") 58 | implementation project(':dozeAliveLib') 59 | 60 | 61 | implementation project(":network") 62 | implementation project(":base") 63 | 64 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 65 | implementation 'androidx.navigation:navigation-fragment-ktx:2.5.2' 66 | implementation 'androidx.navigation:navigation-ui-ktx:2.5.2' 67 | 68 | def htextview_version = "0.1.2" 69 | implementation "com.hanks:htextview-base:$htextview_version" // base library 70 | implementation "com.hanks:htextview-fade:$htextview_version" // optional 71 | 72 | implementation 'androidx.core:core-ktx:1.8.0' 73 | implementation 'androidx.appcompat:appcompat:1.5.1' 74 | implementation 'com.google.android.material:material:1.7.0' 75 | 76 | // Integration with activities 77 | implementation 'androidx.activity:activity-compose:1.3.0' 78 | 79 | 80 | // Compose Material Design 81 | implementation 'androidx.compose.material:material:1.1.1' 82 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1' 83 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' 84 | ksp "com.squareup.moshi:moshi-kotlin-codegen:1.14.0" 85 | 86 | } -------------------------------------------------------------------------------- /archi-test/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 -------------------------------------------------------------------------------- /archi-test/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /archi-test/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyLifeZLB/Android-Architecture/3914a2bc9749366c052a91a9bda92716f5ba427d/archi-test/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/application/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.application; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.os.Build; 8 | import android.os.PowerManager; 9 | import android.provider.Settings; 10 | 11 | import androidx.annotation.RequiresApi; 12 | 13 | import com.architecture.demo.http.HttpBaseInfo; 14 | import com.architecture.httplib.base.BaseHttpApiService; 15 | 16 | /** 17 | * MainApplication 18 | * 19 | */ 20 | public class MainApplication extends Application { 21 | public static boolean isTerminate=false; 22 | 23 | 24 | public void onCreate(){ 25 | super.onCreate(); 26 | 27 | 28 | //初始化的时候要传入的参数 29 | BaseHttpApiService.Companion.init(new HttpBaseInfo(this)); 30 | } 31 | 32 | /** 33 | * 要注意仅仅是主进程结束才是结束,这里没有多进程,简单处理 34 | */ 35 | @Override 36 | public void onTerminate() { 37 | super.onTerminate(); 38 | isTerminate=true; 39 | 40 | } 41 | 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/HttpBaseInfo.java: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http; 2 | 3 | import android.app.Application; 4 | 5 | import com.architecture.demo.BuildConfig; 6 | import com.architecture.httplib.base.IHttpRequestBaseInfo; 7 | 8 | /** 9 | * 全局的初始化,HTTP 请求的初始化,请求需要的基础信息 10 | * 11 | */ 12 | public class HttpBaseInfo implements IHttpRequestBaseInfo { 13 | private Application mApplication; 14 | 15 | public HttpBaseInfo(Application application){ 16 | this.mApplication = application; 17 | } 18 | 19 | @Override 20 | public String getAppVersionName() { 21 | return BuildConfig.VERSION_NAME; 22 | } 23 | 24 | @Override 25 | public String getAppVersionCode() { 26 | return String.valueOf(BuildConfig.VERSION_CODE); 27 | } 28 | 29 | @Override 30 | public boolean isDebug() { 31 | return BuildConfig.DEBUG; 32 | } 33 | 34 | @Override 35 | public Application getApplicationContext() { 36 | return mApplication; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/beans/AliParam.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.beans 2 | 3 | 4 | import com.squareup.moshi.Json 5 | import com.squareup.moshi.JsonClass 6 | 7 | 8 | @Deprecated("临时使用") 9 | 10 | @JsonClass(generateAdapter = true) 11 | data class AliParam( 12 | @Json(name = "input") 13 | val input: Input, 14 | @Json(name = "model") 15 | val model: String 16 | ) { 17 | @JsonClass(generateAdapter = true) 18 | data class Input( 19 | @Json(name = "messages") 20 | val messages: List 21 | ) { 22 | @JsonClass(generateAdapter = true) 23 | data class Message( 24 | @Json(name = "content") 25 | val content: List, 26 | @Json(name = "role") 27 | val role: String 28 | ) { 29 | @JsonClass(generateAdapter = true) 30 | data class Content( 31 | @Json(name = "image") 32 | val image: String, 33 | @Json(name = "text") 34 | val text: String 35 | ) 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/beans/BannerWithDefNPEField.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.beans 2 | 3 | 4 | import com.squareup.moshi.Json 5 | import com.squareup.moshi.JsonClass 6 | 7 | /** 8 | * 这里不需要 9 | * 10 | * 11 | */ 12 | @JsonClass(generateAdapter = true) 13 | data class BannerWithDefNPEField( 14 | @Json(name = "desc") 15 | val desc: String, 16 | @Json(name = "id") 17 | val id: Int, 18 | @Json(name = "imagePath") 19 | val imagePath: String, 20 | @Json(name = "isVisible") 21 | val isVisible: Int, 22 | @Json(name = "order") 23 | val order: Int, 24 | @Json(name = "title") 25 | val title: String, 26 | @Json(name = "type") 27 | val type: Int, 28 | @Json(name = "url") 29 | val url: String, 30 | 31 | 32 | @Json(name = "npeNameItsTestField") //差异在这里,没有这个值 33 | val npeNullAbleWithDef: String? = "It is Default Value", 34 | 35 | // @Json(name = "npeNonNull") 36 | // val npeNonNull: String //? !! 37 | ) -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/beans/EuropeanaBean.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.beans 2 | 3 | import com.squareup.moshi.Json 4 | import com.squareup.moshi.JsonClass 5 | 6 | 7 | /** 8 | * Moshi+codegen 9 | * 10 | * 11 | */ 12 | @JsonClass(generateAdapter = true) 13 | data class EuropeanaBean( 14 | 15 | @Json(name = "success") 16 | val success: Boolean, //是否成功 17 | 18 | @Json(name = "itemsCount") 19 | val itemsCount: Int, //item 个数 20 | 21 | @Json(name = "items") 22 | val items: List //item 内容 23 | 24 | // 剩下的字段丢弃,为了方便演示 25 | ) 26 | 27 | 28 | @JsonClass(generateAdapter = true) 29 | data class Item( 30 | @Json(name = "dataProvider") 31 | val dataProvider: List 32 | 33 | // 剩下的字段丢弃,为了方便演示 34 | 35 | ) -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/beans/FakerDataBean.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.beans 2 | import com.squareup.moshi.JsonClass 3 | 4 | import com.squareup.moshi.Json 5 | 6 | 7 | 8 | @JsonClass(generateAdapter = true) 9 | data class FakerDataBean( 10 | @Json(name = "addresses") 11 | val addresses: List, 12 | @Json(name = "contact") 13 | val contact: Contact, 14 | @Json(name = "country") 15 | val country: String, 16 | @Json(name = "email") 17 | val email: String, 18 | @Json(name = "id") 19 | val id: Int, 20 | @Json(name = "image") 21 | val image: String, 22 | @Json(name = "name") 23 | val name: String, 24 | @Json(name = "phone") 25 | val phone: String, 26 | @Json(name = "vat") 27 | val vat: String, 28 | @Json(name = "website") 29 | val website: String 30 | ) { 31 | @JsonClass(generateAdapter = true) 32 | data class Addresse( 33 | @Json(name = "buildingNumber") 34 | val buildingNumber: String, 35 | @Json(name = "city") 36 | val city: String, 37 | @Json(name = "country") 38 | val country: String, 39 | @Json(name = "county_code") 40 | val countyCode: String, 41 | @Json(name = "id") 42 | val id: Int, 43 | @Json(name = "latitude") 44 | val latitude: Double, 45 | @Json(name = "longitude") 46 | val longitude: Double, 47 | @Json(name = "street") 48 | val street: String, 49 | @Json(name = "streetName") 50 | val streetName: String, 51 | @Json(name = "zipcode") 52 | val zipcode: String 53 | ) 54 | 55 | @JsonClass(generateAdapter = true) 56 | data class Contact( 57 | @Json(name = "address") 58 | val address: Address, 59 | @Json(name = "birthday") 60 | val birthday: String, 61 | @Json(name = "email") 62 | val email: String, 63 | @Json(name = "firstname") 64 | val firstname: String, 65 | @Json(name = "gender") 66 | val gender: String, 67 | @Json(name = "id") 68 | val id: Int, 69 | @Json(name = "image") 70 | val image: String, 71 | @Json(name = "lastname") 72 | val lastname: String, 73 | @Json(name = "phone") 74 | val phone: String, 75 | @Json(name = "website") 76 | val website: String 77 | ) { 78 | @JsonClass(generateAdapter = true) 79 | data class Address( 80 | @Json(name = "buildingNumber") 81 | val buildingNumber: String, 82 | @Json(name = "city") 83 | val city: String, 84 | @Json(name = "country") 85 | val country: String, 86 | @Json(name = "county_code") 87 | val countyCode: String, 88 | @Json(name = "id") 89 | val id: Int, 90 | @Json(name = "latitude") 91 | val latitude: Double, 92 | @Json(name = "longitude") 93 | val longitude: Double, 94 | @Json(name = "street") 95 | val street: String, 96 | @Json(name = "streetName") 97 | val streetName: String, 98 | @Json(name = "zipcode") 99 | val zipcode: String 100 | ) 101 | } 102 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/beans/JsonBean.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.beans 2 | 3 | 4 | import com.squareup.moshi.Json 5 | import com.squareup.moshi.JsonClass 6 | 7 | @JsonClass(generateAdapter = true) 8 | data class JsonBean( 9 | @Json(name = "phone") 10 | val phone: String, 11 | @Json(name = "time") 12 | val time: String, 13 | @Json(name = "wifi") 14 | val wifi: String, 15 | 16 | 17 | @Json(name = "id") 18 | val id: Long, 19 | 20 | @Json(name = "timeStamp") 21 | val timeStamp: Long, 22 | 23 | 24 | ) -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/myinterface/AliApi.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.myinterface 2 | 3 | import com.architecture.demo.http.beans.AliParam 4 | import com.architecture.demo.http.beans.FakerDataBean 5 | import com.architecture.httplib.core.HttpResult 6 | import retrofit2.http.Body 7 | import retrofit2.http.GET 8 | import retrofit2.http.POST 9 | 10 | /** 11 | * 可以比较简单的造出各种数据 12 | * 13 | */ 14 | @Deprecated("临时使用") 15 | interface AliApi { 16 | 17 | // API 假如用不了不维护了。你可以自行替换可用的API https://fakerapi.it/en 18 | @POST("services/aigc/multimodal-generation/generation") 19 | suspend fun getFakerData(@Body a: AliParam): HttpResult 20 | 21 | 22 | 23 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/myinterface/EuropeanaApi.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.myinterface 2 | 3 | import com.architecture.demo.http.beans.EuropeanaBean 4 | import com.architecture.httplib.core.HttpResult 5 | import retrofit2.http.GET 6 | 7 | /** 8 | * 验证测试异常的情况 9 | * 10 | * 11 | */ 12 | interface EuropeanaApi { 13 | 14 | //测试直接写死参数 15 | @GET("search.json?wskey=gogesqui&query=Paris&reusability=open&media=true") 16 | suspend fun getEuropData(): HttpResult 17 | 18 | 19 | 20 | 21 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/myinterface/ExceptionApi.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.myinterface 2 | 3 | import com.architecture.httplib.core.HttpResult 4 | import com.architecture.httplib.beans.HttpEmptyResponse 5 | import retrofit2.http.GET 6 | 7 | /** 8 | * 验证测试异常的情况,保留验证 9 | * 10 | */ 11 | interface ExceptionApi { 12 | 13 | @GET("status/404") 14 | suspend fun status404( 15 | ): HttpResult 16 | 17 | 18 | @GET("status/501") 19 | suspend fun status501( 20 | ): HttpResult 21 | 22 | 23 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/myinterface/FakerApi.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.myinterface 2 | 3 | import com.architecture.demo.http.beans.FakerDataBean 4 | import com.architecture.httplib.core.HttpResult 5 | import retrofit2.http.GET 6 | 7 | /** 8 | * 可以比较简单的造出各种数据 9 | * 10 | */ 11 | interface FakerApi { 12 | 13 | // API 假如用不了不维护了。你可以自行替换可用的API https://fakerapi.it/en 14 | @GET("companies?_quantity=10") 15 | suspend fun getFakerData(): HttpResult> 16 | 17 | 18 | 19 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/myinterface/JsonApi.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.myinterface 2 | 3 | import com.architecture.demo.http.beans.JsonBean 4 | import com.architecture.httplib.core.HttpResult 5 | import retrofit2.http.Body 6 | import retrofit2.http.POST 7 | 8 | /** 9 | * 可以比较简单的造出各种数据 10 | * 11 | */ 12 | interface JsonApi { 13 | 14 | // API 假如用不了不维护了。你可以自行替换可用的API https://fakerapi.it/en 15 | @POST("TestData") 16 | suspend fun postJsonData(@Body l:JsonBean): HttpResult 17 | 18 | 19 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/myinterface/WannaAndroidApi.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.myinterface 2 | 3 | import com.architecture.demo.http.beans.BannerWithDefNPEField 4 | import com.architecture.httplib.core.HttpResult 5 | import retrofit2.http.GET 6 | 7 | /** 8 | * wanandroid 9 | * 10 | */ 11 | interface WannaAndroidApi { 12 | 13 | //测试直接写死参数 suspend 14 | @GET("banner/json") 15 | suspend fun getBanner(): HttpResult> 16 | 17 | 18 | 19 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/service/AliApiService.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.service 2 | 3 | import com.architecture.demo.http.myinterface.AliApi 4 | import com.architecture.demo.http.myinterface.FakerApi 5 | import com.architecture.httplib.core.MoshiResultTypeAdapterFactory 6 | import com.architecture.httplib.base.BaseHttpApiService 7 | import okhttp3.Interceptor 8 | 9 | /** 10 | * FakerApiService 11 | * 12 | */ 13 | @Deprecated("临时使用") 14 | object AliApiService : BaseHttpApiService("https://dashscope.aliyuncs.com/api/v1/") { 15 | 16 | override fun getInterceptor(): Interceptor { 17 | return Interceptor { chain -> 18 | val builder = chain.request().newBuilder() 19 | builder.addHeader("Content-Type", "application/json") 20 | builder.addHeader("Authorization", "Bearer sk-jFKisBOTle") 21 | // builder.addHeader("X-DashScope-WorkSpace", "application/json") 22 | // builder.addHeader("X-DashScope-SSE", "enable") 23 | 24 | chain.proceed(builder.build()) 25 | } 26 | } 27 | 28 | 29 | /** 30 | * 再次封装一次,减少调用的代码量 31 | * 32 | */ 33 | fun getService():AliApi{ 34 | return getService(AliApi::class.java) 35 | } 36 | 37 | 38 | 39 | /** 40 | * 把服务器返回的JSON 通用的大体结构字段定义出来,方便解析 41 | * 42 | * "status": "OK", 43 | "code": 200, 44 | "total": 15, 45 | "data": [ 46 | * 47 | */ 48 | override fun getHttpWrapperHandler(): MoshiResultTypeAdapterFactory.HttpWrapper{ 49 | 50 | return object : MoshiResultTypeAdapterFactory.HttpWrapper { 51 | override fun getStatusCodeKey(): String { 52 | return "code" 53 | } 54 | 55 | override fun getErrorMsgKey(): String { 56 | return "message" 57 | } 58 | 59 | override fun getDataKey(): String { 60 | return "data" 61 | } 62 | 63 | // 这个Host 服务器对应200 表示成功 64 | override fun isRequestSuccess(statusCode: Int): Boolean { 65 | return statusCode == 200 66 | } 67 | } 68 | } 69 | 70 | } 71 | 72 | -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/service/EuropeanaApiService.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.service 2 | 3 | import com.architecture.demo.http.myinterface.EuropeanaApi 4 | import com.architecture.demo.http.myinterface.ExceptionApi 5 | import com.architecture.httplib.core.MoshiResultTypeAdapterFactory 6 | import com.architecture.httplib.base.BaseHttpApiService 7 | import okhttp3.Interceptor 8 | 9 | /** 10 | * EuropeanaApiService 就是无法映射Http Base Wrapper Data,这里就只能自己判断数据是否成功了 11 | * 12 | */ 13 | object EuropeanaApiService : BaseHttpApiService("https://api.europeana.eu/record/v2/") { 14 | 15 | override fun getInterceptor(): Interceptor { 16 | return Interceptor { chain -> 17 | val builder = chain.request().newBuilder() 18 | chain.proceed(builder.build()) 19 | } 20 | } 21 | 22 | 23 | /** 24 | * Europeana ApiService 返回的不是标准code+msg+data HttpWrapper包装类 25 | * 26 | * @return 27 | */ 28 | override fun getHttpWrapperHandler(): MoshiResultTypeAdapterFactory.HttpWrapper? { 29 | //return null 30 | return super.getHttpWrapperHandler() 31 | } 32 | 33 | 34 | /** 35 | * 减少一点重复代码 36 | * 37 | */ 38 | fun getService(): EuropeanaApi { 39 | return super.getService(EuropeanaApi::class.java) 40 | } 41 | 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/service/ExceptionApiService.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.service 2 | 3 | import com.architecture.demo.http.myinterface.ExceptionApi 4 | import com.architecture.httplib.base.BaseHttpApiService 5 | import okhttp3.Interceptor 6 | 7 | 8 | /** 9 | * Rename XXX Service 10 | * 11 | */ 12 | object ExceptionApiService : BaseHttpApiService("https://httpbin.org/") { 13 | 14 | override fun getInterceptor(): Interceptor? { 15 | return null 16 | } 17 | 18 | /** 19 | * 再次封装一次,减少调用的代码量 20 | * 21 | */ 22 | fun getService(): ExceptionApi { 23 | return getService(ExceptionApi::class.java) 24 | } 25 | 26 | 27 | 28 | 29 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/service/FakerApiService.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.service 2 | 3 | import com.architecture.demo.http.myinterface.FakerApi 4 | import com.architecture.httplib.core.MoshiResultTypeAdapterFactory 5 | import com.architecture.httplib.base.BaseHttpApiService 6 | import okhttp3.Interceptor 7 | 8 | /** 9 | * FakerApiService 10 | * 11 | */ 12 | object FakerApiService : BaseHttpApiService("https://fakerapi.it/api/v1/") { 13 | 14 | override fun getInterceptor(): Interceptor { 15 | return Interceptor { chain -> 16 | val builder = chain.request().newBuilder() 17 | builder.addHeader("Source", "source") 18 | chain.proceed(builder.build()) 19 | } 20 | } 21 | 22 | 23 | /** 24 | * 再次封装一次,减少调用的代码量 25 | * 26 | */ 27 | fun getService():FakerApi{ 28 | return getService(FakerApi::class.java) 29 | } 30 | 31 | 32 | 33 | /** 34 | * 把服务器返回的JSON 通用的大体结构字段定义出来,方便解析 35 | * 36 | * "status": "OK", 37 | "code": 200, 38 | "total": 15, 39 | "data": [ 40 | * 41 | */ 42 | override fun getHttpWrapperHandler(): MoshiResultTypeAdapterFactory.HttpWrapper{ 43 | 44 | return object : MoshiResultTypeAdapterFactory.HttpWrapper { 45 | override fun getStatusCodeKey(): String { 46 | return "code" 47 | } 48 | 49 | override fun getErrorMsgKey(): String { 50 | return "status" 51 | } 52 | 53 | override fun getDataKey(): String { 54 | return "data" 55 | } 56 | 57 | // 这个Host 服务器对应200 表示成功 58 | override fun isRequestSuccess(statusCode: Int): Boolean { 59 | return statusCode == 200 60 | } 61 | } 62 | } 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/service/JsonApiService.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.service 2 | 3 | import com.architecture.demo.http.myinterface.FakerApi 4 | import com.architecture.demo.http.myinterface.JsonApi 5 | import com.architecture.httplib.core.MoshiResultTypeAdapterFactory 6 | import com.architecture.httplib.base.BaseHttpApiService 7 | import okhttp3.Interceptor 8 | 9 | /** 10 | * FakerApiService 11 | * 12 | */ 13 | object JsonApiService : BaseHttpApiService("http://10.39.179.70:4444/") { 14 | 15 | override fun getInterceptor(): Interceptor { 16 | return Interceptor { chain -> 17 | val builder = chain.request().newBuilder() 18 | builder.addHeader("Source", "source") 19 | chain.proceed(builder.build()) 20 | } 21 | } 22 | 23 | 24 | /** 25 | * 再次封装一次,减少调用的代码量 26 | * 27 | */ 28 | fun getService():JsonApi{ 29 | return getService(JsonApi::class.java) 30 | } 31 | 32 | 33 | 34 | /** 35 | * 把服务器返回的JSON 通用的大体结构字段定义出来,方便解析 36 | * 37 | * "status": "OK", 38 | "code": 200, 39 | "total": 15, 40 | "data": [ 41 | * 42 | */ 43 | override fun getHttpWrapperHandler(): MoshiResultTypeAdapterFactory.HttpWrapper{ 44 | 45 | return object : MoshiResultTypeAdapterFactory.HttpWrapper { 46 | override fun getStatusCodeKey(): String { 47 | return "code" 48 | } 49 | 50 | override fun getErrorMsgKey(): String { 51 | return "status" 52 | } 53 | 54 | override fun getDataKey(): String { 55 | return "data" 56 | } 57 | 58 | // 这个Host 服务器对应200 表示成功 59 | override fun isRequestSuccess(statusCode: Int): Boolean { 60 | return statusCode == 200 61 | } 62 | } 63 | } 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/http/service/WanAndroidApiService.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.http.service 2 | 3 | import com.architecture.demo.http.myinterface.WannaAndroidApi 4 | import com.architecture.httplib.core.MoshiResultTypeAdapterFactory 5 | import com.architecture.httplib.base.BaseHttpApiService 6 | import okhttp3.Interceptor 7 | 8 | 9 | /** 10 | * 测试域名为https://www.wanandroid.com/ 的服务 11 | * 12 | */ 13 | object WanAndroidApiService : BaseHttpApiService("https://www.wanandroid.com/") { 14 | 15 | override fun getInterceptor(): Interceptor { 16 | return Interceptor { chain -> 17 | val builder = chain.request().newBuilder() 18 | builder.addHeader("Source", "source") 19 | chain.proceed(builder.build()) 20 | } 21 | } 22 | 23 | 24 | /** 25 | * 获取WannaAndroidApi 服务 26 | * 27 | */ 28 | fun getService():WannaAndroidApi{ 29 | return getService(WannaAndroidApi::class.java) 30 | } 31 | 32 | 33 | 34 | /** 35 | * 把服务器返回的JSON 通用的大体结构字段定义出来,方便解析 36 | * 37 | * "status": "OK", 38 | "code": 200, 39 | "total": 15, 40 | "data": [ 41 | * 42 | */ 43 | override fun getHttpWrapperHandler(): MoshiResultTypeAdapterFactory.HttpWrapper{ 44 | 45 | return object : MoshiResultTypeAdapterFactory.HttpWrapper { 46 | override fun getStatusCodeKey(): String { 47 | return "errorCode" 48 | } 49 | 50 | override fun getErrorMsgKey(): String { 51 | return "errorMsg" 52 | } 53 | 54 | override fun getDataKey(): String { 55 | return "data" 56 | } 57 | 58 | override fun isRequestSuccess(statusCode: Int): Boolean { 59 | return statusCode == 0 //0 表示业务上是正确返回了数据 60 | } 61 | } 62 | } 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/test/socket/AndroidSocketClient.java: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.test.socket; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.OutputStream; 8 | import java.io.PrintWriter; 9 | import java.net.Socket; 10 | import java.net.UnknownHostException; 11 | 12 | /** 13 | * Android Socket 收取信息,弹框到通知栏 14 | * 保活验证调试,模拟网络数据传送和进程保活验证 15 | * 16 | * 参考: 17 | * 1 https://www.cnblogs.com/wisdo/p/5860001.html 18 | * 2 https://www.kancloud.cn/nov_93/java_socket/135525 19 | * 20 | */ 21 | class AndroidSocketClient { 22 | 23 | 24 | /** 25 | * 客户端 26 | * 27 | * @param args 28 | */ 29 | public static void main(String[] args) { 30 | 31 | try { 32 | //1、创建客户端Socket,指定服务器地址和端口 33 | Socket socket = new Socket("localhost",8886); 34 | //2、获取输出流,向服务端发送信息 35 | OutputStream os = socket.getOutputStream(); //字节输出流 36 | PrintWriter pw = new PrintWriter(os); //将输出流包装为打印流 37 | pw.write("用户名:admin; 密码:123"); 38 | pw.flush(); 39 | socket.shutdownOutput(); //关闭输出流 40 | //3.获取输入流,并读取服务器端的响应信息 41 | InputStream is= socket.getInputStream(); 42 | BufferedReader br = new BufferedReader(new InputStreamReader(is)); 43 | String info = null; 44 | while ((info = br.readLine()) != null) { 45 | // 循环读取客户端的信息 46 | System.out.println("我是客户端,服务端说:" + info); 47 | } 48 | //4.关闭资源 49 | br.close(); 50 | is.close(); 51 | pw.close(); 52 | os.close(); 53 | socket.close(); 54 | } catch (UnknownHostException e) { 55 | e.printStackTrace(); 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/test/socket/ServerThread.java: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.test.socket; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.OutputStream; 8 | import java.io.PrintWriter; 9 | import java.net.Socket; 10 | 11 | /* 12 | * 服务器线程处理类 13 | * 14 | * https://www.kancloud.cn/nov_93/java_socket/135526 15 | */ 16 | public class ServerThread extends Thread { 17 | // 和本线程相关的Socket 18 | Socket socket = null; 19 | public ServerThread(Socket socket) { 20 | this.socket = socket; 21 | } 22 | 23 | // 线程执行的操作,响应客户端的请求 24 | public void run() { 25 | InputStream is = null; 26 | InputStreamReader isr = null; 27 | BufferedReader br = null; 28 | OutputStream os = null; 29 | PrintWriter pw = null; 30 | try { 31 | System.out.println("服务器启动新连接"); 32 | 33 | 34 | while (true){ 35 | is = socket.getInputStream(); 36 | isr = new InputStreamReader(is); 37 | br = new BufferedReader(isr); 38 | String info = br.readLine(); 39 | if (info!=null&&info.length()!=0) { 40 | // 循环读取客户端的信息 41 | System.out.println("收到客户端信息:" + info); 42 | } 43 | // socket.shutdownInput();// 关闭输入流 44 | 45 | // 获取输出流,响应客户端的请求 46 | os = socket.getOutputStream(); 47 | pw = new PrintWriter(os); 48 | // pw.write("这是一条来自服务端的消息"); 49 | pw.println("这是一条来自服务端的消息 2"); 50 | pw.flush();// 调用flush()方法将缓冲输出 51 | 52 | sleep(1000); 53 | } 54 | 55 | 56 | } catch (IOException e) { 57 | System.out.println("IOException:" + e.toString()); 58 | 59 | } catch (InterruptedException e) { 60 | System.out.println("InterruptedException:" + e.toString()); 61 | throw new RuntimeException(e); 62 | } finally { 63 | // 关闭资源 64 | try { 65 | if (pw != null) { 66 | pw.close(); 67 | } 68 | if (os != null) { 69 | os.close(); 70 | } 71 | if (br != null) { 72 | br.close(); 73 | } 74 | if (isr != null) { 75 | isr.close(); 76 | } 77 | if (is != null) { 78 | is.close(); 79 | } 80 | if (socket != null) { 81 | socket.close(); 82 | } 83 | } catch (IOException e) { 84 | e.printStackTrace(); 85 | } 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/test/socket/SocketServer.java: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.test.socket; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 5 | import java.net.ServerSocket; 6 | import java.net.Socket; 7 | 8 | /** 9 | * 模拟推送,保活验证调试 10 | * https://www.kancloud.cn/nov_93/java_socket/135526 11 | */ 12 | public class SocketServer { 13 | 14 | /** 15 | * 基于TCP协议的Socket通信,实现用户登陆 服务器端 16 | * @param args 17 | */ 18 | public static void main(String[] args) { 19 | try { 20 | // 1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 21 | ServerSocket serverSocket = new ServerSocket(8894); 22 | Socket socket = null; 23 | // 记录客户端的数量 24 | int count = 0; 25 | System.out.println("***服务器启动***"); 26 | // 循环监听客户端的连接 27 | while (true) { 28 | socket = serverSocket.accept(); 29 | // 创建一个新的线程 30 | ServerThread serverThread = new ServerThread(socket); 31 | // 启动线程 32 | serverThread.start(); 33 | count++; 34 | System.out.println("客户端数量: " + count); 35 | InetAddress address = socket.getInetAddress(); 36 | System.out.println("当前客户端的IP: " + address.getHostAddress()+"\n"); 37 | } 38 | } catch (IOException e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/archi/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.archi 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.core.content.ContextCompat 7 | import androidx.navigation.findNavController 8 | import androidx.navigation.ui.AppBarConfiguration 9 | import androidx.navigation.ui.setupActionBarWithNavController 10 | import androidx.navigation.ui.setupWithNavController 11 | import com.anylife.keepalive.keepalive.DozeAliveService 12 | import com.anylife.keepalive.utils.DozeServiceUtils 13 | import com.architecture.demo.R 14 | import com.architecture.demo.databinding.ActivityDemoBinding 15 | import com.google.android.material.bottomnavigation.BottomNavigationView 16 | 17 | class MainActivity : AppCompatActivity() { 18 | 19 | private lateinit var binding: ActivityDemoBinding 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | 24 | binding = ActivityDemoBinding.inflate(layoutInflater) 25 | setContentView(binding.root) 26 | 27 | val navView: BottomNavigationView = binding.navView 28 | 29 | val navController = findNavController(R.id.nav_host_fragment_activity_demo) 30 | // Passing each menu ID as a set of Ids because each 31 | // menu should be considered as top level destinations. 32 | val appBarConfiguration = AppBarConfiguration( 33 | setOf( 34 | R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications 35 | ) 36 | ) 37 | 38 | setupActionBarWithNavController(navController, appBarConfiguration) 39 | navView.setupWithNavController(navController) 40 | 41 | 42 | //这里启动Notification,用于保活---不一定可用,多少有点用 43 | if (!DozeServiceUtils.isServiceRunning(DozeAliveService::class.java.toString(),baseContext)) { 44 | //支持传参数 45 | ContextCompat.startForegroundService(this, Intent(this, DozeAliveService::class.java)) 46 | } 47 | 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/archi/fragment/dashboard/DashboardFragment.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.archi.fragment.dashboard 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.TextView 8 | import androidx.fragment.app.Fragment 9 | import androidx.lifecycle.ViewModelProvider 10 | import com.architecture.demo.databinding.FragmentDashboardBinding 11 | 12 | class DashboardFragment : Fragment() { 13 | 14 | private var _binding: FragmentDashboardBinding? = null 15 | 16 | // This property is only valid between onCreateView and 17 | // onDestroyView. 18 | private val binding get() = _binding!! 19 | 20 | 21 | override fun onCreateView( 22 | inflater: LayoutInflater, 23 | container: ViewGroup?, 24 | savedInstanceState: Bundle? 25 | ): View { 26 | val dashboardViewModel = 27 | ViewModelProvider(this).get(DashboardViewModel::class.java) 28 | 29 | _binding = FragmentDashboardBinding.inflate(inflater, container, false) 30 | val root: View = binding.root 31 | 32 | val textView: TextView = binding.textDashboard 33 | dashboardViewModel.text.observe(viewLifecycleOwner) { 34 | textView.text = it 35 | } 36 | return root 37 | } 38 | 39 | override fun onDestroyView() { 40 | super.onDestroyView() 41 | _binding = null 42 | } 43 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/archi/fragment/dashboard/DashboardViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.archi.fragment.dashboard 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | 7 | class DashboardViewModel : ViewModel() { 8 | 9 | private val _text = MutableLiveData().apply { 10 | value = "This is dashboard Fragment" 11 | } 12 | val text: LiveData = _text 13 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/archi/fragment/home/HomeFragment.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.archi.fragment.home 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.Button 8 | import android.widget.TextView 9 | import androidx.fragment.app.Fragment 10 | import androidx.lifecycle.ViewModelProvider 11 | import com.architecture.baselib.livedata.StateData 12 | import com.architecture.demo.databinding.FragmentHomeBinding 13 | import com.architecture.httplib.utils.MoshiUtils 14 | 15 | /** 16 | * 使用FakeApi的数据 进行演示 17 | * 18 | */ 19 | class HomeFragment : Fragment() { 20 | 21 | private var _binding: FragmentHomeBinding? = null 22 | 23 | // This property is only valid between onCreateView and 24 | // onDestroyView. 25 | private val binding get() = _binding!! 26 | 27 | 28 | override fun onCreateView( 29 | inflater: LayoutInflater, 30 | container: ViewGroup?, 31 | savedInstanceState: Bundle? 32 | ): View { 33 | val homeViewModel = 34 | ViewModelProvider(this)[HomeViewModel::class.java] 35 | 36 | _binding = FragmentHomeBinding.inflate(inflater, container, false) 37 | val root: View = binding.root 38 | 39 | val textView: TextView = binding.textHome 40 | val button: Button = binding.btnHttp 41 | 42 | //把请求的数据格式返回了就可以了 43 | homeViewModel.text.observe(viewLifecycleOwner) { 44 | textView.text = it 45 | } 46 | 47 | 48 | homeViewModel.fakeDataList.observe(viewLifecycleOwner) { 49 | //转为json 50 | //还有异常的情况怎么办? 51 | textView.text = MoshiUtils.toJson(it.data) 52 | 53 | //有点啰嗦,写法上还是要精简一点 54 | homeViewModel.fakeDataList.observe(viewLifecycleOwner) { data -> 55 | when (data.status) { 56 | StateData.DataStatus.SUCCESS -> { 57 | 58 | } 59 | 60 | StateData.DataStatus.ERROR -> { 61 | 62 | }else -> { 63 | 64 | } 65 | } 66 | } 67 | } 68 | 69 | 70 | 71 | button.setOnClickListener { 72 | homeViewModel.requestNet() 73 | } 74 | 75 | 76 | return root 77 | } 78 | 79 | 80 | override fun onDestroyView() { 81 | super.onDestroyView() 82 | _binding = null 83 | } 84 | 85 | 86 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/archi/fragment/home/HomeRepository.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.archi.fragment.home 2 | 3 | import android.util.Log 4 | import com.architecture.baselib.livedata.StateLiveData 5 | import com.architecture.demo.http.beans.FakerDataBean 6 | import com.architecture.demo.http.service.FakerApiService 7 | import com.architecture.httplib.core.HttpResult 8 | import com.architecture.httplib.utils.MoshiUtils 9 | 10 | /** 11 | * 12 | * 13 | */ 14 | class HomeRepository { 15 | 16 | /** 17 | * 精简一下各种error,对于业务层来说没必要细分成这样,一个方法中区分就可以了! 18 | * 19 | * @param data 20 | */ 21 | suspend fun getFakerData(data:StateLiveData>) { 22 | 23 | // 需要再精简一下,有点啰嗦 24 | when (val result = FakerApiService.getService().getFakerData()) { 25 | is HttpResult.Success -> { 26 | //List 数据就直接出来了,方便极了 27 | data.postSuccess(result.data) 28 | Log.e("Success", MoshiUtils.toJson(result.data)) 29 | } 30 | 31 | is HttpResult.Failure ->{ 32 | Log.e("HttpResult.Failure", "错误编码:"+result.code+" 错误信息:"+result.message) 33 | } 34 | 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/archi/fragment/home/HomeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.archi.fragment.home 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import androidx.lifecycle.viewModelScope 7 | import com.architecture.baselib.livedata.StateLiveData 8 | import com.architecture.demo.http.beans.FakerDataBean 9 | import kotlinx.coroutines.launch 10 | 11 | 12 | /** 13 | * ViewModel 没啥好说的 14 | * 15 | */ 16 | class HomeViewModel : ViewModel() { 17 | 18 | private val _text = MutableLiveData().apply { 19 | value = "This is home Fragment" 20 | } 21 | 22 | val text: LiveData = _text 23 | 24 | private val repository by lazy { HomeRepository() } 25 | 26 | val fakeDataList = StateLiveData>() 27 | 28 | 29 | fun requestNet() { 30 | viewModelScope.launch { 31 | repository.getFakerData(fakeDataList) 32 | } 33 | } 34 | 35 | 36 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/archi/fragment/notifications/NotificationsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.archi.fragment.notifications 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.TextView 8 | import androidx.fragment.app.Fragment 9 | import androidx.lifecycle.ViewModelProvider 10 | import com.architecture.demo.databinding.FragmentNotificationsBinding 11 | 12 | class NotificationsFragment : Fragment() { 13 | 14 | private var _binding: FragmentNotificationsBinding? = null 15 | 16 | // This property is only valid between onCreateView and 17 | // onDestroyView. 18 | private val binding get() = _binding!! 19 | 20 | override fun onCreateView( 21 | inflater: LayoutInflater, 22 | container: ViewGroup?, 23 | savedInstanceState: Bundle? 24 | ): View { 25 | val notificationsViewModel = 26 | ViewModelProvider(this).get(NotificationsViewModel::class.java) 27 | 28 | _binding = FragmentNotificationsBinding.inflate(inflater, container, false) 29 | val root: View = binding.root 30 | 31 | val textView: TextView = binding.textNotifications 32 | notificationsViewModel.text.observe(viewLifecycleOwner) { 33 | textView.text = it 34 | } 35 | return root 36 | } 37 | 38 | override fun onDestroyView() { 39 | super.onDestroyView() 40 | _binding = null 41 | } 42 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/archi/fragment/notifications/NotificationsViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.archi.fragment.notifications 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | 7 | class NotificationsViewModel : ViewModel() { 8 | 9 | private val _text = MutableLiveData().apply { 10 | value = "This is notifications Fragment" 11 | } 12 | val text: LiveData = _text 13 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/keepalive/BackGroundWork.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.keepalive 2 | 3 | import android.Manifest 4 | import android.app.Application 5 | import android.content.Context 6 | import android.content.pm.PackageManager 7 | import android.net.wifi.WifiManager 8 | import android.os.BatteryManager 9 | import android.os.Build 10 | import android.util.Log 11 | import androidx.appcompat.app.AppCompatActivity 12 | import androidx.core.app.ActivityCompat 13 | import com.architecture.demo.http.beans.JsonBean 14 | import com.architecture.demo.http.service.JsonApiService 15 | import com.architecture.httplib.core.HttpResult 16 | import kotlinx.coroutines.GlobalScope 17 | import kotlinx.coroutines.launch 18 | import java.text.SimpleDateFormat 19 | import java.util.Date 20 | 21 | /** 22 | * 模拟后台持续收集数据,定位 23 | * 24 | */ 25 | class BackGroundWork { 26 | companion object { 27 | 28 | 29 | private fun stampToDate(s: Long): String { 30 | val res: String 31 | val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 32 | val date = Date(s) 33 | res = simpleDateFormat.format(date) 34 | return res 35 | } 36 | 37 | 38 | /** 39 | * 仅仅是验证,GlobalScope 谨慎使用 40 | * 41 | * @param mContext 42 | */ 43 | fun postJsonData(mContext: Application) { 44 | 45 | GlobalScope.launch { 46 | 47 | val batteryManager = 48 | mContext.getSystemService(Context.BATTERY_SERVICE) as BatteryManager 49 | 50 | val wifiService = 51 | mContext.getSystemService(AppCompatActivity.WIFI_SERVICE) as WifiManager 52 | 53 | var scanResultStr=" - " 54 | 55 | 56 | if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { 57 | val scanResultList=wifiService.scanResults 58 | for(s in scanResultList){ 59 | scanResultStr=scanResultStr+" "+s.SSID 60 | } 61 | } else { 62 | scanResultStr ="scan failed ******************* " 63 | } 64 | 65 | 66 | 67 | 68 | if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { 69 | val scanResultList=wifiService.scanResults 70 | for(s in scanResultList){ 71 | scanResultStr=scanResultStr+" "+s.BSSID 72 | } 73 | 74 | } else { 75 | scanResultStr ="scan failed ******************* " 76 | } 77 | 78 | 79 | val json = JsonBean( 80 | Build.BRAND + " ----- Service 外部 ----- " + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY), 81 | stampToDate(System.currentTimeMillis()), 82 | wifiService.connectionInfo.ssid + " ***** " + scanResultStr, 83 | System.currentTimeMillis(), 84 | System.currentTimeMillis() 85 | ) 86 | 87 | when (val result = JsonApiService.getService().postJsonData(json)) { 88 | is HttpResult.Success -> { 89 | //List 数据就直接出来了,方便极了 90 | Log.e("KeepAlive", "success") 91 | } 92 | 93 | is HttpResult.Failure -> { 94 | Log.e("KeepAlive", result.message + " ----- " + result.code) 95 | } 96 | } 97 | 98 | } 99 | } 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/keepalive/DozeAliveSettingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.keepalive 2 | 3 | import android.os.Bundle 4 | 5 | import com.architecture.baseUI.BaseActivity 6 | import com.architecture.demo.R 7 | 8 | 9 | /** 10 | * 用Fragment 便于封装引用 11 | * 12 | */ 13 | class DozeAliveSettingActivity : BaseActivity() { 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | setContentView(R.layout.activity_keep_alive_setting) 17 | 18 | setActivityTitle("App 运行权限管理",findViewById(R.id.toolbar)) 19 | 20 | 21 | intent.getStringExtra("CLSNAME") 22 | } 23 | 24 | 25 | 26 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/keepalive/H5DozeAliveGuideActivity.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.keepalive 2 | 3 | 4 | import android.os.Bundle 5 | import android.view.View 6 | import com.anylife.keepalive.R 7 | import com.anylife.keepalive.h5.H5DozeAliveGuideFragment 8 | import com.anylife.keepalive.utils.KeepCompactUtil 9 | import com.architecture.baseUI.BaseActivity 10 | import com.architecture.demo.databinding.ActivityH5DozealiveGuideBinding 11 | 12 | /** 13 | * H5 引导 14 | * 15 | */ 16 | open class H5DozeAliveGuideActivity : BaseActivity(),H5DozeAliveGuideFragment.FragmentListener { 17 | private lateinit var binding: ActivityH5DozealiveGuideBinding 18 | 19 | override fun onCreate(savedInstanceState: Bundle?) { 20 | super.onCreate(savedInstanceState) 21 | 22 | binding = ActivityH5DozealiveGuideBinding.inflate(layoutInflater) 23 | setContentView(binding.root) 24 | setActivityTitle("App 运行权限管理", binding.toolbar) 25 | 26 | 27 | val h5GuideFragment= H5DozeAliveGuideFragment.newInstance("") 28 | 29 | supportFragmentManager.beginTransaction() 30 | .add(R.id.container, h5GuideFragment) 31 | .commit() 32 | 33 | binding.goSetting.setOnClickListener { 34 | h5GuideFragment.goSetting() 35 | } 36 | 37 | 38 | val keepType=intent.getStringExtra(H5DozeAliveGuideFragment.KEEP_TYPE).toString() 39 | 40 | //华为特殊处理 41 | if(KeepCompactUtil.deviceEnum.toString()== KeepCompactUtil.PhoneBrandEnum.Huawei.toString()){ 42 | if(keepType == H5DozeAliveGuideFragment.KeepTypeMenu.daemon.toString()){ 43 | binding.goSetting.visibility= View.INVISIBLE 44 | } 45 | } 46 | 47 | } 48 | 49 | override fun process(str: String) { 50 | setActivityTitle(str, findViewById(R.id.toolbar)) 51 | } 52 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/navi/NaviActivity.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.navi 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import androidx.activity.ComponentActivity 6 | import androidx.activity.compose.setContent 7 | import androidx.core.content.ContextCompat 8 | import androidx.lifecycle.ViewModelProvider 9 | import com.anylife.keepalive.keepalive.DozeAliveService 10 | import com.anylife.keepalive.utils.DozeServiceUtils 11 | import com.architecture.demo.application.MainApplication 12 | import com.architecture.demo.ui.keepalive.BackGroundWork 13 | 14 | 15 | /*** 16 | * ComponentActivity :使用最新的尝试看看 17 | * 18 | */ 19 | class NaviActivity : ComponentActivity() { 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | 23 | val naviActivityScreenViewModel = 24 | ViewModelProvider(this)[NaviActivityScreenViewModel::class.java] 25 | 26 | 27 | //尝试使用Compose 吧,不需要大规模使用 28 | setContent { 29 | MainActivityScreen(naviActivityScreenViewModel) 30 | } 31 | 32 | 33 | // //定义一个run 34 | // val run= Runnable { 35 | // //模拟后台持续采集定位 36 | // BackGroundWork.postJsonData(application) 37 | // } 38 | 39 | 40 | Thread { 41 | try { 42 | //1、创建客户端Socket,指定服务器地址和端口 10.39.170.156 43 | 44 | while (!MainApplication.isTerminate) { 45 | //2、获取输出流,向服务端发送信息 46 | BackGroundWork.postJsonData(application) 47 | 48 | Thread.sleep(10000) 49 | } 50 | } catch (e: Exception) { 51 | e.printStackTrace() 52 | } finally { 53 | println("-- finally error -----------") 54 | } 55 | }.start() 56 | 57 | 58 | //这里启动Notification,用于保活---不一定可用,多少有点用 59 | if (!DozeServiceUtils.isServiceRunning(DozeAliveService::class.java.toString(),baseContext)) { 60 | val intent=Intent(this, DozeAliveService::class.java) 61 | 62 | //封装一下,支持传参数 63 | ContextCompat.startForegroundService(this, intent) 64 | } 65 | 66 | // DozeAliveService.s 67 | 68 | 69 | 70 | } 71 | 72 | 73 | 74 | 75 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/navi/NaviActivityScreen.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.navi 2 | 3 | import android.content.Intent 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.fillMaxHeight 7 | import androidx.compose.foundation.layout.fillMaxWidth 8 | import androidx.compose.foundation.layout.padding 9 | import androidx.compose.material.Button 10 | import androidx.compose.material.Text 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.ui.Alignment 13 | import androidx.compose.ui.Modifier 14 | import androidx.compose.ui.graphics.Color 15 | import androidx.compose.ui.platform.LocalContext 16 | import androidx.compose.ui.unit.dp 17 | import androidx.compose.ui.unit.sp 18 | import com.architecture.demo.ui.archi.MainActivity 19 | import com.architecture.demo.ui.keepalive.DozeAliveSettingActivity 20 | import com.architecture.demo.ui.keepalive.H5DozeAliveGuideActivity 21 | 22 | /** 23 | * Compose 编程 24 | * 25 | */ 26 | @Composable //响应式编程,既改既预览 https://developer.android.com/codelabs/jetpack-compose-basics?hl=zh-cn#0 27 | fun MainActivityScreen(viewModel: NaviActivityScreenViewModel) { 28 | Column( 29 | horizontalAlignment = Alignment.CenterHorizontally, 30 | verticalArrangement = Arrangement.Center, 31 | modifier = Modifier.fillMaxWidth().fillMaxHeight().padding(20.dp) 32 | ) { 33 | 34 | val context = LocalContext.current 35 | 36 | Button(onClick = { 37 | val intent = Intent(context, MainActivity::class.java) 38 | context.startActivity(intent) 39 | }, modifier = Modifier.padding(20.dp).fillMaxWidth()){ 40 | Text(text = "App架构重构", fontSize = 16.sp, color = Color.Green) 41 | } 42 | 43 | 44 | //应用保活设置 45 | Button(onClick = { 46 | val intent = Intent(context, DozeAliveSettingActivity::class.java) 47 | intent.putExtra("CLSNAME",H5DozeAliveGuideActivity::class.java.name) 48 | context.startActivity(intent) 49 | 50 | }, modifier = Modifier.padding(20.dp).fillMaxWidth()){ 51 | Text(text = "应用保活权限设置", fontSize = 16.sp, color = Color.Green) 52 | } 53 | 54 | 55 | 56 | Button(onClick = { 57 | viewModel.onGetFakeDataWithKotlinNpeClicked() 58 | }, modifier = Modifier.padding(20.dp).fillMaxWidth()){ 59 | Text(text = "Moshi的Kotlin Safe NPE", fontSize = 14.sp) 60 | } 61 | 62 | 63 | Button(onClick = { 64 | viewModel.onHttpWanHttp() 65 | }, modifier = Modifier.padding(20.dp).fillMaxWidth()){ 66 | Text(text = "Wan Banner Standard Wrapper ", fontSize = 14.sp) 67 | } 68 | 69 | 70 | Button(onClick = { 71 | viewModel.onEuropeanaRequest() 72 | }, modifier = Modifier.padding(20.dp).fillMaxWidth()){ 73 | Text(text = "Euro data unStandard Wrapper", fontSize = 14.sp) 74 | } 75 | 76 | 77 | Button(onClick = { 78 | viewModel.onHttpbinOrg404Clicked() 79 | }, modifier = Modifier.padding(20.dp).fillMaxWidth()){ 80 | Text(text = "httpbin.org的404返回", fontSize = 14.sp) 81 | } 82 | 83 | 84 | Button(onClick = { 85 | viewModel.onHttpbinOrg501Clicked() 86 | }, modifier = Modifier.padding(20.dp).fillMaxWidth()){ 87 | Text(text = "httpbin.org的501返回", fontSize = 14.sp) 88 | } 89 | 90 | } 91 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/navi/NaviActivityScreenViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.navi 2 | 3 | import android.util.Log 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.viewModelScope 6 | import com.architecture.demo.http.beans.FakerDataBean 7 | import com.architecture.demo.http.service.EuropeanaApiService 8 | import com.architecture.demo.http.service.FakerApiService 9 | import com.architecture.httplib.core.HttpResult 10 | import com.architecture.httplib.utils.MoshiUtils 11 | import com.architecture.demo.http.service.ExceptionApiService 12 | import com.architecture.demo.http.service.WanAndroidApiService 13 | import kotlinx.coroutines.launch 14 | 15 | /** 16 | * 使用场景还要简化再封装 17 | * 18 | * 19 | * ViewModel: https://developer.android.com/topic/libraries/architecture/viewmodel?hl=zh-cn 20 | * 21 | * LiveData 也是可以用一下的,不是所有的场景都要上复杂的东西, 22 | * 23 | */ 24 | class NaviActivityScreenViewModel : ViewModel() { 25 | 26 | 27 | fun onGetFakeDataWithKotlinNpeClicked() { 28 | 29 | viewModelScope.launch { 30 | when (val result = FakerApiService.getService().getFakerData()) { 31 | is HttpResult.Success -> { 32 | //List 数据就直接出来了,方便极了 33 | val fakeData: List = result.data 34 | Log.e("HTTP Success", MoshiUtils.toJson(fakeData)) 35 | } 36 | 37 | is HttpResult.Failure -> { 38 | Log.e("HTTP Failure", result.message + " ----- " + result.code) 39 | } 40 | 41 | } 42 | } 43 | } 44 | 45 | 46 | /** 47 | * viewModelScope.launch { 每个请求都要这样写太繁琐了吧 48 | * 49 | */ 50 | fun onHttpWanHttp() { 51 | 52 | viewModelScope.launch { 53 | val result = WanAndroidApiService.getService().getBanner() 54 | when (result) { 55 | is HttpResult.Success -> { 56 | Log.e("Success", MoshiUtils.toJson(result.data)) 57 | } 58 | 59 | is HttpResult.Failure -> { 60 | Log.e("Failure", result.message + " ----- " + result.code) 61 | } 62 | 63 | } 64 | } 65 | 66 | } 67 | 68 | 69 | /** 70 | * Europeana ApiService 返回的不是标准code+msg+data HttpWrapper包装类 71 | * 72 | */ 73 | fun onEuropeanaRequest() { 74 | viewModelScope.launch { 75 | when (val result = EuropeanaApiService.getService().getEuropData()) { 76 | is HttpResult.Success -> { 77 | if(result.data.success){ 78 | Log.e("Success", MoshiUtils.toJson(result.data.items)) //多一层链路.item 79 | }else{ 80 | Log.e("code is not ok","") 81 | } 82 | } 83 | 84 | is HttpResult.Failure -> { 85 | Log.e("Failure", result.message + " ----- " + result.code) 86 | } 87 | } 88 | } 89 | } 90 | 91 | 92 | fun onHttpbinOrg404Clicked() { 93 | viewModelScope.launch { 94 | when (val result = ExceptionApiService.getService().status404()) { 95 | is HttpResult.Success -> { 96 | Log.e("Success", MoshiUtils.toJson(result.data)) 97 | } 98 | 99 | is HttpResult.Failure -> { 100 | Log.e("Failure", result.message + " ----- " + result.code) 101 | } 102 | } 103 | } 104 | } 105 | 106 | 107 | fun onHttpbinOrg501Clicked() { 108 | 109 | viewModelScope.launch { 110 | when (val result = ExceptionApiService.getService().status501()) { 111 | 112 | is HttpResult.Success -> { 113 | Log.e("Success", MoshiUtils.toJson(result.data)) 114 | } 115 | 116 | is HttpResult.Failure -> { 117 | Log.e("Failure", result.message + " ----- " + result.code) 118 | } 119 | 120 | } 121 | } 122 | } 123 | 124 | 125 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/navi/alitest/AliActivity.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.navi.alitest 2 | 3 | import android.os.Bundle 4 | import android.widget.TextView 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.lifecycle.ViewModelProvider 7 | import com.architecture.demo.R 8 | 9 | @Deprecated("临时使用") 10 | class AliActivity : AppCompatActivity() { 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | setContentView(R.layout.activity_ali) 14 | 15 | val message=findViewById(R.id.message) 16 | 17 | 18 | val aliViewModel = 19 | ViewModelProvider(this)[AliViewModel::class.java] 20 | 21 | message.setOnClickListener{ 22 | aliViewModel.requestNet() 23 | } 24 | 25 | 26 | 27 | //把请求的数据格式返回了就可以了 28 | aliViewModel.fakeDataList.observe(this) { 29 | message.text = it.toString() 30 | } 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/navi/alitest/AliRepository.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.navi.alitest 2 | 3 | import android.util.Log 4 | import com.architecture.baselib.livedata.StateLiveData 5 | import com.architecture.demo.http.beans.AliParam 6 | import com.architecture.demo.http.beans.FakerDataBean 7 | import com.architecture.demo.http.service.AliApiService 8 | import com.architecture.httplib.core.HttpResult 9 | import com.architecture.httplib.utils.MoshiUtils 10 | 11 | /** 12 | * 13 | */ 14 | @Deprecated("临时使用") 15 | class AliRepository { 16 | 17 | /** 18 | * 精简一下各种error,对于业务层来说没必要细分成这样,一个方法中区分就可以了! 19 | * 20 | * @param data 21 | */ 22 | suspend fun getFakerData(data:StateLiveData) { 23 | 24 | 25 | val messages: MutableList = ArrayList() 26 | val contents: MutableList = ArrayList() 27 | contents.add( 28 | AliParam.Input.Message.Content( 29 | "https://dashscope.oss-cn-beijing.aliyuncs.com/images/dog_and_girl.jpeg", 30 | "这个图片是哪里?" 31 | ) 32 | ) 33 | messages.add(AliParam.Input.Message(contents, "user")) 34 | 35 | val input = AliParam.Input(messages) 36 | val aliAiParam = AliParam(input, "qwen-vl-plus") 37 | 38 | 39 | // 需要再精简一下,有点啰嗦 40 | when (val result = AliApiService.getService().getFakerData(aliAiParam)) { 41 | is HttpResult.Success -> { 42 | //List 数据就直接出来了,方便极了 43 | data.postSuccess(result.data) 44 | Log.e("Success", MoshiUtils.toJson(result.data)) 45 | } 46 | 47 | is HttpResult.Failure ->{ 48 | Log.e("HttpResult.Failure", "错误编码:"+result.code+" 错误信息:"+result.message) 49 | } 50 | 51 | } 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/navi/alitest/AliViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.navi.alitest 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import androidx.lifecycle.viewModelScope 7 | import com.architecture.baselib.livedata.StateLiveData 8 | import com.architecture.demo.http.beans.FakerDataBean 9 | import kotlinx.coroutines.launch 10 | 11 | 12 | /** 13 | * ViewModel 没啥好说的 14 | * 15 | */ 16 | @Deprecated("临时使用") 17 | class AliViewModel : ViewModel() { 18 | 19 | private val _text = MutableLiveData().apply { 20 | value = "This is home Fragment" 21 | } 22 | 23 | val text: LiveData = _text 24 | 25 | private val repository by lazy { AliRepository() } 26 | 27 | val fakeDataList = StateLiveData() 28 | 29 | 30 | fun requestNet() { 31 | viewModelScope.launch { 32 | repository.getFakerData(fakeDataList) 33 | } 34 | } 35 | 36 | 37 | } -------------------------------------------------------------------------------- /archi-test/src/main/java/com/architecture/demo/ui/navi/alitest/test.java: -------------------------------------------------------------------------------- 1 | package com.architecture.demo.ui.navi.alitest; 2 | 3 | import com.architecture.demo.http.beans.AliParam; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | @Deprecated 9 | class test { 10 | //https://p8.itc.cn/q_70/images03/20220218/982b02f3d9d7448d8ae5bc0298f4d55c.jpeg 11 | public void test(){ 12 | List messages=new ArrayList<>(); 13 | List contents=new ArrayList<>(); 14 | contents.add(new AliParam.Input.Message.Content("https://p8.itc.cn/q_70/images03/20220218/982b02f3d9d7448d8ae5bc0298f4d55c.jpeg","这个图片是哪里?")); 15 | messages.add(new AliParam.Input.Message(contents,"user")); 16 | 17 | AliParam.Input input=new AliParam.Input(messages); 18 | AliParam aliParam=new AliParam(input,"qwen-vl-plus"); 19 | 20 | 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /archi-test/src/main/res/drawable/ic_dashboard_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /archi-test/src/main/res/drawable/ic_home_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /archi-test/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 14 | 17 | 20 | 23 | 26 | 29 | 32 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /archi-test/src/main/res/drawable/ic_notifications_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /archi-test/src/main/res/drawable/shape_blue_btn_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /archi-test/src/main/res/drawable/shape_green_btn_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /archi-test/src/main/res/layout/activity_ali.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /archi-test/src/main/res/layout/activity_demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 31 | 32 | -------------------------------------------------------------------------------- /archi-test/src/main/res/layout/activity_h5_dozealive_guide.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 28 | 29 | 30 | 31 | 39 | 40 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /archi-test/src/main/res/layout/activity_keep_alive_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 25 | 26 | -------------------------------------------------------------------------------- /archi-test/src/main/res/layout/fragment_dashboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /archi-test/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |