├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── deploymentTargetSelector.xml ├── gradle.xml ├── kotlinc.xml ├── migrations.xml ├── misc.xml └── vcs.xml ├── LICENSE ├── NetworkApiData ├── build.gradle ├── libs │ └── annotations.jar └── src │ └── main │ └── java │ └── com │ └── wx │ └── test │ └── api │ ├── data │ ├── BaiDuImageResponse.kt │ ├── BaiduDataBean.kt │ ├── BaseResponse.kt │ └── wanandroid │ │ ├── CommonResult.kt │ │ └── home │ │ ├── HomeData.kt │ │ ├── HomeItemBean.kt │ │ └── WanAndroidHome.kt │ ├── net │ └── NetApi.kt │ └── retrofit │ ├── HeaderInterceptor.kt │ ├── RequestBodyCreate.kt │ ├── RequestBodyWrapper.kt │ └── RetrofitUtils.kt ├── README.md ├── annotation_compiler ├── .gitignore ├── build.gradle ├── libs │ └── javax.inject-1.jar └── src │ └── main │ └── java │ └── com │ └── annotation_compiler │ ├── AnnotationsCompiler.java │ └── AptProcessor.kt ├── app_wx1 ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── wx │ │ └── architecture │ │ ├── MyApp.kt │ │ ├── code │ │ ├── app │ │ │ └── AppGlobals.kt │ │ ├── base │ │ │ ├── BaseFragment.kt │ │ │ ├── BaseViewModel.kt │ │ │ └── BaseViewModelActivity.kt │ │ ├── data │ │ │ └── DialogBean.kt │ │ ├── dialog │ │ │ └── ShowUIDialog.kt │ │ ├── ex │ │ │ ├── ExceptionEX.kt │ │ │ ├── Flow.kt │ │ │ └── Throwable.kt │ │ └── utils │ │ │ └── NetWorkHelp.kt │ │ ├── data_source │ │ ├── repository │ │ │ └── NetRepository.kt │ │ └── tata.kt │ │ └── ui │ │ ├── activity │ │ └── MainActivity.kt │ │ └── viewmodel │ │ └── MainViewModel.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ └── ic_loading.webp │ ├── drawable │ ├── ic_launcher_background.xml │ └── progressbar_shape.xml │ ├── layout │ ├── activity_main.xml │ └── layout_loading.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 │ ├── values-night │ └── themes.xml │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── app_wx2 ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── wx │ │ └── architecture │ │ ├── MyApp.kt │ │ ├── code │ │ ├── app │ │ │ └── AppGlobals.kt │ │ ├── base │ │ │ ├── BaseFragment.kt │ │ │ ├── BaseViewModel.kt │ │ │ └── BaseViewModelActivity.kt │ │ ├── data │ │ │ └── DialogBean.kt │ │ ├── dialog │ │ │ └── ShowUIDialog.kt │ │ ├── ex │ │ │ ├── ExceptionEX.kt │ │ │ ├── Flow.kt │ │ │ └── Throwable.kt │ │ └── utils │ │ │ └── NetWorkHelp.kt │ │ ├── data_source │ │ ├── kapt │ │ │ └── KaptComponet.kt │ │ ├── repository │ │ │ └── BaseRepository.kt │ │ └── tata.kt │ │ └── ui │ │ ├── activity │ │ └── MainActivity.kt │ │ └── viewmodel │ │ └── MainViewModel.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ └── ic_loading.webp │ ├── drawable │ ├── ic_launcher_background.xml │ └── progressbar_shape.xml │ ├── layout │ ├── activity_main.xml │ └── layout_loading.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 │ ├── values-night │ └── themes.xml │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── app_wx3 ├── .gitignore ├── build.gradle ├── libs │ ├── annotation_compiler.jar │ └── annotations.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── wx │ │ └── architecture │ │ ├── MyApp.kt │ │ ├── code │ │ ├── app │ │ │ └── AppGlobals.kt │ │ ├── base │ │ │ ├── BaseFragment.kt │ │ │ ├── BaseRepositoryProxy.kt │ │ │ ├── BaseViewModel.kt │ │ │ └── BaseViewModelActivity.kt │ │ ├── data │ │ │ └── DialogBean.kt │ │ ├── dialog │ │ │ └── ShowUIDialog.kt │ │ ├── ex │ │ │ ├── ExceptionEX.kt │ │ │ ├── Flow.kt │ │ │ └── Throwable.kt │ │ └── utils │ │ │ └── NetWorkHelp.kt │ │ ├── data_source │ │ ├── kapt │ │ │ └── KaptInterface.kt │ │ ├── repository │ │ │ └── RepositoryPoxy.kt │ │ └── tata.kt │ │ └── ui │ │ ├── activity │ │ └── MainActivity.kt │ │ └── viewmodel │ │ └── MainViewModel.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ └── ic_loading.webp │ ├── drawable │ ├── ic_launcher_background.xml │ └── progressbar_shape.xml │ ├── layout │ ├── activity_main.xml │ └── layout_loading.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 │ ├── values-night │ └── themes.xml │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── app_wx4 ├── .gitignore ├── build.gradle ├── libs │ ├── annotation_compiler.jar │ └── annotations.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── wx │ │ └── architecture │ │ ├── MyApp.kt │ │ ├── code │ │ ├── app │ │ │ └── AppGlobals.kt │ │ ├── base │ │ │ ├── BaseFragment.kt │ │ │ ├── BaseRepositoryProxy.kt │ │ │ ├── BaseViewModel.kt │ │ │ └── BaseViewModelActivity.kt │ │ ├── data │ │ │ └── DialogBean.kt │ │ ├── dialog │ │ │ └── ShowUIDialog.kt │ │ ├── ex │ │ │ ├── ExceptionEX.kt │ │ │ ├── Flow.kt │ │ │ └── Throwable.kt │ │ └── utils │ │ │ └── NetWorkHelp.kt │ │ ├── data_source │ │ ├── repository │ │ │ └── RepositoryPoxy.kt │ │ └── tata.kt │ │ └── ui │ │ ├── activity │ │ └── MainActivity.kt │ │ └── viewmodel │ │ └── MainViewModel.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ └── ic_loading.webp │ ├── drawable │ ├── ic_launcher_background.xml │ └── progressbar_shape.xml │ ├── layout │ ├── activity_main.xml │ └── layout_loading.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 │ ├── values-night │ └── themes.xml │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── app_wx_switch_net ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── wx │ │ └── architecture │ │ ├── MyApp.kt │ │ ├── code │ │ ├── app │ │ │ └── AppGlobals.kt │ │ ├── base │ │ │ ├── BaseFragment.kt │ │ │ ├── BaseViewModel.kt │ │ │ └── BaseViewModelActivity.kt │ │ ├── data │ │ │ └── DialogBean.kt │ │ ├── dialog │ │ │ └── ShowUIDialog.kt │ │ ├── ex │ │ │ ├── ExceptionEX.kt │ │ │ ├── Flow.kt │ │ │ └── Throwable.kt │ │ └── utils │ │ │ ├── BuildParamUtils.kt │ │ │ ├── NetWorkHelp.kt │ │ │ └── RequestBodyCreate.kt │ │ ├── data_source │ │ ├── data │ │ │ ├── CommonResult.kt │ │ │ ├── HomeData.kt │ │ │ ├── HomeItemBean.kt │ │ │ └── WanAndroidHome.kt │ │ ├── dl_hilt │ │ │ ├── AbstractHttp.kt │ │ │ └── annotation │ │ │ │ ├── BindHttpUrlConnection.kt │ │ │ │ └── BindOkhttp.kt │ │ ├── net │ │ │ ├── HttpUrlConnectionImpl.kt │ │ │ ├── INetApi.kt │ │ │ ├── OkhttpImpl.kt │ │ │ └── http │ │ │ │ ├── HttpURLConnectionUtils.kt │ │ │ │ └── HttpUrlConnectionRequest.kt │ │ ├── repository │ │ │ └── NetRepository.kt │ │ └── tata.kt │ │ └── ui │ │ ├── activity │ │ └── MainActivity.kt │ │ └── viewmodel │ │ └── MainViewModel.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ └── ic_loading.webp │ ├── drawable │ ├── ic_launcher_background.xml │ └── progressbar_shape.xml │ ├── layout │ ├── activity_main.xml │ └── layout_loading.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 │ ├── values-night │ └── themes.xml │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | 17 | # Project exclude paths 18 | /NetworkApiData/build/ -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 11 | 12 | 14 | 15 | 17 | 18 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 26 | 27 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /NetworkApiData/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'kotlin' 4 | } 5 | 6 | java { 7 | sourceCompatibility = JavaVersion.VERSION_1_8 8 | targetCompatibility = JavaVersion.VERSION_1_8 9 | } 10 | 11 | 12 | dependencies { 13 | 14 | api fileTree(dir: 'libs', include: ['*.jar']) 15 | 16 | implementation "org.jetbrains.kotlin:kotlin-stdlib:1.7.0" 17 | 18 | //网络层 retrofit okhttp 相关 start 19 | api 'com.squareup.retrofit2:retrofit:2.9.0' 20 | api 'com.squareup.retrofit2:retrofit:2.9.0' 21 | api 'com.squareup.retrofit2:converter-scalars:2.9.0' 22 | api 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' 23 | api 'com.squareup.okhttp3:logging-interceptor:4.0.0' 24 | api 'com.squareup.retrofit2:converter-gson:2.9.0' 25 | api 'com.squareup.retrofit2:converter-scalars:2.1.0' 26 | //网络层 retrofit okhttp 相关 end 27 | 28 | // api project(path: ':annotations') 29 | } -------------------------------------------------------------------------------- /NetworkApiData/libs/annotations.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/NetworkApiData/libs/annotations.jar -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/data/BaiDuImageResponse.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.data 2 | 3 | import java.util.ArrayList 4 | 5 | class BaiDuImageResponse() { 6 | var gsm:String?=null 7 | var data: ArrayList?=null 8 | } -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/data/BaiduDataBean.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.data 2 | 3 | data class BaiduDataBean(var adType: Int, var thumbURL: String, var middleURL: String) -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/data/BaseResponse.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.data 2 | 3 | //data class BaseResponse(val code :Int,var errorMsg:String,var t:T) { 4 | data class BaseResponse(var gsm: String, var data: T) -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/data/wanandroid/CommonResult.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.data.wanandroid 2 | 3 | open class CommonResult { 4 | var data: T? = null 5 | var errorCode: Int? = 0 6 | var errorMsg: String? = null 7 | } -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/data/wanandroid/home/HomeData.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.data.wanandroid.home 2 | 3 | import com.wx.test.api.data.wanandroid.CommonResult 4 | 5 | class HomeData : CommonResult() { 6 | } 7 | -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/data/wanandroid/home/HomeItemBean.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.data.wanandroid.home 2 | 3 | data class HomeItemBean( 4 | val author:String, 5 | val chapterName:String, 6 | val link:String, 7 | val title:String 8 | ) 9 | -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/data/wanandroid/home/WanAndroidHome.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.data.wanandroid.home 2 | 3 | data class WanAndroidHome( 4 | val datas: MutableList, 5 | val curPage: Int, 6 | val size: Int, 7 | val total: Int 8 | ) -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/retrofit/HeaderInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.retrofit 2 | 3 | import okhttp3.Interceptor 4 | import okhttp3.Request 5 | import okhttp3.Response 6 | import java.io.IOException 7 | 8 | class HeaderInterceptor : Interceptor { 9 | 10 | @Throws(IOException::class) 11 | override fun intercept(chain: Interceptor.Chain): Response { 12 | val request: Request = chain.request() 13 | val authorised = request 14 | .newBuilder() 15 | .addHeader("Connection", "keep-alive") // 16 | .addHeader("Accept-Language", "zh-CN,zh;q=0.9") // 17 | .addHeader( 18 | "Authorization", 19 | "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjaGFudElkIjo1OTIsInVzZXJfbmFtZSI6IjE4OTgyOTkwNzAyIiwib3BlbmlkIjpudWxsLCJzY29wZSI6WyJhbGwiXSwiaWQiOjY5MSwiY2xpZW50X3NvdXJjZSI6bnVsbCwiZXhwIjoxNzI2MjIzNzYyLCJhdXRob3JpdGllcyI6WyJyYmFjXzEzX-aXoOS6uuWUruWNluWVhuWutiJdLCJqdGkiOiJmYmVhMGRlZi01MjNmLTRkYTctYjY3Yy1lMjljZjJkYmU1YzUiLCJjbGllbnRfaWQiOiJjdXN0b21lci1hcHAiLCJyZWFsbmFtZSI6bnVsbH0.f4QtuwWdj096Dzp2o4aVyEnDof3-7gR7NX-LX-j8KbBmXwdYtKG32AvRKxY5t5ubwhTqe0IHkobZZqTcub4bnd8DdmSUJa0Q8UQP1EgMWuUubSuojHifOctNzZFlc74v28NUbzlhslmQNzHL5f7zxjP7zVdMfKvGD9eSjeHlG8w" 20 | ) // 21 | .addHeader("Accept", "application/json, text/javascript, */*") // 22 | // .addHeader("Referer", " https://wwz.lanzouj.com/ihT5x20ulecf") //https 23 | // .addHeader("Upgrade-insecure-Requests", "1") // 24 | // .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36") // 25 | // if (request.header("User-Agent") == null) { 26 | authorised.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36") // 27 | // } 28 | return chain.proceed(authorised.build()) 29 | // return chain.proceed(authorised.build()) 30 | } 31 | } -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/retrofit/RequestBodyCreate.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.retrofit 2 | 3 | import okhttp3.MediaType.Companion.toMediaTypeOrNull 4 | import okhttp3.RequestBody 5 | 6 | object RequestBodyCreate { 7 | 8 | fun toBody(body: String) = RequestBody.create("application/json; charset=utf-8".toMediaTypeOrNull(), body) 9 | } -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/retrofit/RequestBodyWrapper.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.retrofit 2 | 3 | import okhttp3.MediaType 4 | import okhttp3.MediaType.Companion.toMediaTypeOrNull 5 | import okhttp3.RequestBody 6 | import okio.BufferedSink 7 | 8 | class RequestBodyWrapper constructor(val postBody: String) : RequestBody() { 9 | 10 | override fun contentType(): MediaType? { 11 | return "application/json; charset=utf-8".toMediaTypeOrNull() 12 | } 13 | 14 | override fun writeTo(sink: BufferedSink) { 15 | sink.write(postBody.toByteArray(), 0, postBody.toByteArray().size) 16 | } 17 | } -------------------------------------------------------------------------------- /NetworkApiData/src/main/java/com/wx/test/api/retrofit/RetrofitUtils.kt: -------------------------------------------------------------------------------- 1 | package com.wx.test.api.retrofit 2 | 3 | import okhttp3.OkHttpClient 4 | import okhttp3.logging.HttpLoggingInterceptor 5 | import retrofit2.Retrofit 6 | import retrofit2.converter.gson.GsonConverterFactory 7 | import retrofit2.converter.scalars.ScalarsConverterFactory 8 | import java.util.concurrent.TimeUnit 9 | 10 | class RetrofitUtils private constructor() { 11 | val baseUrl = "https://www.wanandroid.com/" 12 | 13 | companion object { 14 | val instance by lazy { RetrofitUtils() } 15 | } 16 | 17 | private inline val retrofit: Retrofit 18 | get() { 19 | val logging = HttpLoggingInterceptor() 20 | val timeout = 30000L 21 | val okHttpClient = OkHttpClient.Builder() 22 | .addInterceptor(HeaderInterceptor()) 23 | .addInterceptor(logging) 24 | // .addInterceptor(RetrofitClient.BaseUrlInterceptor()) 25 | .callTimeout(timeout, TimeUnit.MILLISECONDS) 26 | //设置连接超时 27 | .connectTimeout(timeout, TimeUnit.MILLISECONDS) 28 | //设置从主机读信息超时 29 | .readTimeout(timeout, TimeUnit.MILLISECONDS) 30 | //设置写信息超时 31 | .writeTimeout(timeout, TimeUnit.MILLISECONDS) 32 | .retryOnConnectionFailure(true)//设置出现错误进行重新连接。 33 | .build(); 34 | return Retrofit.Builder() 35 | .client(okHttpClient) 36 | .addConverterFactory(ScalarsConverterFactory.create()) 37 | .addConverterFactory(GsonConverterFactory.create()) 38 | .baseUrl(baseUrl) 39 | .build() 40 | } 41 | 42 | fun create(service: Class?): T { 43 | if (service == null) { 44 | throw RuntimeException("Api service is null!") 45 | } 46 | return retrofit.create(service)!! 47 | } 48 | } -------------------------------------------------------------------------------- /annotation_compiler/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /annotation_compiler/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'java-library' 4 | id 'kotlin' 5 | id 'kotlin-kapt' 6 | } 7 | 8 | 9 | dependencies { 10 | implementation fileTree(dir: 'libs', include: ['*.jar']) 11 | implementation "org.jetbrains.kotlin:kotlin-stdlib:1.7.0" 12 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2' 13 | // annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4' java 用法 14 | // implementation 'com.google.auto.service:auto-service:1.0-rc4' java 用法 15 | 16 | implementation "com.google.auto.service:auto-service:1.0-rc4" // kotlin 用法 17 | kapt "com.google.auto.service:auto-service:1.0" // kotlin 用法 18 | implementation "com.squareup:kotlinpoet:1.8.0" 19 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 20 | 21 | // implementation project(path: ':annotations') 22 | implementation project(path: ':NetworkApiData') 23 | } 24 | java { 25 | sourceCompatibility = JavaVersion.VERSION_1_8 26 | targetCompatibility = JavaVersion.VERSION_1_8 27 | } -------------------------------------------------------------------------------- /annotation_compiler/libs/javax.inject-1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/annotation_compiler/libs/javax.inject-1.jar -------------------------------------------------------------------------------- /app_wx1/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app_wx1/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | } 5 | 6 | android { 7 | compileSdk 32 8 | 9 | defaultConfig { 10 | applicationId "com.wx.wxnetarchitecture" 11 | minSdk 21 12 | targetSdk 32 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | // testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | kotlinOptions { 30 | jvmTarget = '1.8' 31 | } 32 | } 33 | 34 | dependencies { 35 | 36 | implementation 'androidx.core:core-ktx:1.7.0' 37 | implementation 'androidx.appcompat:appcompat:1.3.0' 38 | implementation 'com.google.android.material:material:1.4.0' 39 | 40 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 41 | implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' 42 | implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' 43 | implementation 'com.squareup.okhttp3:okhttp:4.9.3' 44 | implementation 'com.squareup.okio:okio:2.10.0' 45 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0' 46 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 47 | 48 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' 49 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' 50 | implementation 'androidx.activity:activity-ktx:1.3.0-rc01' 51 | implementation 'androidx.fragment:fragment-ktx:1.4.0-alpha04' 52 | 53 | implementation project(path: ':NetworkApiData') 54 | 55 | // testImplementation 'junit:junit:4.13.2' 56 | // androidTestImplementation 'androidx.test.ext:junit:1.1.3' 57 | // androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 58 | } -------------------------------------------------------------------------------- /app_wx1/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app_wx1/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/MyApp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture 2 | 3 | import android.app.Application 4 | import com.wx.architecture.code.app.AppGlobals 5 | 6 | class MyApp : Application() { 7 | 8 | override fun onCreate() { 9 | super.onCreate() 10 | AppGlobals.sApplication = this 11 | } 12 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/app/AppGlobals.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.app 2 | 3 | import android.app.Application 4 | 5 | object AppGlobals { 6 | lateinit var sApplication: Application 7 | 8 | fun getApplication(): Application { 9 | if (!this::sApplication.isInitialized) { 10 | //去反射得到 11 | try { 12 | val aClass = Class.forName("android.app.ActivityThread") 13 | //获取里面的currentApplication 14 | val currentApplication = aClass.getDeclaredMethod("currentApplication") 15 | sApplication = currentApplication.invoke(null, *emptyArray()) as Application 16 | } catch (e: Exception) { 17 | e.printStackTrace() 18 | } 19 | } 20 | return sApplication 21 | } 22 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | class BaseFragment : Fragment() { 6 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/base/BaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.viewModelScope 6 | import com.wx.architecture.code.data.DialogBean 7 | import com.wx.architecture.code.ex.flowOnIOAndCatch 8 | import com.wx.test.api.data.wanandroid.CommonResult 9 | import kotlinx.coroutines.CoroutineScope 10 | import kotlinx.coroutines.NonCancellable.start 11 | import kotlinx.coroutines.cancel 12 | import kotlinx.coroutines.flow.Flow 13 | import kotlinx.coroutines.flow.collect 14 | import kotlinx.coroutines.flow.onCompletion 15 | import kotlinx.coroutines.flow.onStart 16 | import kotlinx.coroutines.launch 17 | 18 | open class BaseViewModel : ViewModel() { 19 | val errorMsgLiveData by lazy { MutableLiveData() } 20 | val showUIDialog by lazy { MutableLiveData() } 21 | 22 | fun show(strMessage: String = "正在请求数据") { 23 | val showBean = showUIDialog.value ?: DialogBean(strMessage, true) 24 | showBean.isShow = true 25 | showBean.msg = strMessage 26 | showUIDialog.postValue(showBean) 27 | } 28 | 29 | fun hide() { 30 | val showBean = showUIDialog.value ?: DialogBean("", true) 31 | showBean.isShow = false 32 | showUIDialog.postValue(showBean) 33 | } 34 | 35 | override fun onCleared() { 36 | viewModelScope.cancel() 37 | } 38 | 39 | protected fun Flow.flowOnIOAndCatch(): Flow = flowOnIOAndCatch(errorMsgLiveData) 40 | 41 | protected fun Flow.onStartAndShow(strMessage: String = "正在请求数据"): Flow = onStart { 42 | show() 43 | } 44 | 45 | protected fun Flow.onCompletionAndHide(): Flow = onCompletion { 46 | hide() 47 | } 48 | 49 | protected suspend fun Flow.onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() { 50 | onStartAndShow().onCompletionAndHide().flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 51 | } 52 | 53 | fun flowAsyncWorkOnViewModelScopeLaunch(flowAsyncWork: suspend () -> Flow) { 54 | viewModelScope.launch { 55 | flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 56 | } 57 | } 58 | 59 | fun flowAsyncWorkOnViewModelScopeLaunch2(block: suspend CoroutineScope.() -> Unit) { 60 | viewModelScope.launch { 61 | block.invoke(this) 62 | // flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 63 | } 64 | } 65 | 66 | // block: suspend CoroutineScope.() -> Unit 67 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/base/BaseViewModelActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import androidx.annotation.LayoutRes 6 | import androidx.annotation.MainThread 7 | import androidx.appcompat.app.AppCompatActivity 8 | import androidx.lifecycle.ViewModelLazy 9 | import com.wx.architecture.code.dialog.ShowUIDialog 10 | import java.lang.reflect.ParameterizedType 11 | 12 | 13 | open class BaseViewModelActivity(@LayoutRes val layResID: Int) : AppCompatActivity() { 14 | private var loading: ShowUIDialog? = null 15 | 16 | protected val viewModel by lazyViewModels() 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(layResID) 21 | initX() 22 | } 23 | 24 | protected fun initX() { 25 | bindObserve() 26 | } 27 | 28 | //是否loading 29 | open fun isShowloading(): Boolean? { 30 | return loading?.isShowing() 31 | } 32 | 33 | open fun showloading(showText: String?) { 34 | if (null == loading) loading = ShowUIDialog(this) 35 | if (isShowloading() == true) return 36 | if (showText != null) loading?.show(showText) 37 | } 38 | 39 | open fun hideLoading() { 40 | loading?.dismiss() 41 | loading = null 42 | } 43 | 44 | override fun onDestroy() { 45 | hideLoading() 46 | super.onDestroy() 47 | } 48 | 49 | protected fun bindObserve() { 50 | viewModel?.run { 51 | showUIDialog.observe(this@BaseViewModelActivity) { it -> 52 | if (it.isShow) showloading(it.msg) else hideLoading() 53 | } 54 | errorMsgLiveData.observe(this@BaseViewModelActivity) { 55 | //公共toast 提示样式可以自行封装 56 | Toast.makeText(this@BaseViewModelActivity, it, Toast.LENGTH_SHORT).show() 57 | } 58 | } 59 | } 60 | 61 | @MainThread 62 | inline fun lazyViewModels(): Lazy { 63 | val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class 64 | return ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) 65 | } 66 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/data/DialogBean.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.data 2 | 3 | data class DialogBean(var msg:String, var isShow:Boolean){ 4 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/dialog/ShowUIDialog.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.dialog 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.view.Gravity 6 | import android.view.View 7 | import android.widget.TextView 8 | import androidx.appcompat.app.AppCompatDialog 9 | import com.wx.architecture.R 10 | 11 | class ShowUIDialog : AppCompatDialog { 12 | 13 | lateinit var txt_loading_text: TextView 14 | 15 | constructor (context: Context) : super(context, R.style.Loading) { 16 | setContentView(R.layout.layout_loading) 17 | window?.run { 18 | txt_loading_text = findViewById(R.id.txt_loading_text) 19 | attributes.gravity = Gravity.CENTER 20 | } 21 | } 22 | 23 | fun show(showText: String) { 24 | txt_loading_text?.apply { 25 | if (showText.isNotEmpty()) { 26 | text = showText 27 | visibility = View.VISIBLE 28 | } else { 29 | visibility = View.GONE 30 | } 31 | } 32 | if (!isShowing()) { 33 | show() 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/ex/ExceptionEX.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | class ExceptionEX(val errorCode: Int, val errorMessage: String) : Exception(errorMessage) { 4 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/ex/Flow.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.wx.test.api.data.wanandroid.CommonResult 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.flow.* 7 | import java.lang.Exception 8 | 9 | 10 | fun Flow.flowOnIOAndCatch(errorMsgLiveData: MutableLiveData? = null): Flow = 11 | flowOn(Dispatchers.IO) 12 | .catch { 13 | it.printStackTrace() 14 | errorMsgLiveData?.value = it.parseErrorString(); 15 | } 16 | 17 | suspend fun Flow.flowOnIOAndCatchAAndCollect() { 18 | flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 19 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/ex/Throwable.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import com.google.gson.JsonSyntaxException 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.app.AppGlobals 6 | import com.wx.architecture.code.utils.isNetWorkActive 7 | import retrofit2.HttpException 8 | import java.io.InterruptedIOException 9 | import java.net.ConnectException 10 | import java.net.SocketException 11 | import java.net.SocketTimeoutException 12 | import java.net.UnknownHostException 13 | import java.util.concurrent.TimeoutException 14 | 15 | fun Throwable?.parseErrorString(): String = when (this) { 16 | is ConnectException, is SocketException -> { 17 | if (message?.contains("Network is unreachable") == true) 18 | getString(R.string.Mobilenetuseless_msg) 19 | if (message?.contains("Failed to connect to") == true) 20 | getString(R.string.failed_to_connect_to) 21 | else 22 | getString(R.string.ConnectException) 23 | } 24 | is HttpException -> { 25 | if (message?.contains("HTTP 50") == true) { 26 | message!!.substring(0, 8) 27 | } else { 28 | getString(R.string.HttpException) 29 | } 30 | } 31 | is InterruptedIOException -> { 32 | if (message?.contains("timeout") == true) 33 | getString(R.string.SocketTimeoutException) 34 | else 35 | getString(R.string.ConnectException) 36 | } 37 | is UnknownHostException -> getString(R.string.UnknownHostException) 38 | is JsonSyntaxException -> getString(R.string.JsonSyntaxException) 39 | is SocketTimeoutException, is TimeoutException -> getString(R.string.SocketTimeoutException) 40 | is IllegalArgumentException -> { 41 | if (message?.contains("baseUrl must end in ") == true) 42 | if (AppGlobals.getApplication().isNetWorkActive()) getString(R.string.HostBaseUrlError) 43 | else getString(R.string.Mobilenetuseless_msg) 44 | else message ?: getString(R.string.ElseNetException) 45 | } 46 | else -> getString(R.string.ElseNetException) 47 | } 48 | 49 | fun getString(resID: Int) = AppGlobals.getApplication().getString(resID) -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/code/utils/NetWorkHelp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.utils 2 | import android.app.Application 3 | import android.content.Context 4 | import android.net.ConnectivityManager 5 | import android.net.NetworkCapabilities 6 | import android.os.Build 7 | 8 | fun Application.isNetWorkActive(): Boolean { 9 | val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 10 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 11 | val network = connectivityManager.activeNetwork ?: return false 12 | val activeNetwork = 13 | connectivityManager.getNetworkCapabilities(network) ?: return false 14 | return when { 15 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true 16 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true 17 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true 18 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true 19 | else -> false 20 | } 21 | } else { 22 | @Suppress("DEPRECATION") val networkInfo = 23 | connectivityManager.activeNetworkInfo ?: return false 24 | @Suppress("DEPRECATION") 25 | return networkInfo.isConnected 26 | } 27 | return true 28 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/data_source/tata.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source 2 | 3 | class tata { 4 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/ui/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.activity 2 | 3 | import android.view.View 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.base.BaseViewModelActivity 6 | import com.wx.architecture.ui.viewmodel.MainViewModel 7 | 8 | class MainActivity : BaseViewModelActivity(R.layout.activity_main), View.OnClickListener { 9 | 10 | override fun onClick(v: View?) { 11 | when (v?.id) { 12 | R.id.btn1 -> { 13 | viewModel.getHomeList(1) 14 | } 15 | else -> {} 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app_wx1/src/main/java/com/wx/architecture/ui/viewmodel/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.viewmodel 2 | 3 | import com.wx.architecture.code.base.BaseViewModel 4 | import com.wx.architecture.data_source.repository.NetRepository 5 | import kotlinx.coroutines.flow.onEach 6 | 7 | class MainViewModel : BaseViewModel() { 8 | 9 | private val repository by lazy { NetRepository.instance } 10 | 11 | fun getHomeList(page: Int) { 12 | flowAsyncWorkOnViewModelScopeLaunch { 13 | repository.getHomeList(page).onEach { 14 | errorMsgLiveData.postValue(it.data?.datas!![0].title) 15 | android.util.Log.e("MainViewModel", "one 111 ${it.data?.datas!![0].title}") 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /app_wx1/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/drawable-xhdpi/ic_loading.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/drawable-xhdpi/ic_loading.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/drawable/progressbar_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/layout/layout_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx1/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx1/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WXNetArchitecture 3 | 4 | 5 | 未知错误异常 6 | 网络超时 7 | 网络超时 8 | 网络错误 9 | 网络错误 10 | 服务器异常 11 | 无网络连接 12 | 请求地址错误 13 | 当前网络不可用 14 | 无法连接到服务器 15 | 数据错误,json解析错误 16 | 17 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 32 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app_wx1/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app_wx2/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app_wx2/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | id 'kotlin-kapt' 5 | } 6 | 7 | android { 8 | compileSdk 32 9 | 10 | defaultConfig { 11 | applicationId "com.wx.wxnetarchitecture" 12 | minSdk 21 13 | targetSdk 32 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | // testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_8 28 | targetCompatibility JavaVersion.VERSION_1_8 29 | } 30 | kotlinOptions { 31 | jvmTarget = '1.8' 32 | } 33 | kapt { 34 | generateStubs = true 35 | } 36 | } 37 | 38 | dependencies { 39 | // implementation fileTree(dir: 'libs', include: ['*.jar']) 40 | 41 | implementation 'androidx.core:core-ktx:1.7.0' 42 | implementation 'androidx.appcompat:appcompat:1.3.0' 43 | implementation 'com.google.android.material:material:1.4.0' 44 | 45 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 46 | implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' 47 | implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' 48 | implementation 'com.squareup.okhttp3:okhttp:4.9.3' 49 | implementation 'com.squareup.okio:okio:2.10.0' 50 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0' 51 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 52 | 53 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' 54 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' 55 | implementation 'androidx.activity:activity-ktx:1.3.0-rc01' 56 | implementation 'androidx.fragment:fragment-ktx:1.4.0-alpha04' 57 | 58 | implementation project(path: ':NetworkApiData') 59 | kapt project(path: ':annotation_compiler') 60 | 61 | // testImplementation 'junit:junit:4.13.2' 62 | // androidTestImplementation 'androidx.test.ext:junit:1.1.3' 63 | // androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 64 | } -------------------------------------------------------------------------------- /app_wx2/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app_wx2/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/MyApp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture 2 | 3 | import android.app.Application 4 | import com.wx.architecture.code.app.AppGlobals 5 | 6 | class MyApp : Application() { 7 | 8 | override fun onCreate() { 9 | super.onCreate() 10 | AppGlobals.sApplication = this 11 | } 12 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/app/AppGlobals.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.app 2 | 3 | import android.app.Application 4 | 5 | object AppGlobals { 6 | lateinit var sApplication: Application 7 | 8 | fun getApplication(): Application { 9 | if (!this::sApplication.isInitialized) { 10 | //去反射得到 11 | try { 12 | val aClass = Class.forName("android.app.ActivityThread") 13 | //获取里面的currentApplication 14 | val currentApplication = aClass.getDeclaredMethod("currentApplication") 15 | sApplication = currentApplication.invoke(null, *emptyArray()) as Application 16 | } catch (e: Exception) { 17 | e.printStackTrace() 18 | } 19 | } 20 | return sApplication 21 | } 22 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | class BaseFragment : Fragment() { 6 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/base/BaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.viewModelScope 6 | import com.wx.architecture.code.data.DialogBean 7 | import com.wx.architecture.code.ex.flowOnIOAndCatch 8 | import com.wx.test.api.data.wanandroid.CommonResult 9 | import kotlinx.coroutines.CoroutineScope 10 | import kotlinx.coroutines.NonCancellable.start 11 | import kotlinx.coroutines.cancel 12 | import kotlinx.coroutines.flow.Flow 13 | import kotlinx.coroutines.flow.collect 14 | import kotlinx.coroutines.flow.onCompletion 15 | import kotlinx.coroutines.flow.onStart 16 | import kotlinx.coroutines.launch 17 | 18 | open class BaseViewModel : ViewModel() { 19 | val errorMsgLiveData by lazy { MutableLiveData() } 20 | val showUIDialog by lazy { MutableLiveData() } 21 | 22 | fun show(strMessage: String = "正在请求数据") { 23 | val showBean = showUIDialog.value ?: DialogBean(strMessage, true) 24 | showBean.isShow = true 25 | showBean.msg = strMessage 26 | showUIDialog.postValue(showBean) 27 | } 28 | 29 | fun hide() { 30 | val showBean = showUIDialog.value ?: DialogBean("", true) 31 | showBean.isShow = false 32 | showUIDialog.postValue(showBean) 33 | } 34 | 35 | override fun onCleared() { 36 | viewModelScope.cancel() 37 | } 38 | 39 | protected fun Flow.flowOnIOAndCatch(): Flow = flowOnIOAndCatch(errorMsgLiveData) 40 | 41 | protected fun Flow.onStartAndShow(strMessage: String = "正在请求数据"): Flow = onStart { 42 | show() 43 | } 44 | 45 | protected fun Flow.onCompletionAndHide(): Flow = onCompletion { 46 | hide() 47 | } 48 | 49 | protected suspend fun Flow.onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() { 50 | onStartAndShow().onCompletionAndHide().flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 51 | } 52 | 53 | fun flowAsyncWorkOnViewModelScopeLaunch(flowAsyncWork: suspend () -> Flow) { 54 | viewModelScope.launch { 55 | flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 56 | } 57 | } 58 | 59 | fun flowAsyncWorkOnViewModelScopeLaunch2(block: suspend CoroutineScope.() -> Unit) { 60 | viewModelScope.launch { 61 | block.invoke(this) 62 | // flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 63 | } 64 | } 65 | 66 | // block: suspend CoroutineScope.() -> Unit 67 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/base/BaseViewModelActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import androidx.annotation.LayoutRes 6 | import androidx.annotation.MainThread 7 | import androidx.appcompat.app.AppCompatActivity 8 | import androidx.lifecycle.ViewModelLazy 9 | import com.wx.architecture.code.dialog.ShowUIDialog 10 | import java.lang.reflect.ParameterizedType 11 | 12 | 13 | open class BaseViewModelActivity(@LayoutRes val layResID: Int) : AppCompatActivity() { 14 | private var loading: ShowUIDialog? = null 15 | 16 | protected val viewModel by lazyViewModels() 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(layResID) 21 | initX() 22 | } 23 | 24 | protected fun initX() { 25 | bindObserve() 26 | } 27 | 28 | //是否loading 29 | open fun isShowloading(): Boolean? { 30 | return loading?.isShowing() 31 | } 32 | 33 | open fun showloading(showText: String?) { 34 | if (null == loading) loading = ShowUIDialog(this) 35 | if (isShowloading() == true) return 36 | if (showText != null) loading?.show(showText) 37 | } 38 | 39 | open fun hideLoading() { 40 | loading?.dismiss() 41 | loading = null 42 | } 43 | 44 | override fun onDestroy() { 45 | hideLoading() 46 | super.onDestroy() 47 | } 48 | 49 | protected fun bindObserve() { 50 | viewModel?.run { 51 | showUIDialog.observe(this@BaseViewModelActivity) { it -> 52 | if (it.isShow) showloading(it.msg) else hideLoading() 53 | } 54 | errorMsgLiveData.observe(this@BaseViewModelActivity) { 55 | //公共toast 提示样式可以自行封装 56 | Toast.makeText(this@BaseViewModelActivity, it, Toast.LENGTH_SHORT).show() 57 | } 58 | } 59 | } 60 | 61 | @MainThread 62 | inline fun lazyViewModels(): Lazy { 63 | val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class 64 | return ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) 65 | } 66 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/data/DialogBean.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.data 2 | 3 | data class DialogBean(var msg:String, var isShow:Boolean){ 4 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/dialog/ShowUIDialog.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.dialog 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.view.Gravity 6 | import android.view.View 7 | import android.widget.TextView 8 | import androidx.appcompat.app.AppCompatDialog 9 | import com.wx.architecture.R 10 | 11 | class ShowUIDialog : AppCompatDialog { 12 | 13 | lateinit var txt_loading_text: TextView 14 | 15 | constructor (context: Context) : super(context, R.style.Loading) { 16 | setContentView(R.layout.layout_loading) 17 | window?.run { 18 | txt_loading_text = findViewById(R.id.txt_loading_text) 19 | attributes.gravity = Gravity.CENTER 20 | } 21 | } 22 | 23 | fun show(showText: String) { 24 | txt_loading_text?.apply { 25 | if (showText.isNotEmpty()) { 26 | text = showText 27 | visibility = View.VISIBLE 28 | } else { 29 | visibility = View.GONE 30 | } 31 | } 32 | if (!isShowing()) { 33 | show() 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/ex/ExceptionEX.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | class ExceptionEX(val errorCode: Int, val errorMessage: String) : Exception(errorMessage) { 4 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/ex/Flow.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.wx.test.api.data.wanandroid.CommonResult 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.flow.* 7 | import java.lang.Exception 8 | 9 | 10 | fun Flow.flowOnIOAndCatch(errorMsgLiveData: MutableLiveData? = null): Flow = 11 | flowOn(Dispatchers.IO) 12 | .catch { 13 | it.printStackTrace() 14 | errorMsgLiveData?.value = it.parseErrorString(); 15 | } 16 | 17 | suspend fun Flow.flowOnIOAndCatchAAndCollect() { 18 | flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 19 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/ex/Throwable.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import com.google.gson.JsonSyntaxException 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.app.AppGlobals 6 | import com.wx.architecture.code.utils.isNetWorkActive 7 | import retrofit2.HttpException 8 | import java.io.InterruptedIOException 9 | import java.net.ConnectException 10 | import java.net.SocketException 11 | import java.net.SocketTimeoutException 12 | import java.net.UnknownHostException 13 | import java.util.concurrent.TimeoutException 14 | 15 | fun Throwable?.parseErrorString(): String = when (this) { 16 | is ConnectException, is SocketException -> { 17 | if (message?.contains("Network is unreachable") == true) 18 | getString(R.string.Mobilenetuseless_msg) 19 | if (message?.contains("Failed to connect to") == true) 20 | getString(R.string.failed_to_connect_to) 21 | else 22 | getString(R.string.ConnectException) 23 | } 24 | is HttpException -> { 25 | if (message?.contains("HTTP 50") == true) { 26 | message!!.substring(0, 8) 27 | } else { 28 | getString(R.string.HttpException) 29 | } 30 | } 31 | is InterruptedIOException -> { 32 | if (message?.contains("timeout") == true) 33 | getString(R.string.SocketTimeoutException) 34 | else 35 | getString(R.string.ConnectException) 36 | } 37 | is UnknownHostException -> getString(R.string.UnknownHostException) 38 | is JsonSyntaxException -> getString(R.string.JsonSyntaxException) 39 | is SocketTimeoutException, is TimeoutException -> getString(R.string.SocketTimeoutException) 40 | is IllegalArgumentException -> { 41 | if (message?.contains("baseUrl must end in ") == true) 42 | if (AppGlobals.sApplication.isNetWorkActive()) getString(R.string.HostBaseUrlError) 43 | else getString(R.string.Mobilenetuseless_msg) 44 | else message ?: getString(R.string.ElseNetException) 45 | } 46 | else -> getString(R.string.ElseNetException) 47 | } 48 | 49 | fun getString(resID: Int) = AppGlobals.sApplication.getString(resID) -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/code/utils/NetWorkHelp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.utils 2 | import android.app.Application 3 | import android.content.Context 4 | import android.net.ConnectivityManager 5 | import android.net.NetworkCapabilities 6 | import android.os.Build 7 | 8 | fun Application.isNetWorkActive(): Boolean { 9 | val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 10 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 11 | val network = connectivityManager.activeNetwork ?: return false 12 | val activeNetwork = 13 | connectivityManager.getNetworkCapabilities(network) ?: return false 14 | return when { 15 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true 16 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true 17 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true 18 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true 19 | else -> false 20 | } 21 | } else { 22 | @Suppress("DEPRECATION") val networkInfo = 23 | connectivityManager.activeNetworkInfo ?: return false 24 | @Suppress("DEPRECATION") 25 | return networkInfo.isConnected 26 | } 27 | return true 28 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/data_source/kapt/KaptComponet.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.kapt 2 | 3 | import com.wx.annotations.AutoCreateRepository 4 | 5 | /** 6 | * interfaceApi: 接口类名字, 7 | * superClass : 自动生成的类的继承的父类 8 | **/ 9 | @AutoCreateRepository(interfaceApi = "com.wx.test.api.net.NetApi", superClass = "com.wx.architecture.data_source.repository.BaseRepository") 10 | class KaptComponet { 11 | } 12 | -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/data_source/repository/BaseRepository.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.repository 2 | 3 | import com.wx.test.api.retrofit.RetrofitUtils 4 | import com.wx.test.api.data.BaseResponse 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.withContext 7 | import java.lang.reflect.ParameterizedType 8 | 9 | open class BaseRepository() { 10 | val service by lazy { createService() } 11 | 12 | private fun createService(): T { 13 | val clazz = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class 14 | return RetrofitUtils.instance.create(clazz) 15 | } 16 | 17 | // 18 | suspend fun apiCall(api: suspend () -> BaseResponse): BaseResponse = withContext(Dispatchers.IO) { api.invoke() } 19 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/data_source/tata.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source 2 | 3 | class tata { 4 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/ui/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.activity 2 | 3 | import android.view.View 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.base.BaseViewModelActivity 6 | import com.wx.architecture.ui.viewmodel.MainViewModel 7 | 8 | class MainActivity : BaseViewModelActivity(R.layout.activity_main), View.OnClickListener { 9 | 10 | override fun onClick(v: View?) { 11 | when (v?.id) { 12 | R.id.btn1 -> { 13 | viewModel.getHomeList(1) 14 | } 15 | else -> {} 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app_wx2/src/main/java/com/wx/architecture/ui/viewmodel/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.viewmodel 2 | 3 | import com.wx.architecture.code.base.BaseViewModel 4 | import com.wx.architecture.data_source.kapt.RNetApiRepository 5 | import kotlinx.coroutines.flow.onEach 6 | 7 | class MainViewModel : BaseViewModel() { 8 | 9 | private val repository by lazy { RNetApiRepository() } 10 | 11 | fun getHomeList(page: Int) { 12 | flowAsyncWorkOnViewModelScopeLaunch { 13 | val time = System.currentTimeMillis() 14 | repository.getHomeList(page).onEach { 15 | errorMsgLiveData.postValue(it.data?.datas!![0].title) 16 | android.util.Log.e("MainViewModel", "two 222 ${it.data?.datas!![0].title}") 17 | android.util.Log.e("MainViewModel", "耗时:${(System.currentTimeMillis() - time)} ms") 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /app_wx2/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/drawable-xhdpi/ic_loading.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/drawable-xhdpi/ic_loading.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/drawable/progressbar_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/layout/layout_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx2/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx2/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WXNetArchitecture 3 | 4 | 5 | 未知错误异常 6 | 网络超时 7 | 网络超时 8 | 网络错误 9 | 网络错误 10 | 服务器异常 11 | 无网络连接 12 | 请求地址错误 13 | 当前网络不可用 14 | 无法连接到服务器 15 | 数据错误,json解析错误 16 | 17 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 32 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app_wx2/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app_wx3/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app_wx3/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | id 'kotlin-kapt' 5 | } 6 | 7 | android { 8 | compileSdk 32 9 | 10 | defaultConfig { 11 | applicationId "com.wx.wxnetarchitecture" 12 | minSdk 21 13 | targetSdk 32 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | // testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_8 28 | targetCompatibility JavaVersion.VERSION_1_8 29 | } 30 | kotlinOptions { 31 | jvmTarget = '1.8' 32 | } 33 | kapt { 34 | generateStubs = true 35 | } 36 | } 37 | 38 | dependencies { 39 | // implementation fileTree(dir: 'libs', include: ['*.jar']) 40 | implementation 'org.jetbrains.kotlin:kotlin-reflect:1.7.0' 41 | 42 | implementation 'androidx.core:core-ktx:1.7.0' 43 | implementation 'androidx.appcompat:appcompat:1.3.0' 44 | implementation 'com.google.android.material:material:1.4.0' 45 | 46 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 47 | implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' 48 | implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' 49 | implementation 'com.squareup.okhttp3:okhttp:4.9.3' 50 | implementation 'com.squareup.okio:okio:2.10.0' 51 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0' 52 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 53 | 54 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' 55 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' 56 | implementation 'androidx.activity:activity-ktx:1.3.0-rc01' 57 | implementation 'androidx.fragment:fragment-ktx:1.4.0-alpha04' 58 | 59 | implementation project(path: ':NetworkApiData') 60 | kapt project(path: ':annotation_compiler') 61 | 62 | // testImplementation 'junit:junit:4.13.2' 63 | // androidTestImplementation 'androidx.test.ext:junit:1.1.3' 64 | // androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 65 | } -------------------------------------------------------------------------------- /app_wx3/libs/annotation_compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/libs/annotation_compiler.jar -------------------------------------------------------------------------------- /app_wx3/libs/annotations.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/libs/annotations.jar -------------------------------------------------------------------------------- /app_wx3/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app_wx3/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/MyApp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture 2 | 3 | import android.app.Application 4 | import com.wx.architecture.code.app.AppGlobals 5 | 6 | class MyApp : Application() { 7 | 8 | override fun onCreate() { 9 | super.onCreate() 10 | AppGlobals.sApplication = this 11 | } 12 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/app/AppGlobals.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.app 2 | 3 | import android.app.Application 4 | 5 | object AppGlobals { 6 | lateinit var sApplication: Application 7 | 8 | fun getApplication(): Application { 9 | if (!this::sApplication.isInitialized) { 10 | //去反射得到 11 | try { 12 | val aClass = Class.forName("android.app.ActivityThread") 13 | //获取里面的currentApplication 14 | val currentApplication = aClass.getDeclaredMethod("currentApplication") 15 | sApplication = currentApplication.invoke(null, *emptyArray()) as Application 16 | } catch (e: Exception) { 17 | e.printStackTrace() 18 | } 19 | } 20 | return sApplication 21 | } 22 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | class BaseFragment : Fragment() { 6 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/base/BaseRepositoryProxy.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import okhttp3.MultipartBody 4 | import okhttp3.RequestBody 5 | import kotlin.reflect.KFunction 6 | import kotlin.reflect.full.callSuspend 7 | import kotlin.reflect.full.memberFunctions 8 | import kotlin.reflect.javaType 9 | 10 | open class BaseRepositoryProxy { 11 | 12 | private val map by lazy { mutableMapOf?>() } 13 | private val sb by lazy { StringBuffer() } 14 | 15 | @OptIn(ExperimentalStdlibApi::class) 16 | fun findSuspendMethod(service: Class, methodName: String, args: Array): KFunction<*>? { 17 | sb.delete(0, sb.length) 18 | sb.append(service.name) 19 | .append(methodName) 20 | args.forEach { 21 | sb.append(it.javaClass.typeName) 22 | } 23 | val key = sb.toString() 24 | if (!map.containsKey(key)) { 25 | val function = service.kotlin.memberFunctions.find { f -> 26 | var isRight = 0 27 | if (f.name == methodName && f.isSuspend) { 28 | if (args.size == 0 && f.parameters.size == 1) { 29 | isRight = 2 30 | } else { 31 | f.parameters.forEachIndexed { index, it -> 32 | if (index > 0 && args.size > 0) { 33 | if (args.size == 0) { 34 | isRight = 2 35 | return@forEachIndexed 36 | } 37 | if (it.type.javaType.typeName == javaClassTransform(args[index - 1].javaClass).typeName) { 38 | isRight = 2 39 | } else { 40 | isRight = 1 41 | return@forEachIndexed 42 | } 43 | } 44 | } 45 | } 46 | } 47 | //方法名一直 是挂起函数 方法参数个数一致, 参数类型一致 48 | f.name == methodName && f.isSuspend && f.parameters.size - 1 == args.size && isRight == 2 49 | } 50 | map[key] = function 51 | } 52 | return map[key] 53 | } 54 | 55 | private fun javaClassTransform(clazz: Class) = when (clazz.typeName) { 56 | "java.lang.Integer" -> Int::class.java 57 | "java.lang.String" -> String::class.java 58 | "java.lang.Float" -> Float::class.java 59 | "java.lang.Long" -> Long::class.java 60 | "java.lang.Boolean" -> Boolean::class.java 61 | "java.lang.Double" -> Double::class.java 62 | "java.lang.Byte" -> Byte::class.java 63 | "java.lang.Short" -> Short::class.java 64 | "java.lang.Character" -> Char::class.java 65 | "SingletonMap" -> Map::class.java 66 | "LinkedHashMap" -> MutableMap::class.java 67 | "HashMap" -> HashMap::class.java 68 | "Part" -> MultipartBody.Part::class.java 69 | "RequestBody" -> RequestBody::class.java 70 | else -> { 71 | if ("RequestBody" == clazz.superclass.simpleName) { 72 | RequestBody::class.java 73 | } else { 74 | Any::class.java 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/base/BaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.viewModelScope 6 | import com.wx.architecture.code.data.DialogBean 7 | import com.wx.architecture.code.ex.flowOnIOAndCatch 8 | import com.wx.test.api.data.wanandroid.CommonResult 9 | import kotlinx.coroutines.CoroutineScope 10 | import kotlinx.coroutines.NonCancellable.start 11 | import kotlinx.coroutines.cancel 12 | import kotlinx.coroutines.flow.Flow 13 | import kotlinx.coroutines.flow.collect 14 | import kotlinx.coroutines.flow.onCompletion 15 | import kotlinx.coroutines.flow.onStart 16 | import kotlinx.coroutines.launch 17 | 18 | open class BaseViewModel : ViewModel() { 19 | val errorMsgLiveData by lazy { MutableLiveData() } 20 | val showUIDialog by lazy { MutableLiveData() } 21 | 22 | fun show(strMessage: String = "正在请求数据") { 23 | val showBean = showUIDialog.value ?: DialogBean(strMessage, true) 24 | showBean.isShow = true 25 | showBean.msg = strMessage 26 | showUIDialog.postValue(showBean) 27 | } 28 | 29 | fun hide() { 30 | val showBean = showUIDialog.value ?: DialogBean("", true) 31 | showBean.isShow = false 32 | showUIDialog.postValue(showBean) 33 | } 34 | 35 | override fun onCleared() { 36 | viewModelScope.cancel() 37 | } 38 | 39 | protected fun Flow.flowOnIOAndCatch(): Flow = flowOnIOAndCatch(errorMsgLiveData) 40 | 41 | protected fun Flow.onStartAndShow(strMessage: String = "正在请求数据"): Flow = onStart { 42 | show() 43 | } 44 | 45 | protected fun Flow.onCompletionAndHide(): Flow = onCompletion { 46 | hide() 47 | } 48 | 49 | protected suspend fun Flow.onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() { 50 | onStartAndShow().onCompletionAndHide().flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 51 | } 52 | 53 | fun flowAsyncWorkOnViewModelScopeLaunch(flowAsyncWork: suspend () -> Flow) { 54 | viewModelScope.launch { 55 | flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 56 | } 57 | } 58 | 59 | // fun flowAsyncWorkOnViewModelScopeLaunch2(block: suspend CoroutineScope.() -> Unit) { 60 | // viewModelScope.launch { 61 | // val b = block.invoke(this) 62 | // b. onStartAndShow().onCompletionAndHide().flowOnIOAndCatch() 63 | // b 64 | //// flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 65 | // } 66 | // } 67 | 68 | // block: suspend CoroutineScope.() -> Unit 69 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/base/BaseViewModelActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import androidx.annotation.LayoutRes 6 | import androidx.annotation.MainThread 7 | import androidx.appcompat.app.AppCompatActivity 8 | import androidx.lifecycle.ViewModelLazy 9 | import com.wx.architecture.code.dialog.ShowUIDialog 10 | import java.lang.reflect.ParameterizedType 11 | 12 | 13 | open class BaseViewModelActivity(@LayoutRes val layResID: Int) : AppCompatActivity() { 14 | private var loading: ShowUIDialog? = null 15 | 16 | protected val viewModel by lazyViewModels() 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(layResID) 21 | initX() 22 | } 23 | 24 | protected fun initX() { 25 | bindObserve() 26 | } 27 | 28 | //是否loading 29 | open fun isShowloading(): Boolean? { 30 | return loading?.isShowing() 31 | } 32 | 33 | open fun showloading(showText: String?) { 34 | if (null == loading) loading = ShowUIDialog(this) 35 | if (isShowloading() == true) return 36 | if (showText != null) loading?.show(showText) 37 | } 38 | 39 | open fun hideLoading() { 40 | loading?.dismiss() 41 | loading = null 42 | } 43 | 44 | override fun onDestroy() { 45 | hideLoading() 46 | super.onDestroy() 47 | } 48 | 49 | protected fun bindObserve() { 50 | viewModel?.run { 51 | showUIDialog.observe(this@BaseViewModelActivity) { it -> 52 | if (it.isShow) showloading(it.msg) else hideLoading() 53 | } 54 | errorMsgLiveData.observe(this@BaseViewModelActivity) { 55 | //公共toast 提示样式可以自行封装 56 | Toast.makeText(this@BaseViewModelActivity, it, Toast.LENGTH_SHORT).show() 57 | } 58 | } 59 | } 60 | 61 | @MainThread 62 | inline fun lazyViewModels(): Lazy { 63 | val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class 64 | return ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) 65 | } 66 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/data/DialogBean.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.data 2 | 3 | data class DialogBean(var msg:String, var isShow:Boolean){ 4 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/dialog/ShowUIDialog.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.dialog 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.view.Gravity 6 | import android.view.View 7 | import android.widget.TextView 8 | import androidx.appcompat.app.AppCompatDialog 9 | import com.wx.architecture.R 10 | 11 | class ShowUIDialog : AppCompatDialog { 12 | 13 | lateinit var txt_loading_text: TextView 14 | 15 | constructor (context: Context) : super(context, R.style.Loading) { 16 | setContentView(R.layout.layout_loading) 17 | window?.run { 18 | txt_loading_text = findViewById(R.id.txt_loading_text) 19 | attributes.gravity = Gravity.CENTER 20 | } 21 | } 22 | 23 | fun show(showText: String) { 24 | txt_loading_text?.apply { 25 | if (showText.isNotEmpty()) { 26 | text = showText 27 | visibility = View.VISIBLE 28 | } else { 29 | visibility = View.GONE 30 | } 31 | } 32 | if (!isShowing()) { 33 | show() 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/ex/ExceptionEX.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | class ExceptionEX(val errorCode: Int, val errorMessage: String) : Exception(errorMessage) { 4 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/ex/Flow.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.wx.test.api.data.wanandroid.CommonResult 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.flow.* 7 | import java.lang.Exception 8 | 9 | 10 | fun Flow.flowOnIOAndCatch(errorMsgLiveData: MutableLiveData? = null): Flow = 11 | flowOn(Dispatchers.IO) 12 | .catch { 13 | it.printStackTrace() 14 | errorMsgLiveData?.value = it.parseErrorString(); 15 | } 16 | 17 | suspend fun Flow.flowOnIOAndCatchAAndCollect() { 18 | flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 19 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/ex/Throwable.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import com.google.gson.JsonSyntaxException 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.app.AppGlobals 6 | import com.wx.architecture.code.utils.isNetWorkActive 7 | import retrofit2.HttpException 8 | import java.io.InterruptedIOException 9 | import java.net.ConnectException 10 | import java.net.SocketException 11 | import java.net.SocketTimeoutException 12 | import java.net.UnknownHostException 13 | import java.util.concurrent.TimeoutException 14 | 15 | fun Throwable?.parseErrorString(): String = when (this) { 16 | is ConnectException, is SocketException -> { 17 | if (message?.contains("Network is unreachable") == true) 18 | getString(R.string.Mobilenetuseless_msg) 19 | if (message?.contains("Failed to connect to") == true) 20 | getString(R.string.failed_to_connect_to) 21 | else 22 | getString(R.string.ConnectException) 23 | } 24 | is HttpException -> { 25 | if (message?.contains("HTTP 50") == true) { 26 | message!!.substring(0, 8) 27 | } else { 28 | getString(R.string.HttpException) 29 | } 30 | } 31 | is InterruptedIOException -> { 32 | if (message?.contains("timeout") == true) 33 | getString(R.string.SocketTimeoutException) 34 | else 35 | getString(R.string.ConnectException) 36 | } 37 | is UnknownHostException -> getString(R.string.UnknownHostException) 38 | is JsonSyntaxException -> getString(R.string.JsonSyntaxException) 39 | is SocketTimeoutException, is TimeoutException -> getString(R.string.SocketTimeoutException) 40 | is IllegalArgumentException -> { 41 | if (message?.contains("baseUrl must end in ") == true) 42 | if (AppGlobals.sApplication.isNetWorkActive()) getString(R.string.HostBaseUrlError) 43 | else getString(R.string.Mobilenetuseless_msg) 44 | else message ?: getString(R.string.ElseNetException) 45 | } 46 | else -> getString(R.string.ElseNetException) 47 | } 48 | 49 | fun getString(resID: Int) = AppGlobals.sApplication.getString(resID) -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/code/utils/NetWorkHelp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.utils 2 | import android.app.Application 3 | import android.content.Context 4 | import android.net.ConnectivityManager 5 | import android.net.NetworkCapabilities 6 | import android.os.Build 7 | 8 | fun Application.isNetWorkActive(): Boolean { 9 | val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 10 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 11 | val network = connectivityManager.activeNetwork ?: return false 12 | val activeNetwork = 13 | connectivityManager.getNetworkCapabilities(network) ?: return false 14 | return when { 15 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true 16 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true 17 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true 18 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true 19 | else -> false 20 | } 21 | } else { 22 | @Suppress("DEPRECATION") val networkInfo = 23 | connectivityManager.activeNetworkInfo ?: return false 24 | @Suppress("DEPRECATION") 25 | return networkInfo.isConnected 26 | } 27 | return true 28 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/data_source/kapt/KaptInterface.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.kapt 2 | 3 | import com.wx.annotations.AutoCreateRepositoryInterface 4 | 5 | @AutoCreateRepositoryInterface(interfaceApi = "com.wx.test.api.net.NetApi") 6 | class KaptInterface { 7 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/data_source/repository/RepositoryPoxy.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.repository 2 | 3 | import com.wx.architecture.code.base.BaseRepositoryProxy 4 | import com.wx.test.api.net.NetApi 5 | import com.wx.test.api.retrofit.RetrofitUtils 6 | import kotlinx.coroutines.flow.catch 7 | import kotlinx.coroutines.flow.flow 8 | import okhttp3.MultipartBody 9 | import okhttp3.RequestBody 10 | import java.lang.reflect.InvocationTargetException 11 | import java.lang.reflect.Proxy 12 | import kotlin.reflect.full.callSuspend 13 | import kotlin.reflect.full.memberFunctions 14 | import kotlin.reflect.javaType 15 | 16 | class RepositoryPoxy private constructor() : BaseRepositoryProxy() { 17 | 18 | val service = NetApi::class.java 19 | val api by lazy { RetrofitUtils.instance.create(service) } 20 | 21 | 22 | companion object { 23 | val instance by lazy { RepositoryPoxy() } 24 | } 25 | 26 | fun callApiMethod(serviceR: Class): R { 27 | return Proxy.newProxyInstance(serviceR.classLoader, arrayOf(serviceR)) { proxy, method, args -> 28 | flow { 29 | val funcds = findSuspendMethod(service, method.name, args) 30 | if (args == null) { 31 | emit(funcds?.callSuspend(api)) 32 | } else { 33 | emit(funcds?.callSuspend(api, *args)) 34 | } 35 | // emit((service.getMethod(method.name, *parameterTypes)?.invoke(api, *(args ?: emptyArray())) as Call).execute().body()) 36 | }.catch { 37 | if (it is InvocationTargetException) { 38 | throw Throwable(it.targetException) 39 | } else { 40 | it.printStackTrace() 41 | throw it 42 | } 43 | } 44 | } as R 45 | } 46 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/data_source/tata.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source 2 | 3 | class tata { 4 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/ui/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.activity 2 | 3 | import android.view.View 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.base.BaseViewModelActivity 6 | import com.wx.architecture.ui.viewmodel.MainViewModel 7 | 8 | class MainActivity : BaseViewModelActivity(R.layout.activity_main), View.OnClickListener { 9 | 10 | override fun onClick(v: View?) { 11 | when (v?.id) { 12 | R.id.btn1 -> { 13 | viewModel.getHomeList(1) 14 | } 15 | else -> {} 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app_wx3/src/main/java/com/wx/architecture/ui/viewmodel/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.viewmodel 2 | 3 | import com.wx.architecture.code.base.BaseViewModel 4 | import com.wx.architecture.data_source.kapt.INetApiRepository 5 | import com.wx.architecture.data_source.repository.RepositoryPoxy 6 | import kotlinx.coroutines.flow.collect 7 | import kotlinx.coroutines.flow.onEach 8 | 9 | class MainViewModel : BaseViewModel() { 10 | 11 | private val repository by lazy { RepositoryPoxy.instance } 12 | 13 | fun getHomeList(page: Int) { 14 | flowAsyncWorkOnViewModelScopeLaunch { 15 | val time = System.currentTimeMillis() 16 | repository.callApiMethod(INetApiRepository::class.java).getHomeList(page).onEach { 17 | errorMsgLiveData.postValue(it.data?.datas!![0].title) 18 | android.util.Log.e("MainViewModel", "three 333 ${it.data?.datas!![0].title}") 19 | android.util.Log.e("MainViewModel", "耗时:${(System.currentTimeMillis() - time)} ms") 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app_wx3/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/drawable-xhdpi/ic_loading.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/drawable-xhdpi/ic_loading.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/drawable/progressbar_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/layout/layout_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx3/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx3/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WXNetArchitecture 3 | 4 | 5 | 未知错误异常 6 | 网络超时 7 | 网络超时 8 | 网络错误 9 | 网络错误 10 | 服务器异常 11 | 无网络连接 12 | 请求地址错误 13 | 当前网络不可用 14 | 无法连接到服务器 15 | 数据错误,json解析错误 16 | 17 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 32 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app_wx3/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app_wx4/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app_wx4/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | id 'kotlin-kapt' 5 | } 6 | 7 | android { 8 | compileSdk 32 9 | 10 | defaultConfig { 11 | applicationId "com.wx.wxnetarchitecture" 12 | minSdk 21 13 | targetSdk 32 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | // testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_8 28 | targetCompatibility JavaVersion.VERSION_1_8 29 | } 30 | kotlinOptions { 31 | jvmTarget = '1.8' 32 | } 33 | kapt { 34 | generateStubs = true 35 | } 36 | } 37 | 38 | dependencies { 39 | // implementation fileTree(dir: 'libs', include: ['*.jar']) 40 | implementation 'org.jetbrains.kotlin:kotlin-reflect:1.7.0' 41 | 42 | implementation 'androidx.core:core-ktx:1.7.0' 43 | implementation 'androidx.appcompat:appcompat:1.3.0' 44 | implementation 'com.google.android.material:material:1.4.0' 45 | 46 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 47 | implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' 48 | implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' 49 | implementation 'com.squareup.okhttp3:okhttp:4.9.3' 50 | implementation 'com.squareup.okio:okio:2.10.0' 51 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0' 52 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 53 | 54 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' 55 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' 56 | implementation 'androidx.activity:activity-ktx:1.3.0-rc01' 57 | implementation 'androidx.fragment:fragment-ktx:1.4.0-alpha04' 58 | 59 | implementation project(path: ':NetworkApiData') 60 | 61 | // testImplementation 'junit:junit:4.13.2' 62 | // androidTestImplementation 'androidx.test.ext:junit:1.1.3' 63 | // androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 64 | } -------------------------------------------------------------------------------- /app_wx4/libs/annotation_compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/libs/annotation_compiler.jar -------------------------------------------------------------------------------- /app_wx4/libs/annotations.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/libs/annotations.jar -------------------------------------------------------------------------------- /app_wx4/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app_wx4/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/MyApp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture 2 | 3 | import android.app.Application 4 | import com.wx.architecture.code.app.AppGlobals 5 | 6 | class MyApp : Application() { 7 | 8 | override fun onCreate() { 9 | super.onCreate() 10 | AppGlobals.sApplication = this 11 | } 12 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/app/AppGlobals.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.app 2 | 3 | import android.app.Application 4 | 5 | object AppGlobals { 6 | lateinit var sApplication: Application 7 | 8 | fun getApplication(): Application { 9 | if (!this::sApplication.isInitialized) { 10 | //去反射得到 11 | try { 12 | val aClass = Class.forName("android.app.ActivityThread") 13 | //获取里面的currentApplication 14 | val currentApplication = aClass.getDeclaredMethod("currentApplication") 15 | sApplication = currentApplication.invoke(null, *emptyArray()) as Application 16 | } catch (e: Exception) { 17 | e.printStackTrace() 18 | } 19 | } 20 | return sApplication 21 | } 22 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | class BaseFragment : Fragment() { 6 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/base/BaseRepositoryProxy.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import okhttp3.MultipartBody 4 | import okhttp3.RequestBody 5 | import kotlin.reflect.KFunction 6 | import kotlin.reflect.full.callSuspend 7 | import kotlin.reflect.full.memberFunctions 8 | import kotlin.reflect.javaType 9 | 10 | open class BaseRepositoryProxy { 11 | private val map by lazy { mutableMapOf?>() } 12 | private val sb by lazy { StringBuffer() } 13 | 14 | @OptIn(ExperimentalStdlibApi::class) 15 | fun findSuspendMethod(service: Class, methodName: String, args: Array): KFunction<*>? { 16 | sb.delete(0, sb.length) 17 | sb.append(service.name) 18 | .append(methodName) 19 | args.forEach { 20 | sb.append(it.javaClass.typeName) 21 | } 22 | val key = sb.toString() 23 | if (!map.containsKey(key)) { 24 | val function = service.kotlin.memberFunctions.find { f -> 25 | var isRight = 0 26 | if (f.name == methodName && f.isSuspend) { 27 | if (args.size == 0 && f.parameters.size == 1) { 28 | isRight = 2 29 | } else { 30 | f.parameters.forEachIndexed { index, it -> 31 | if (index > 0 && args.size > 0) { 32 | if (args.size == 0) { 33 | isRight = 2 34 | return@forEachIndexed 35 | } 36 | if (it.type.javaType.typeName == javaClassTransform(args[index - 1].javaClass).typeName) { 37 | isRight = 2 38 | } else { 39 | isRight = 1 40 | return@forEachIndexed 41 | } 42 | } 43 | } 44 | } 45 | } 46 | //方法名一直 是挂起函数 方法参数个数一致, 参数类型一致 47 | f.name == methodName && f.isSuspend && f.parameters.size - 1 == args.size && isRight == 2 48 | } 49 | map[key] = function 50 | } 51 | return map[key] 52 | } 53 | 54 | fun javaClassTransform(clazz: Class) = when (clazz.typeName) { 55 | "java.lang.Integer" -> Int::class.java 56 | "java.lang.String" -> String::class.java 57 | "java.lang.Float" -> Float::class.java 58 | "java.lang.Long" -> Long::class.java 59 | "java.lang.Boolean" -> Boolean::class.java 60 | "java.lang.Double" -> Double::class.java 61 | "java.lang.Byte" -> Byte::class.java 62 | "java.lang.Short" -> Short::class.java 63 | "java.lang.Character" -> Char::class.java 64 | "SingletonMap" -> Map::class.java 65 | "LinkedHashMap" -> MutableMap::class.java 66 | "HashMap" -> HashMap::class.java 67 | "Part" -> MultipartBody.Part::class.java 68 | "RequestBody" -> RequestBody::class.java 69 | else -> { 70 | if ("RequestBody" == clazz.superclass.simpleName) { 71 | RequestBody::class.java 72 | } else { 73 | Any::class.java 74 | } 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/base/BaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.viewModelScope 6 | import com.wx.architecture.code.data.DialogBean 7 | import com.wx.architecture.code.ex.flowOnIOAndCatch 8 | import com.wx.test.api.data.wanandroid.CommonResult 9 | import kotlinx.coroutines.CoroutineScope 10 | import kotlinx.coroutines.NonCancellable.start 11 | import kotlinx.coroutines.cancel 12 | import kotlinx.coroutines.flow.Flow 13 | import kotlinx.coroutines.flow.collect 14 | import kotlinx.coroutines.flow.onCompletion 15 | import kotlinx.coroutines.flow.onStart 16 | import kotlinx.coroutines.launch 17 | 18 | open class BaseViewModel : ViewModel() { 19 | val errorMsgLiveData by lazy { MutableLiveData() } 20 | val showUIDialog by lazy { MutableLiveData() } 21 | 22 | fun show(strMessage: String = "正在请求数据") { 23 | val showBean = showUIDialog.value ?: DialogBean(strMessage, true) 24 | showBean.isShow = true 25 | showBean.msg = strMessage 26 | showUIDialog.postValue(showBean) 27 | } 28 | 29 | fun hide() { 30 | val showBean = showUIDialog.value ?: DialogBean("", true) 31 | showBean.isShow = false 32 | showUIDialog.postValue(showBean) 33 | } 34 | 35 | override fun onCleared() { 36 | viewModelScope.cancel() 37 | } 38 | 39 | protected fun Flow.flowOnIOAndCatch(): Flow = flowOnIOAndCatch(errorMsgLiveData) 40 | 41 | protected fun Flow.onStartAndShow(strMessage: String = "正在请求数据"): Flow = onStart { 42 | show() 43 | } 44 | 45 | protected fun Flow.onCompletionAndHide(): Flow = onCompletion { 46 | hide() 47 | } 48 | 49 | protected suspend fun Flow.onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() { 50 | onStartAndShow().onCompletionAndHide().flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 51 | } 52 | 53 | fun flowAsyncWorkOnViewModelScopeLaunch(flowAsyncWork: suspend () -> Flow) { 54 | viewModelScope.launch { 55 | flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 56 | } 57 | } 58 | 59 | fun flowAsyncWorkOnViewModelScopeLaunch2(block: suspend CoroutineScope.() -> Unit) { 60 | viewModelScope.launch { 61 | block.invoke(this) 62 | // flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 63 | } 64 | } 65 | 66 | // block: suspend CoroutineScope.() -> Unit 67 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/base/BaseViewModelActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import androidx.annotation.LayoutRes 6 | import androidx.annotation.MainThread 7 | import androidx.appcompat.app.AppCompatActivity 8 | import androidx.lifecycle.ViewModelLazy 9 | import com.wx.architecture.code.dialog.ShowUIDialog 10 | import java.lang.reflect.ParameterizedType 11 | 12 | 13 | open class BaseViewModelActivity(@LayoutRes val layResID: Int) : AppCompatActivity() { 14 | private var loading: ShowUIDialog? = null 15 | 16 | protected val viewModel by lazyViewModels() 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(layResID) 21 | initX() 22 | } 23 | 24 | protected fun initX() { 25 | bindObserve() 26 | } 27 | 28 | //是否loading 29 | open fun isShowloading(): Boolean? { 30 | return loading?.isShowing() 31 | } 32 | 33 | open fun showloading(showText: String?) { 34 | if (null == loading) loading = ShowUIDialog(this) 35 | if (isShowloading() == true) return 36 | if (showText != null) loading?.show(showText) 37 | } 38 | 39 | open fun hideLoading() { 40 | loading?.dismiss() 41 | loading = null 42 | } 43 | 44 | override fun onDestroy() { 45 | hideLoading() 46 | super.onDestroy() 47 | } 48 | 49 | protected fun bindObserve() { 50 | viewModel?.run { 51 | showUIDialog.observe(this@BaseViewModelActivity) { it -> 52 | if (it.isShow) showloading(it.msg) else hideLoading() 53 | } 54 | errorMsgLiveData.observe(this@BaseViewModelActivity) { 55 | //公共toast 提示样式可以自行封装 56 | Toast.makeText(this@BaseViewModelActivity, it, Toast.LENGTH_SHORT).show() 57 | } 58 | } 59 | } 60 | 61 | @MainThread 62 | inline fun lazyViewModels(): Lazy { 63 | val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class 64 | return ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) 65 | } 66 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/data/DialogBean.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.data 2 | 3 | data class DialogBean(var msg:String, var isShow:Boolean){ 4 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/dialog/ShowUIDialog.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.dialog 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.view.Gravity 6 | import android.view.View 7 | import android.widget.TextView 8 | import androidx.appcompat.app.AppCompatDialog 9 | import com.wx.architecture.R 10 | 11 | class ShowUIDialog : AppCompatDialog { 12 | 13 | lateinit var txt_loading_text: TextView 14 | 15 | constructor (context: Context) : super(context, R.style.Loading) { 16 | setContentView(R.layout.layout_loading) 17 | window?.run { 18 | txt_loading_text = findViewById(R.id.txt_loading_text) 19 | attributes.gravity = Gravity.CENTER 20 | } 21 | } 22 | 23 | fun show(showText: String) { 24 | txt_loading_text?.apply { 25 | if (showText.isNotEmpty()) { 26 | text = showText 27 | visibility = View.VISIBLE 28 | } else { 29 | visibility = View.GONE 30 | } 31 | } 32 | if (!isShowing()) { 33 | show() 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/ex/ExceptionEX.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | class ExceptionEX(val errorCode: Int, val errorMessage: String) : Exception(errorMessage) { 4 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/ex/Flow.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.wx.test.api.data.wanandroid.CommonResult 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.flow.* 7 | import java.lang.Exception 8 | 9 | 10 | fun Flow.flowOnIOAndCatch(errorMsgLiveData: MutableLiveData? = null): Flow = 11 | flowOn(Dispatchers.IO) 12 | .catch { 13 | it.printStackTrace() 14 | errorMsgLiveData?.value = it.parseErrorString(); 15 | } 16 | 17 | suspend fun Flow.flowOnIOAndCatchAAndCollect() { 18 | flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 19 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/ex/Throwable.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import com.google.gson.JsonSyntaxException 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.app.AppGlobals 6 | import com.wx.architecture.code.utils.isNetWorkActive 7 | import retrofit2.HttpException 8 | import java.io.InterruptedIOException 9 | import java.net.ConnectException 10 | import java.net.SocketException 11 | import java.net.SocketTimeoutException 12 | import java.net.UnknownHostException 13 | import java.util.concurrent.TimeoutException 14 | 15 | fun Throwable?.parseErrorString(): String = when (this) { 16 | is ConnectException, is SocketException -> { 17 | if (message?.contains("Network is unreachable") == true) 18 | getString(R.string.Mobilenetuseless_msg) 19 | if (message?.contains("Failed to connect to") == true) 20 | getString(R.string.failed_to_connect_to) 21 | else 22 | getString(R.string.ConnectException) 23 | } 24 | is HttpException -> { 25 | if (message?.contains("HTTP 50") == true) { 26 | message!!.substring(0, 8) 27 | } else { 28 | getString(R.string.HttpException) 29 | } 30 | } 31 | is InterruptedIOException -> { 32 | if (message?.contains("timeout") == true) 33 | getString(R.string.SocketTimeoutException) 34 | else 35 | getString(R.string.ConnectException) 36 | } 37 | is UnknownHostException -> getString(R.string.UnknownHostException) 38 | is JsonSyntaxException -> getString(R.string.JsonSyntaxException) 39 | is SocketTimeoutException, is TimeoutException -> getString(R.string.SocketTimeoutException) 40 | is IllegalArgumentException -> { 41 | if (message?.contains("baseUrl must end in ") == true) 42 | if (AppGlobals.sApplication.isNetWorkActive()) getString(R.string.HostBaseUrlError) 43 | else getString(R.string.Mobilenetuseless_msg) 44 | else message ?: getString(R.string.ElseNetException) 45 | } 46 | else -> getString(R.string.ElseNetException) 47 | } 48 | 49 | fun getString(resID: Int) = AppGlobals.sApplication.getString(resID) -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/code/utils/NetWorkHelp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.utils 2 | import android.app.Application 3 | import android.content.Context 4 | import android.net.ConnectivityManager 5 | import android.net.NetworkCapabilities 6 | import android.os.Build 7 | 8 | fun Application.isNetWorkActive(): Boolean { 9 | val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 10 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 11 | val network = connectivityManager.activeNetwork ?: return false 12 | val activeNetwork = 13 | connectivityManager.getNetworkCapabilities(network) ?: return false 14 | return when { 15 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true 16 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true 17 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true 18 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true 19 | else -> false 20 | } 21 | } else { 22 | @Suppress("DEPRECATION") val networkInfo = 23 | connectivityManager.activeNetworkInfo ?: return false 24 | @Suppress("DEPRECATION") 25 | return networkInfo.isConnected 26 | } 27 | return true 28 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/data_source/repository/RepositoryPoxy.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.repository 2 | 3 | import com.wx.architecture.code.base.BaseRepositoryProxy 4 | import com.wx.test.api.net.NetApi 5 | import com.wx.test.api.retrofit.RetrofitUtils 6 | import kotlinx.coroutines.flow.Flow 7 | import kotlinx.coroutines.flow.flow 8 | import okhttp3.MultipartBody 9 | import okhttp3.RequestBody 10 | import retrofit2.Call 11 | import kotlin.reflect.full.callSuspend 12 | import kotlin.reflect.full.memberFunctions 13 | import kotlin.reflect.javaType 14 | 15 | class RepositoryPoxy private constructor() : BaseRepositoryProxy() { 16 | 17 | val service = NetApi::class.java 18 | val api by lazy { RetrofitUtils.instance.create(service) } 19 | 20 | 21 | companion object { 22 | val instance by lazy { RepositoryPoxy() } 23 | } 24 | 25 | fun callApiMethod(clazzR: Class, methodName: String, vararg args: Any): Flow { 26 | return flow { 27 | val clssss = mutableListOf>() 28 | args?.forEach { 29 | clssss.add(javaClassTransform(it.javaClass)) 30 | } 31 | val parameterTypes = clssss.toTypedArray() 32 | val call = (service.getMethod(methodName, *parameterTypes)?.invoke(api, *(args ?: emptyArray())) as Call) 33 | call?.execute()?.body()?.let { 34 | emit(it as R) 35 | } 36 | } 37 | } 38 | 39 | @OptIn(ExperimentalStdlibApi::class) 40 | fun callApiSuspendMethod(clazzR: Class, methodName: String, vararg args: Any): Flow { 41 | return flow { 42 | val funcds = findSuspendMethod(service, methodName, args) 43 | if (args == null) { 44 | emit(funcds?.callSuspend(api) as R) 45 | } else { 46 | emit(funcds?.callSuspend(api, *args) as R) 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/data_source/tata.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source 2 | 3 | class tata { 4 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/ui/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.activity 2 | 3 | import android.view.View 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.base.BaseViewModelActivity 6 | import com.wx.architecture.ui.viewmodel.MainViewModel 7 | 8 | class MainActivity : BaseViewModelActivity(R.layout.activity_main), View.OnClickListener { 9 | 10 | override fun onClick(v: View?) { 11 | when (v?.id) { 12 | R.id.btn1 -> { 13 | viewModel.getHomeList(1) 14 | } 15 | else -> {} 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app_wx4/src/main/java/com/wx/architecture/ui/viewmodel/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.viewmodel 2 | 3 | import com.wx.architecture.code.base.BaseViewModel 4 | import com.wx.architecture.data_source.repository.RepositoryPoxy 5 | import com.wx.test.api.data.wanandroid.home.HomeData 6 | import kotlinx.coroutines.flow.onEach 7 | 8 | class MainViewModel : BaseViewModel() { 9 | 10 | private val repository by lazy { RepositoryPoxy.instance } 11 | 12 | fun getHomeList(page: Int) { 13 | flowAsyncWorkOnViewModelScopeLaunch { 14 | val time = System.currentTimeMillis() 15 | repository.callApiSuspendMethod(HomeData::class.java, "getHomeListB", page).onEach { 16 | errorMsgLiveData.postValue(it.data?.datas!![0].title) 17 | android.util.Log.e("MainViewModel", "four 444 ${it.data?.datas!![0].title}") 18 | android.util.Log.e("MainViewModel", "耗时:${(System.currentTimeMillis() - time)} ms") 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app_wx4/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/drawable-xhdpi/ic_loading.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/drawable-xhdpi/ic_loading.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/drawable/progressbar_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/layout/layout_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx4/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx4/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WXNetArchitecture 3 | 4 | 5 | 未知错误异常 6 | 网络超时 7 | 网络超时 8 | 网络错误 9 | 网络错误 10 | 服务器异常 11 | 无网络连接 12 | 请求地址错误 13 | 当前网络不可用 14 | 无法连接到服务器 15 | 数据错误,json解析错误 16 | 17 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 32 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app_wx4/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app_wx_switch_net/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app_wx_switch_net/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | id 'dagger.hilt.android.plugin' 5 | id 'kotlin-kapt' 6 | } 7 | 8 | android { 9 | compileSdk 32 10 | 11 | defaultConfig { 12 | applicationId "com.wx.wxnetarchitecture5" 13 | minSdk 21 14 | targetSdk 32 15 | versionCode 1 16 | versionName "1.0" 17 | 18 | // testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | compileOptions { 28 | sourceCompatibility JavaVersion.VERSION_1_8 29 | targetCompatibility JavaVersion.VERSION_1_8 30 | } 31 | kotlinOptions { 32 | jvmTarget = '1.8' 33 | } 34 | 35 | kapt { 36 | generateStubs = true 37 | } 38 | } 39 | 40 | dependencies { 41 | 42 | implementation 'androidx.core:core-ktx:1.7.0' 43 | implementation 'androidx.appcompat:appcompat:1.3.0' 44 | implementation 'com.google.android.material:material:1.4.0' 45 | 46 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 47 | implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' 48 | implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' 49 | implementation 'com.squareup.okhttp3:okhttp:4.9.3' 50 | implementation 'com.squareup.okio:okio:2.10.0' 51 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0' 52 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 53 | 54 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' 55 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' 56 | implementation 'androidx.activity:activity-ktx:1.3.0-rc01' 57 | implementation 'androidx.fragment:fragment-ktx:1.4.0-alpha04' 58 | 59 | //hilt 60 | implementation "com.google.dagger:hilt-android:2.42" 61 | kapt "com.google.dagger:hilt-android-compiler:2.42" 62 | kapt 'androidx.hilt:hilt-compiler:1.0.0' 63 | 64 | implementation 'com.android.volley:volley:1.2.0' 65 | 66 | } -------------------------------------------------------------------------------- /app_wx_switch_net/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/MyApp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture 2 | 3 | import android.app.Application 4 | import com.wx.architecture.code.app.AppGlobals 5 | import dagger.hilt.android.HiltAndroidApp 6 | 7 | @HiltAndroidApp 8 | class MyApp : Application() { 9 | 10 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/app/AppGlobals.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.app 2 | 3 | import android.app.Application 4 | 5 | object AppGlobals { 6 | lateinit var sApplication: Application 7 | 8 | fun getApplication(): Application { 9 | if (!this::sApplication.isInitialized) { 10 | //去反射得到 11 | try { 12 | val aClass = Class.forName("android.app.ActivityThread") 13 | //获取里面的currentApplication 14 | val currentApplication = aClass.getDeclaredMethod("currentApplication") 15 | sApplication = currentApplication.invoke(null, *emptyArray()) as Application 16 | } catch (e: Exception) { 17 | e.printStackTrace() 18 | } 19 | } 20 | return sApplication 21 | } 22 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | class BaseFragment : Fragment() { 6 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/base/BaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.viewModelScope 6 | import com.wx.architecture.code.data.DialogBean 7 | import com.wx.architecture.code.ex.flowOnIOAndCatch 8 | import kotlinx.coroutines.CoroutineScope 9 | import kotlinx.coroutines.cancel 10 | import kotlinx.coroutines.flow.Flow 11 | import kotlinx.coroutines.flow.collect 12 | import kotlinx.coroutines.flow.onCompletion 13 | import kotlinx.coroutines.flow.onStart 14 | import kotlinx.coroutines.launch 15 | 16 | open class BaseViewModel : ViewModel() { 17 | val errorMsgLiveData by lazy { MutableLiveData() } 18 | val showUIDialog by lazy { MutableLiveData() } 19 | 20 | fun show(strMessage: String = "正在请求数据") { 21 | val showBean = showUIDialog.value ?: DialogBean(strMessage, true) 22 | showBean.isShow = true 23 | showBean.msg = strMessage 24 | showUIDialog.postValue(showBean) 25 | } 26 | 27 | fun hide() { 28 | val showBean = showUIDialog.value ?: DialogBean("", true) 29 | showBean.isShow = false 30 | showUIDialog.postValue(showBean) 31 | } 32 | 33 | override fun onCleared() { 34 | viewModelScope.cancel() 35 | } 36 | 37 | protected fun Flow.flowOnIOAndCatch(): Flow = flowOnIOAndCatch(errorMsgLiveData) 38 | 39 | protected fun Flow.onStartAndShow(strMessage: String = "正在请求数据"): Flow = onStart { 40 | show() 41 | } 42 | 43 | protected fun Flow.onCompletionAndHide(): Flow = onCompletion { 44 | hide() 45 | } 46 | 47 | protected suspend fun Flow.onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() { 48 | onStartAndShow().onCompletionAndHide().flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 49 | } 50 | 51 | fun flowAsyncWorkOnViewModelScopeLaunch(flowAsyncWork: suspend () -> Flow) { 52 | viewModelScope.launch { 53 | flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 54 | } 55 | } 56 | 57 | fun flowAsyncWorkOnViewModelScopeLaunch2(block: suspend CoroutineScope.() -> Unit) { 58 | viewModelScope.launch { 59 | block.invoke(this) 60 | // flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() 61 | } 62 | } 63 | 64 | // block: suspend CoroutineScope.() -> Unit 65 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/base/BaseViewModelActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.base 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import androidx.annotation.LayoutRes 6 | import androidx.annotation.MainThread 7 | import androidx.appcompat.app.AppCompatActivity 8 | import androidx.lifecycle.ViewModelLazy 9 | import com.wx.architecture.code.dialog.ShowUIDialog 10 | import java.lang.reflect.ParameterizedType 11 | 12 | 13 | open class BaseViewModelActivity(@LayoutRes val layResID: Int) : AppCompatActivity() { 14 | private var loading: ShowUIDialog? = null 15 | 16 | protected val viewModel by lazyViewModels() 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(layResID) 21 | initX() 22 | } 23 | 24 | protected fun initX() { 25 | bindObserve() 26 | } 27 | 28 | //是否loading 29 | open fun isShowloading(): Boolean? { 30 | return loading?.isShowing() 31 | } 32 | 33 | open fun showloading(showText: String?) { 34 | if (null == loading) loading = ShowUIDialog(this) 35 | if (isShowloading() == true) return 36 | if (showText != null) loading?.show(showText) 37 | } 38 | 39 | open fun hideLoading() { 40 | loading?.dismiss() 41 | loading = null 42 | } 43 | 44 | override fun onDestroy() { 45 | hideLoading() 46 | super.onDestroy() 47 | } 48 | 49 | protected fun bindObserve() { 50 | viewModel?.run { 51 | showUIDialog.observe(this@BaseViewModelActivity) { it -> 52 | if (it.isShow) showloading(it.msg) else hideLoading() 53 | } 54 | errorMsgLiveData.observe(this@BaseViewModelActivity) { 55 | //公共toast 提示样式可以自行封装 56 | Toast.makeText(this@BaseViewModelActivity, it, Toast.LENGTH_SHORT).show() 57 | } 58 | } 59 | } 60 | 61 | @MainThread 62 | inline fun lazyViewModels(): Lazy { 63 | val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class 64 | return ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) 65 | } 66 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/data/DialogBean.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.data 2 | 3 | data class DialogBean(var msg:String, var isShow:Boolean){ 4 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/dialog/ShowUIDialog.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.dialog 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.view.Gravity 6 | import android.view.View 7 | import android.widget.TextView 8 | import androidx.appcompat.app.AppCompatDialog 9 | import com.wx.architecture.R 10 | 11 | class ShowUIDialog : AppCompatDialog { 12 | 13 | lateinit var txt_loading_text: TextView 14 | 15 | constructor (context: Context) : super(context, R.style.Loading) { 16 | setContentView(R.layout.layout_loading) 17 | window?.run { 18 | txt_loading_text = findViewById(R.id.txt_loading_text) 19 | attributes.gravity = Gravity.CENTER 20 | } 21 | } 22 | 23 | fun show(showText: String) { 24 | txt_loading_text?.apply { 25 | if (showText.isNotEmpty()) { 26 | text = showText 27 | visibility = View.VISIBLE 28 | } else { 29 | visibility = View.GONE 30 | } 31 | } 32 | if (!isShowing()) { 33 | show() 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/ex/ExceptionEX.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | class ExceptionEX(val errorCode: Int, val errorMessage: String) : Exception(errorMessage) { 4 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/ex/Flow.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.flow.* 6 | import java.lang.Exception 7 | 8 | 9 | fun Flow.flowOnIOAndCatch(errorMsgLiveData: MutableLiveData? = null): Flow = 10 | flowOn(Dispatchers.IO) 11 | .catch { 12 | it.printStackTrace() 13 | errorMsgLiveData?.value = it.parseErrorString(); 14 | } 15 | 16 | suspend fun Flow.flowOnIOAndCatchAAndCollect() { 17 | flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 18 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/ex/Throwable.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.ex 2 | 3 | import com.google.gson.JsonSyntaxException 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.app.AppGlobals 6 | import com.wx.architecture.code.utils.isNetWorkActive 7 | import retrofit2.HttpException 8 | import java.io.InterruptedIOException 9 | import java.net.ConnectException 10 | import java.net.SocketException 11 | import java.net.SocketTimeoutException 12 | import java.net.UnknownHostException 13 | import java.util.concurrent.TimeoutException 14 | 15 | fun Throwable?.parseErrorString(): String = when (this) { 16 | is ConnectException, is SocketException -> { 17 | if (message?.contains("Network is unreachable") == true) 18 | getString(R.string.Mobilenetuseless_msg) 19 | if (message?.contains("Failed to connect to") == true) 20 | getString(R.string.failed_to_connect_to) 21 | else 22 | getString(R.string.ConnectException) 23 | } 24 | is HttpException -> { 25 | if (message?.contains("HTTP 50") == true) { 26 | message!!.substring(0, 8) 27 | } else { 28 | getString(R.string.HttpException) 29 | } 30 | } 31 | is InterruptedIOException -> { 32 | if (message?.contains("timeout") == true) 33 | getString(R.string.SocketTimeoutException) 34 | else 35 | getString(R.string.ConnectException) 36 | } 37 | is UnknownHostException -> getString(R.string.UnknownHostException) 38 | is JsonSyntaxException -> getString(R.string.JsonSyntaxException) 39 | is SocketTimeoutException, is TimeoutException -> getString(R.string.SocketTimeoutException) 40 | is IllegalArgumentException -> { 41 | if (message?.contains("baseUrl must end in ") == true) 42 | if (AppGlobals.getApplication().isNetWorkActive()) getString(R.string.HostBaseUrlError) 43 | else getString(R.string.Mobilenetuseless_msg) 44 | else message ?: getString(R.string.ElseNetException) 45 | } 46 | else -> getString(R.string.ElseNetException) 47 | } 48 | 49 | fun getString(resID: Int) = AppGlobals.getApplication().getString(resID) -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/utils/BuildParamUtils.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.utils 2 | 3 | import okhttp3.RequestBody 4 | 5 | object BuildParamUtils { 6 | 7 | fun buildParamUrl(url: String, map: MutableMap? = null): String { 8 | val sb = StringBuilder(url) 9 | .append("?") 10 | map?.forEach { 11 | sb.append(it.key) 12 | sb.append("=") 13 | sb.append(it.value) 14 | } 15 | return sb.toString() 16 | } 17 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/utils/NetWorkHelp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.utils 2 | import android.app.Application 3 | import android.content.Context 4 | import android.net.ConnectivityManager 5 | import android.net.NetworkCapabilities 6 | import android.os.Build 7 | 8 | fun Application.isNetWorkActive(): Boolean { 9 | val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 10 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 11 | val network = connectivityManager.activeNetwork ?: return false 12 | val activeNetwork = 13 | connectivityManager.getNetworkCapabilities(network) ?: return false 14 | return when { 15 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true 16 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true 17 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true 18 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true 19 | else -> false 20 | } 21 | } else { 22 | @Suppress("DEPRECATION") val networkInfo = 23 | connectivityManager.activeNetworkInfo ?: return false 24 | @Suppress("DEPRECATION") 25 | return networkInfo.isConnected 26 | } 27 | return true 28 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/code/utils/RequestBodyCreate.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.code.utils 2 | 3 | import okhttp3.MediaType.Companion.toMediaTypeOrNull 4 | import okhttp3.RequestBody 5 | 6 | object RequestBodyCreate { 7 | 8 | fun toBody(body: String) = RequestBody.create("application/json; charset=utf-8".toMediaTypeOrNull(), body) 9 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/data/CommonResult.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.data 2 | 3 | open class CommonResult { 4 | var data: T? = null 5 | var errorCode: Int? = 0 6 | var errorMsg: String? = null 7 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/data/HomeData.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.data 2 | 3 | 4 | class HomeData : CommonResult() { 5 | } 6 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/data/HomeItemBean.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.data 2 | 3 | data class HomeItemBean( 4 | val author:String, 5 | val chapterName:String, 6 | val link:String, 7 | val title:String 8 | ) 9 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/data/WanAndroidHome.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.data 2 | 3 | data class WanAndroidHome( 4 | val datas: MutableList, 5 | val curPage: Int, 6 | val size: Int, 7 | val total: Int 8 | ) -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/dl_hilt/AbstractHttp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.dl_hilt 2 | 3 | import com.wx.architecture.data_source.dl_hilt.annotation.BindHttpUrlConnection 4 | import com.wx.architecture.data_source.dl_hilt.annotation.BindOkhttp 5 | import com.wx.architecture.data_source.net.HttpUrlConnectionImpl 6 | import com.wx.architecture.data_source.net.INetApi 7 | import com.wx.architecture.data_source.net.OkhttpImpl 8 | import dagger.Binds 9 | import dagger.Module 10 | import dagger.hilt.InstallIn 11 | import dagger.hilt.components.SingletonComponent 12 | import javax.inject.Singleton 13 | 14 | @InstallIn(SingletonComponent::class) 15 | @Module 16 | abstract class AbstractHttp { 17 | 18 | @BindOkhttp 19 | @Singleton 20 | @Binds 21 | abstract fun bindOkhttp(h: OkhttpImpl): INetApi 22 | 23 | @BindHttpUrlConnection 24 | @Singleton 25 | @Binds 26 | abstract fun bindHttpUrlConnection(h: HttpUrlConnectionImpl): INetApi 27 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/dl_hilt/annotation/BindHttpUrlConnection.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.dl_hilt.annotation 2 | 3 | import java.lang.annotation.Retention 4 | import java.lang.annotation.RetentionPolicy 5 | import javax.inject.Qualifier 6 | 7 | @Qualifier 8 | @Retention(RetentionPolicy.RUNTIME) 9 | annotation class BindHttpUrlConnection() 10 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/dl_hilt/annotation/BindOkhttp.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.dl_hilt.annotation 2 | 3 | import java.lang.annotation.Retention 4 | import java.lang.annotation.RetentionPolicy 5 | import javax.inject.Qualifier 6 | 7 | @Qualifier 8 | @Retention(RetentionPolicy.RUNTIME) 9 | annotation class BindOkhttp() 10 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/net/HttpUrlConnectionImpl.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.net 2 | 3 | import com.google.gson.Gson 4 | import com.wx.architecture.code.utils.BuildParamUtils 5 | import com.wx.architecture.data_source.net.http.HttpUrlConnectionRequest 6 | import javax.inject.Inject 7 | 8 | class HttpUrlConnectionImpl @Inject constructor() : INetApi { 9 | private val gson by lazy { Gson() } 10 | 11 | override suspend fun getApi(url: String, clazzR: Class, header: MutableMap?, map: MutableMap?): R { 12 | val json = HttpUrlConnectionRequest.getResult(BuildParamUtils.buildParamUrl(url, map), header) 13 | android.util.Log.e("OkhttpImpl", "HttpUrlConnection 请求:${json}") 14 | return gson.fromJson(json, clazzR) 15 | } 16 | 17 | override suspend fun postApi(url: String, clazzR: Class, header: MutableMap?, body: String?): R { 18 | val json = HttpUrlConnectionRequest.postData(url, header, body) 19 | return gson.fromJson(json, clazzR) 20 | } 21 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/net/INetApi.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.net 2 | 3 | interface INetApi { 4 | /** 5 | * Get请求 6 | * @param url:请求地址 7 | * @param clazzR:返回对象类型 8 | * @param header:请求头 9 | * @param map:请求参数 10 | */ 11 | 12 | suspend fun getApi(url: String, clazzR: Class, header: MutableMap? = null, map: MutableMap? = null): R 13 | 14 | /** 15 | * Get请求 16 | * @param url:请求地址 17 | * @param clazzR:返回对象类型 18 | * @param header:请求头 19 | * @param map:请求参数 20 | * @param body:请求body 21 | */ 22 | suspend fun postApi(url: String, clazzR: Class, header: MutableMap? = null, body: String? = null): R 23 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/net/OkhttpImpl.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.net 2 | 3 | import com.google.gson.Gson 4 | import com.wx.architecture.code.utils.BuildParamUtils.buildParamUrl 5 | import com.wx.architecture.code.utils.RequestBodyCreate 6 | import okhttp3.OkHttpClient 7 | import okhttp3.Request 8 | import javax.inject.Inject 9 | 10 | class OkhttpImpl @Inject constructor() : INetApi { 11 | 12 | private val okHttpClient by lazy { OkHttpClient() } 13 | private val gson by lazy { Gson() } 14 | 15 | override suspend fun getApi(url: String, clazzR: Class, header: MutableMap?, map: MutableMap?): R { 16 | try { 17 | val request = Request.Builder().url(buildParamUrl(url, map)) 18 | header?.forEach { 19 | request.addHeader(it.key, it.value) 20 | } 21 | val response = okHttpClient.newCall(request.build()).execute() 22 | if (response.isSuccessful) { 23 | val json = response.body?.string() 24 | android.util.Log.e("OkhttpImpl","okhttp 请求:${json}") 25 | return gson.fromJson(json, clazzR) 26 | } else { 27 | throw RuntimeException("response fail") 28 | } 29 | } catch (e: Exception) { 30 | throw e 31 | } 32 | } 33 | 34 | override suspend fun postApi(url: String, clazzR: Class, header: MutableMap?, body: String?): R { 35 | try { 36 | val request = Request.Builder().url(url) 37 | header?.forEach { 38 | request.addHeader(it.key, it.value) 39 | } 40 | body?.let { 41 | request.post(RequestBodyCreate.toBody(it)) 42 | } 43 | val response = okHttpClient.newCall(request.build()).execute() 44 | if (response.isSuccessful) { 45 | return gson.fromJson(response.body.toString(), clazzR) 46 | } else { 47 | throw RuntimeException("response fail") 48 | } 49 | } catch (e: Exception) { 50 | throw e 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/net/http/HttpURLConnectionUtils.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.net.http 2 | 3 | import java.security.SecureRandom 4 | import java.security.cert.CertificateException 5 | import java.security.cert.X509Certificate 6 | import javax.net.ssl.* 7 | 8 | object HttpURLConnectionUtils { 9 | var mSSLSocketFactory: SSLSocketFactory? = null 10 | 11 | /** 12 | * 信任所有host 13 | */ 14 | val hnv = HostnameVerifier { _, _ -> true } 15 | 16 | /** 17 | * 设置https 18 | * 19 | * @author :Atar 20 | * @createTime:2015-9-17下午4:57:39 21 | * @version:1.0.0 22 | * @modifyTime: 23 | * @modifyAuthor: 24 | * @description: 25 | */ 26 | fun trustAllHosts() { 27 | try { 28 | val trustAllCerts = arrayOf(object : X509TrustManager { 29 | override fun getAcceptedIssuers(): Array { 30 | return arrayOf() 31 | } 32 | 33 | @Throws(CertificateException::class) 34 | override fun checkClientTrusted(chain: Array, authType: String) { 35 | } 36 | 37 | @Throws(CertificateException::class) 38 | override fun checkServerTrusted(chain: Array, authType: String) { 39 | } 40 | }) 41 | val sc = SSLContext.getInstance("TLS") 42 | sc.init(null, trustAllCerts, SecureRandom()) 43 | if (mSSLSocketFactory == null) { 44 | mSSLSocketFactory = sc.socketFactory 45 | } 46 | HttpsURLConnection.setDefaultHostnameVerifier(hnv) 47 | HttpsURLConnection.setDefaultSSLSocketFactory(mSSLSocketFactory) 48 | } catch (e: Exception) { 49 | e.printStackTrace() 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/repository/NetRepository.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source.repository 2 | 3 | import com.wx.architecture.data_source.data.HomeData 4 | import com.wx.architecture.data_source.data.WanAndroidHome 5 | import com.wx.architecture.data_source.dl_hilt.annotation.BindHttpUrlConnection 6 | import com.wx.architecture.data_source.dl_hilt.annotation.BindOkhttp 7 | import com.wx.architecture.data_source.net.INetApi 8 | import kotlinx.coroutines.flow.Flow 9 | import kotlinx.coroutines.flow.flow 10 | import javax.inject.Inject 11 | 12 | 13 | //class NetRepository @Inject constructor(@BindHttpUrlConnection val netHttp: INetApi) { 14 | class NetRepository @Inject constructor(@BindOkhttp val netHttp: INetApi) { 15 | 16 | suspend fun getHomeList(): Flow { 17 | return flow { 18 | netHttp.getApi("https://www.wanandroid.com/article/list/0/json", HomeData::class.java).data?.let { emit(it) } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/data_source/tata.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.data_source 2 | 3 | class tata { 4 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/ui/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.activity 2 | 3 | import android.view.View 4 | import com.wx.architecture.R 5 | import com.wx.architecture.code.base.BaseViewModelActivity 6 | import com.wx.architecture.ui.viewmodel.MainViewModel 7 | import dagger.hilt.android.AndroidEntryPoint 8 | 9 | @AndroidEntryPoint 10 | class MainActivity : BaseViewModelActivity(R.layout.activity_main), View.OnClickListener { 11 | 12 | override fun onClick(v: View?) { 13 | when (v?.id) { 14 | R.id.btn1 -> { 15 | viewModel.getHomeList() 16 | } 17 | else -> {} 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/java/com/wx/architecture/ui/viewmodel/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wx.architecture.ui.viewmodel 2 | 3 | import com.wx.architecture.code.base.BaseViewModel 4 | import com.wx.architecture.data_source.repository.NetRepository 5 | import dagger.hilt.android.lifecycle.HiltViewModel 6 | import kotlinx.coroutines.flow.onEach 7 | import javax.inject.Inject 8 | 9 | @HiltViewModel 10 | class MainViewModel @Inject constructor(private val repository: NetRepository) : BaseViewModel() { 11 | 12 | 13 | fun getHomeList() { 14 | flowAsyncWorkOnViewModelScopeLaunch { 15 | repository.getHomeList().onEach { 16 | val title = it.datas!![0].title 17 | android.util.Log.e("MainViewModel", "one 111 ${title}") 18 | errorMsgLiveData.postValue(title) 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/drawable-xhdpi/ic_loading.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/drawable-xhdpi/ic_loading.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/drawable/progressbar_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/layout/layout_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/app_wx_switch_net/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WXNetArchitecture 3 | 4 | 5 | 未知错误异常 6 | 网络超时 7 | 网络超时 8 | 网络错误 9 | 网络错误 10 | 服务器异常 11 | 无网络连接 12 | 请求地址错误 13 | 当前网络不可用 14 | 无法连接到服务器 15 | 数据错误,json解析错误 16 | 17 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 32 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app_wx_switch_net/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | dependencies { 5 | classpath 'com.google.dagger:hilt-android-gradle-plugin:2.42' 6 | } 7 | } 8 | 9 | plugins { 10 | id 'com.android.application' version '7.2.1' apply false 11 | id 'com.android.library' version '7.2.1' apply false 12 | id 'org.jetbrains.kotlin.android' version '1.7.10' apply false 13 | } 14 | 15 | 16 | 17 | task clean(type: Delete) { 18 | delete rootProject.buildDir 19 | } -------------------------------------------------------------------------------- /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=-Xmx2048m -Dfile.encoding=UTF-8 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 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgllss/WXNetArchitecture/0e8477a47090eb8366d5a4c6735a8b3b39f4145f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Sep 20 17:28:29 CST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | } 15 | rootProject.name = "WXNetArchitecture" 16 | include ':app_wx1' 17 | include ':app_wx2' 18 | include ':app_wx3' 19 | include ':app_wx4' 20 | include ':app_wx_switch_net' 21 | include ':annotation_compiler' 22 | include ':NetworkApiData' 23 | --------------------------------------------------------------------------------