├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── tbright │ │ └── ktbaseproject │ │ └── demo │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── tbright │ │ │ └── ktbaseproject │ │ │ └── demo │ │ │ ├── BaseApplication.kt │ │ │ ├── GlobalConstants.kt │ │ │ ├── bean │ │ │ ├── Gank.kt │ │ │ └── MusicBean.kt │ │ │ ├── customconfig │ │ │ ├── HeaderInterceptor.kt │ │ │ ├── HttpConfig.kt │ │ │ └── ShowUIConfig.kt │ │ │ ├── extensions │ │ │ └── ActivityExtensions.kt │ │ │ ├── net │ │ │ ├── api │ │ │ │ ├── ApiServices.kt │ │ │ │ └── GankServices.kt │ │ │ └── response │ │ │ │ ├── BaseGankResponse.kt │ │ │ │ └── BaseMagicResponse.kt │ │ │ └── ui │ │ │ ├── TestProvider.kt │ │ │ ├── activity │ │ │ ├── MainActivity.kt │ │ │ ├── MainContract.kt │ │ │ └── MainPresenter.kt │ │ │ └── fragment │ │ │ ├── MainFragment.kt │ │ │ ├── MainFragmentContract.kt │ │ │ ├── MainFragmentModel.kt │ │ │ ├── MainFragmentPresenter.kt │ │ │ └── MyFragmentActivity.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_fragment.xml │ │ ├── activity_main.xml │ │ ├── bottom_dialog_mian.xml │ │ └── dialog_mian.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── aa.png │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values-sw1024dp │ │ └── dimens.xml │ │ ├── values-sw1280dp │ │ └── dimens.xml │ │ ├── values-sw1365dp │ │ └── dimens.xml │ │ ├── values-sw384dp │ │ └── dimens.xml │ │ ├── values-sw392dp │ │ └── dimens.xml │ │ ├── values-sw400dp │ │ └── dimens.xml │ │ ├── values-sw410dp │ │ └── dimens.xml │ │ ├── values-sw411dp │ │ └── dimens.xml │ │ ├── values-sw432dp │ │ └── dimens.xml │ │ ├── values-sw480dp │ │ └── dimens.xml │ │ ├── values-sw533dp │ │ └── dimens.xml │ │ ├── values-sw592dp │ │ └── dimens.xml │ │ ├── values-sw600dp │ │ └── dimens.xml │ │ ├── values-sw640dp │ │ └── dimens.xml │ │ ├── values-sw662dp │ │ └── dimens.xml │ │ ├── values-sw720dp │ │ └── dimens.xml │ │ ├── values-sw768dp │ │ └── dimens.xml │ │ ├── values-sw800dp │ │ └── dimens.xml │ │ ├── values-sw811dp │ │ └── dimens.xml │ │ ├── values-sw820dp │ │ └── dimens.xml │ │ ├── values-sw960dp │ │ └── dimens.xml │ │ ├── values-sw961dp │ │ └── dimens.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── provider_paths.xml │ └── test │ └── java │ └── com │ └── tbright │ └── ktbaseproject │ └── demo │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── ktbaselibrary ├── .gitignore ├── build.gradle ├── config.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── tbright │ │ └── ktbaselibrary │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── tbright │ │ │ └── ktbaselibrary │ │ │ ├── base │ │ │ ├── BaseActivity.kt │ │ │ ├── BaseCommonDialog.kt │ │ │ ├── BaseFragment.kt │ │ │ └── BaseResponse.kt │ │ │ ├── dialog │ │ │ ├── BottomCommonDialog.kt │ │ │ └── CommonDialog.kt │ │ │ ├── event │ │ │ ├── DefaultEventBusManager.kt │ │ │ └── MessageEvent.kt │ │ │ ├── extension │ │ │ ├── ActivityExtensions.kt │ │ │ ├── ContextExtensions.kt │ │ │ ├── ExtraExtensions.kt │ │ │ ├── FragmentExtensions.kt │ │ │ ├── ImageExtensions.kt │ │ │ ├── RetrofitExtensions.kt │ │ │ ├── StringExtensions.kt │ │ │ └── ViewExtensions.kt │ │ │ ├── global │ │ │ ├── GlobalConfig.kt │ │ │ └── GlobalConstants.kt │ │ │ ├── mvp │ │ │ ├── BaseModel.kt │ │ │ ├── BaseMvpActivity.kt │ │ │ ├── BaseMvpFragment.kt │ │ │ ├── BasePresenter.kt │ │ │ ├── BaseView.kt │ │ │ ├── IModel.kt │ │ │ └── IPresenter.kt │ │ │ ├── net │ │ │ ├── download │ │ │ │ ├── DownLoadEngine.kt │ │ │ │ ├── DownloadCallback.kt │ │ │ │ ├── DownloadManager.kt │ │ │ │ ├── DownloadQueue.kt │ │ │ │ ├── DownloadTask.kt │ │ │ │ └── OkHttpDownload.kt │ │ │ ├── exception │ │ │ │ └── NoNetworkException.kt │ │ │ └── interceptor │ │ │ │ ├── CacheInterceptor.kt │ │ │ │ └── MultiUrlInterceptor.kt │ │ │ ├── proxy │ │ │ ├── EventBusProxy.kt │ │ │ ├── HttpConfigProxy.kt │ │ │ └── ShowUIProxy.kt │ │ │ ├── utils │ │ │ ├── ActivityUtils.kt │ │ │ ├── AppUtils.kt │ │ │ ├── NetworkHelper.kt │ │ │ ├── ReflectUtils.kt │ │ │ ├── contentresolver │ │ │ │ ├── ContentResolverAnnotation.kt │ │ │ │ ├── ContentResolverManager.kt │ │ │ │ └── ContentResolverMethod.kt │ │ │ └── permission │ │ │ │ ├── PermissionExtension.kt │ │ │ │ └── PermissionFragment.kt │ │ │ └── widget │ │ │ └── LoadingDialogFragment.kt │ └── res │ │ ├── drawable │ │ ├── dialog_common_bg.xml │ │ └── loading_dialog_bg.xml │ │ ├── layout │ │ ├── dialog_common.xml │ │ └── loading_dialog_view.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── tbright │ └── ktbaselibrary │ └── ExampleUnitTest.kt ├── pic ├── 1.png └── 2.png ├── screenMatch.properties ├── screenMatch_example_dimens.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ktBaseLibrary 3 | 4 | ktBaseLibrary是基于 MVP + Retrofit + 协程 的android快速开发框架。 5 | 6 | 之前一直使用rxjava + retrofit。在使用了kotlin之后,接触了协程,现在retrofit已经支持了协程,在使用retrofit+协程之后,果断的抛弃了rxjava。 7 | 8 | 之所以抛弃了rxjava,主要有以下两个方面: 9 | > * 可以以同步的方式写出异步的代码。 10 | > * 减少一个rxjava的依赖,可以减小apk的体积 11 | 12 | 下面是以同步方式写出异步代码的实例: 13 | ```kotlin 14 | mainScope.launch { 15 | //网络请求 16 | val singlePoetry = ApiServices.instance.singlePoetry().response() 17 | 18 | //singlePoetry是网络请求的结果 19 | if (singlePoetry != null) { 20 | mView?.showResult(singlePoetry) 21 | } 22 | 23 | mView?.hideLoading() 24 | } 25 | ``` 26 | 以上代码简洁,逻辑清晰。 27 | 28 | 29 | # 框架简介 30 | 框架主体使用 ``kotlin + mvp + retrofit + 协程`` 的模式。另外引用了一些好用的第三方库以及自己封装的一些基础库。具体如下图: 31 | ![image](https://github.com/T-bright/ktBaseLibrary/blob/master/pic/2.png?raw=true) 32 | 33 | # 如何使用 34 | ## 1、依赖 35 | 在主项目app的build.gradle中依赖 36 | ``` 37 | dependencies { 38 | ... 39 | implementation 'com.tbright:ktbaselibrary:1.1.3' 40 | } 41 | ``` 42 | 在project的build.gradle中配置 43 | ``` 44 | allprojects { 45 | repositories { 46 | maven { url 'https://dl.bintray.com/tongsiwei49/ktbaselibrary/' } 47 | } 48 | } 49 | ``` 50 | 51 | 或者 下载到本地导入Module. 52 | 53 | ## 2、使用 54 | ### 2.1、配置http请求 55 | 需继承 ``HttpConfigProxy``,这里主要是统一处理错误的请求结果。下面是demo里面实现的一个,具体的大家可以根据自己的项目作修改,详细请看: 56 | [HttpConfig](https://github.com/T-bright/ktBaseLibrary/blob/master/app/src/main/java/com/tbright/ktbaseproject/demo/customconfig/HttpConfig.kt/) 57 | ``` 58 | class HttpConfig : HttpConfigProxy() { 59 | 60 | private var mRetrofit: Retrofit? = null 61 | 62 | private var mRetrofitBuilder: Retrofit.Builder? = null 63 | 64 | private var mOkHttpClientBuilder: OkHttpClient.Builder? = null 65 | 66 | // 67 | override var baseUrl: String = mBaseUrl 68 | 69 | override var baseUrls: Map 70 | set(value) {} 71 | get() { 72 | var urls = linkedMapOf() 73 | if (urls.isNotEmpty()) return urls 74 | if (GlobalConfig.isDebug) {//可以在这里动态切换服务 75 | urls[BASE_URL] = mBaseUrl 76 | urls[GANK_URL] = mGankUrl 77 | } else { 78 | urls[BASE_URL] = mBaseUrl 79 | urls[GANK_URL] = mGankUrl 80 | } 81 | return urls 82 | } 83 | 84 | override suspend fun parseResponseData(responseData: Deferred>): T? { 85 | try { 86 | var response = responseData.await() 87 | if (response.isResponseSuccess()) { 88 | return response.getResponseData() 89 | } else { 90 | MessageEvent( EVENTCODE_RESPONSE_FAIL,response.getResponseMessage()).send() 91 | return null 92 | } 93 | } catch (e: Throwable) { 94 | var errMsg = "网络异常" 95 | when (e) { 96 | is UnknownHostException -> errMsg = "连接失败" 97 | is ConnectException -> errMsg = "连接失败" 98 | is SocketTimeoutException -> errMsg = "连接超时" 99 | is InterruptedIOException -> errMsg = "连接中断" 100 | is SSLHandshakeException -> errMsg = "证书验证失败" 101 | is JSONException -> errMsg = "数据解析错误" 102 | is JsonSyntaxException -> errMsg = "数据解析错误" 103 | is NoNetworkException -> errMsg = "无可用网络" 104 | is HttpException -> { 105 | when (e.code()) { 106 | UNAUTHORIZED, FORBIDDEN -> {//这两个一般会要求重新登录 107 | MessageEvent(EVENTCODE_RELOGIN,errMsg).send() 108 | return null 109 | } 110 | } 111 | } 112 | else -> errMsg = e.message.toString() 113 | } 114 | MessageEvent(EVENTCODE_RESPONSE_FAIL, errMsg).send() 115 | } 116 | return null 117 | } 118 | 119 | override suspend fun parseResponseWrapperData(responseData: Deferred>,vararg needDisposeError:Any): BaseResponse? { 120 | try { 121 | var response = responseData.await() 122 | if (response.isResponseSuccess()) { 123 | return response 124 | } else { 125 | if(needDisposeError.contains(response.getResponseStatus())){//如果包含,不统一处理,在相应的页面特殊处理 126 | return response 127 | }else{ 128 | MessageEvent( EVENTCODE_RESPONSE_FAIL,response.getResponseMessage()).send() 129 | return null 130 | } 131 | } 132 | } catch (e: Throwable) { 133 | var errMsg = "网络异常" 134 | when (e) { 135 | is UnknownHostException -> errMsg = "连接失败" 136 | is ConnectException -> errMsg = "连接失败" 137 | is SocketTimeoutException -> errMsg = "连接超时" 138 | is InterruptedIOException -> errMsg = "连接中断" 139 | is SSLHandshakeException -> errMsg = "证书验证失败" 140 | is JSONException -> errMsg = "数据解析错误" 141 | is JsonSyntaxException -> errMsg = "数据解析错误" 142 | is NoNetworkException -> errMsg = "无可用网络" 143 | is HttpException -> { 144 | when (e.code()) { 145 | UNAUTHORIZED, FORBIDDEN -> {//这两个一般会要求重新登录 146 | MessageEvent(EVENTCODE_RELOGIN,errMsg).send() 147 | return null 148 | } 149 | } 150 | } 151 | else -> errMsg = e.message.toString() 152 | } 153 | MessageEvent(EVENTCODE_RESPONSE_FAIL, errMsg).send() 154 | } 155 | return null 156 | } 157 | 158 | 159 | override fun initRetrofit() { 160 | initClient() 161 | mRetrofitBuilder = Retrofit.Builder() 162 | mRetrofit = mRetrofitBuilder?.run { 163 | baseUrl(GlobalConfig.httpConfigProxy?.baseUrl ?: GlobalConfig.httpConfigProxy?.baseUrls!!.values.first())//如果项目就一个域名,可以直接使用baseUrl,baseUrls可以不用管 164 | .addConverterFactory(GsonConverterFactory.create()) 165 | .addCallAdapterFactory(CoroutineCallAdapterFactory()) 166 | .client(mOkHttpClientBuilder!!.build()) 167 | .build() 168 | build() 169 | } 170 | } 171 | 172 | private var mRetrofitServices = hashMapOf() 173 | 174 | @Suppress("UNCHECKED_CAST") 175 | override fun create(clazz: Class): T { 176 | var key = clazz.canonicalName 177 | var mRetrofitService = mRetrofitServices[key] 178 | if (mRetrofitService == null) { 179 | mRetrofitService = mRetrofit!!.create(clazz) 180 | mRetrofitServices[key!!] = mRetrofitService!! 181 | } 182 | return mRetrofitService as T 183 | } 184 | 185 | private fun initClient() { 186 | mOkHttpClientBuilder = OkHttpClient.Builder() 187 | mOkHttpClientBuilder?.run { 188 | if (GlobalConfig.isDebug) { 189 | val loggingInterceptor = HttpLoggingInterceptor() 190 | loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY 191 | //设置 Debug Log 模式 192 | addInterceptor(loggingInterceptor) 193 | } 194 | connectTimeout(TIME_OUT, TimeUnit.SECONDS) 195 | readTimeout(TIME_OUT, TimeUnit.SECONDS) 196 | writeTimeout(TIME_OUT, TimeUnit.SECONDS) 197 | 198 | //错误重连 199 | retryOnConnectionFailure(true) 200 | addInterceptor(CacheInterceptor()) 201 | addInterceptor(HeaderInterceptor()) 202 | addInterceptor(MultiUrlInterceptor()) 203 | 204 | } 205 | } 206 | } 207 | ``` 208 | 209 | ### 2.2、配置默认loading框 210 | 需继承 ``ShowUIProxy``。它的作用主要是统一显示请求网络是需要显示的loading框。下面是demo里面实现的一个,具体的大家可以根据自己的项目作修改,详细请看: 211 | [ShowUIConfig](https://github.com/T-bright/ktBaseLibrary/blob/master/app/src/main/java/com/tbright/ktbaseproject/demo/customconfig/ShowUIConfig.kt/) 212 | ``` 213 | class ShowUIConfig : ShowUIProxy { 214 | override fun parseResponseFailMessage(messageEvent: MessageEvent) { 215 | when (messageEvent.code) { 216 | EVENTCODE_RESPONSE_FAIL -> { 217 | hideLoading() 218 | if (messageEvent.data != null) { 219 | var errorMessage = messageEvent.data as String 220 | showError(errorMessage) 221 | } else { 222 | showError("网络错误") 223 | } 224 | } 225 | EVENTCODE_RELOGIN -> {//重新登录 226 | hideLoading() 227 | getTopActivity().reLogin() 228 | } 229 | } 230 | } 231 | 232 | override fun showLoading() { 233 | getTopActivity().showLoadingDialog() 234 | } 235 | 236 | override fun hideLoading() { 237 | getTopActivity().hideLoadingDialog() 238 | } 239 | 240 | override fun showError(errorMessage: String) { 241 | errorMessage.showToast() 242 | } 243 | } 244 | ``` 245 | ### 2.3、在Application中设置 246 | 这个是必须的 247 | ``` 248 | GlobalConfig.init(this,httpConfigProxy = HttpConfig(),showUIProxy = ShowUIConfig()) 249 | ``` 250 | 251 | ### 2.4、Activity 252 | 继承``BaseMvpActivity`` 253 | ``` 254 | class MainActivity : BaseMvpActivity(),MainContract.MainView { 255 | override fun getLayoutId(): Int { 256 | return R.layout.activity_main 257 | } 258 | 259 | override fun initView(savedInstanceState: Bundle?) { 260 | 261 | } 262 | 263 | override fun initData() { 264 | 265 | } 266 | } 267 | ``` 268 | 当然如果页面很简单,没有什么逻辑要处理,也可以继承 ``BaseActivity`` 。 269 | ``` 270 | class MainActivity : BaseActivity() { 271 | override fun getLayoutId(): Int { 272 | return R.layout.activity_main 273 | } 274 | 275 | override fun initView(savedInstanceState: Bundle?) { 276 | 277 | } 278 | 279 | override fun initData() { 280 | 281 | } 282 | } 283 | ``` 284 | ### 2.5、Fragment 285 | ``Fragment`` 的使用方式和 ``Activity`` 差不多,继承 ``BaseMvpFragment``。 286 | ``` 287 | class MainFragment : BaseMvpFragment(),MainFragmentContract.MainView { 288 | 289 | override fun getLayoutId(): Int { 290 | return R.layout.activity_main 291 | } 292 | 293 | override fun initView(savedInstanceState: Bundle?) { 294 | 295 | } 296 | 297 | override fun initData() { 298 | 299 | } 300 | 301 | } 302 | ``` 303 | 当然也可以直接继承 ``BaseFragment`` ,与直接继承 ``Activity`` 一样。 304 | 305 | ### 2.6、Presenter和View 306 | ``Presenter`` 需继承 ``BasePresenter`` ,``View`` 需继承 ``BaseView``。下面是demo的契约类,可以参考: 307 | ``` 308 | interface MainContract { 309 | 310 | abstract class MainPresenter : BasePresenter(){ 311 | 312 | abstract fun singlePoetry() 313 | 314 | ... 315 | } 316 | 317 | interface MainView : BaseView{ 318 | fun showResult(result : String) 319 | } 320 | } 321 | ``` 322 | 323 | 下面是MainPresenter的实例代码: 324 | ``` 325 | class MainPresenter : MainContract.MainPresenter() { 326 | 327 | override fun singlePoetry() { 328 | mView?.showLoading() 329 | mainScope.launch { 330 | //网络请求 331 | val singlePoetry = ApiServices.instance.singlePoetry().response() 332 | 333 | //singlePoetry是网络请求的结果 334 | if (singlePoetry != null) { 335 | mView?.showResult(singlePoetry) 336 | } 337 | 338 | mView?.hideLoading() 339 | } 340 | } 341 | 342 | } 343 | ``` 344 | 可以看见,网络请求的逻辑非常清晰。 345 | 346 | 具体的实例,可以参考demo。 347 | 348 | # 关于框架 349 | 后续会进一步完善,欢迎大家多都提意见 350 | 351 | QQ群(1105357684) 352 | 353 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | compileSdkVersion mCompileSdkVersion 9 | buildToolsVersion mBuildToolsVersion 10 | defaultConfig { 11 | applicationId "com.tbright.ktbaseproject.demo" 12 | minSdkVersion mMinSdkVersion 13 | targetSdkVersion mTargetSdkVersion 14 | versionCode versionCode 15 | versionName versionName 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(dir: 'libs', include: ['*.jar']) 34 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 35 | implementation 'androidx.appcompat:appcompat:1.1.0' 36 | implementation 'androidx.core:core-ktx:1.3.0' 37 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 38 | testImplementation 'junit:junit:4.13' 39 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 40 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 41 | // implementation project(path: ':ktbaselibrary') 42 | //快速开发库 mvp架构 43 | implementation "com.tbright:ktbaselibrary:1.1.4" 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/tbright/ktbaseproject/demo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.tbright.ktbaseproject.demo", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 39 | 40 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/BaseApplication.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo 2 | 3 | import android.app.Application 4 | import com.tbright.ktbaselibrary.global.GlobalConfig 5 | import com.tbright.ktbaseproject.demo.customconfig.HttpConfig 6 | import com.tbright.ktbaseproject.demo.customconfig.ShowUIConfig 7 | 8 | class BaseApplication : Application() { 9 | override fun onCreate() { 10 | super.onCreate() 11 | GlobalConfig.init(this,httpConfigProxy = HttpConfig(),showUIProxy = ShowUIConfig()) 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/GlobalConstants.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo 2 | 3 | object GlobalConstants { 4 | 5 | 6 | 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/bean/Gank.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.bean 2 | 3 | class Gank { 4 | var _id: String? = null 5 | var coverImageUrl: String? = null 6 | var desc: String? = null 7 | var title: String? = null 8 | var type: String? = null 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/bean/MusicBean.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.bean 2 | 3 | class MusicBean { 4 | var title: String? = null 5 | var cid: Int? = 0 6 | var channellist: List? = null 7 | } 8 | 9 | class ChannelList { 10 | var thumb: String? = null 11 | 12 | var name: String? = null 13 | 14 | var cate_name: String? = null 15 | 16 | var cate_sname: String? = null 17 | 18 | var ch_name: String? = null 19 | 20 | var value: Int? = null 21 | 22 | var channelid: String? = null 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/customconfig/HeaderInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.customconfig 2 | 3 | import android.text.TextUtils 4 | import com.tbright.ktbaseproject.demo.GlobalConstants 5 | import okhttp3.Interceptor 6 | import okhttp3.Response 7 | 8 | class HeaderInterceptor : Interceptor { 9 | override fun intercept(chain: Interceptor.Chain): Response { 10 | val authorization = "" 11 | var request = chain.request() 12 | val newBuilder = request.newBuilder() 13 | if (!TextUtils.isEmpty(authorization)) { 14 | newBuilder.header("Authorization", authorization!!) 15 | } 16 | val newRequest = newBuilder.method(request.method(), request.body()) 17 | .build() 18 | return chain.proceed(newRequest) 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/customconfig/HttpConfig.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.customconfig 2 | 3 | import com.google.gson.JsonSyntaxException 4 | import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory 5 | import com.tbright.ktbaselibrary.base.BaseResponse 6 | import com.tbright.ktbaselibrary.event.MessageEvent 7 | import com.tbright.ktbaselibrary.global.GlobalConfig 8 | import com.tbright.ktbaselibrary.global.TIME_OUT 9 | import com.tbright.ktbaselibrary.net.exception.NoNetworkException 10 | import com.tbright.ktbaselibrary.net.interceptor.CacheInterceptor 11 | import com.tbright.ktbaselibrary.net.interceptor.MultiUrlInterceptor 12 | import com.tbright.ktbaselibrary.proxy.HttpConfigProxy 13 | import kotlinx.coroutines.Deferred 14 | import okhttp3.OkHttpClient 15 | import okhttp3.logging.HttpLoggingInterceptor 16 | import org.json.JSONException 17 | import retrofit2.HttpException 18 | import retrofit2.Retrofit 19 | import retrofit2.converter.gson.GsonConverterFactory 20 | import java.io.InterruptedIOException 21 | import java.net.ConnectException 22 | import java.net.SocketTimeoutException 23 | import java.net.UnknownHostException 24 | import java.util.concurrent.TimeUnit 25 | import javax.net.ssl.SSLHandshakeException 26 | 27 | 28 | 29 | const val UNAUTHORIZED = 401 30 | const val FORBIDDEN = 403 31 | const val NOT_FOUND = 404 32 | const val REQUEST_TIMEOUT = 408 33 | const val INTERNAL_SERVER_ERROR = 500 34 | const val BAD_GATEWAY = 502 35 | const val SERVICE_UNAVAILABLE = 503 36 | const val GATEWAY_TIMEOUT = 504 37 | 38 | const val EVENTCODE_RELOGIN = 998 //需要重新登录 39 | const val EVENTCODE_RESPONSE_FAIL = 999 //http请求失败 40 | 41 | const val BASE_URL = "base_Url" 42 | const val mBaseUrl = "https://api.apiopen.top/" 43 | 44 | const val GANK_URL = "gank_Url" 45 | const val mGankUrl = "https://gank.io/" 46 | 47 | class HttpConfig : HttpConfigProxy() { 48 | 49 | private var mRetrofit: Retrofit? = null 50 | 51 | private var mRetrofitBuilder: Retrofit.Builder? = null 52 | 53 | private var mOkHttpClientBuilder: OkHttpClient.Builder? = null 54 | 55 | // 56 | override var baseUrl: String = mBaseUrl 57 | 58 | override var baseUrls: Map 59 | set(value) {} 60 | get() { 61 | var urls = linkedMapOf() 62 | if (urls.isNotEmpty()) return urls 63 | if (GlobalConfig.isDebug) {//可以在这里动态切换服务 64 | urls[BASE_URL] = mBaseUrl 65 | urls[GANK_URL] = mGankUrl 66 | } else { 67 | urls[BASE_URL] = mBaseUrl 68 | urls[GANK_URL] = mGankUrl 69 | } 70 | return urls 71 | } 72 | 73 | override suspend fun parseResponseData(responseData: Deferred>): T? { 74 | try { 75 | var response = responseData.await() 76 | if (response.isResponseSuccess()) { 77 | return response.getResponseData() 78 | } else { 79 | MessageEvent( EVENTCODE_RESPONSE_FAIL,response.getResponseMessage()).send() 80 | return null 81 | } 82 | } catch (e: Throwable) { 83 | var errMsg = "网络异常" 84 | when (e) { 85 | is UnknownHostException -> errMsg = "连接失败" 86 | is ConnectException -> errMsg = "连接失败" 87 | is SocketTimeoutException -> errMsg = "连接超时" 88 | is InterruptedIOException -> errMsg = "连接中断" 89 | is SSLHandshakeException -> errMsg = "证书验证失败" 90 | is JSONException -> errMsg = "数据解析错误" 91 | is JsonSyntaxException -> errMsg = "数据解析错误" 92 | is NoNetworkException -> errMsg = "无可用网络" 93 | is HttpException -> { 94 | when (e.code()) { 95 | UNAUTHORIZED, FORBIDDEN -> {//这两个一般会要求重新登录 96 | MessageEvent(EVENTCODE_RELOGIN,errMsg).send() 97 | return null 98 | } 99 | } 100 | } 101 | else -> errMsg = e.message.toString() 102 | } 103 | MessageEvent(EVENTCODE_RESPONSE_FAIL, errMsg).send() 104 | } 105 | return null 106 | } 107 | 108 | override suspend fun parseResponseWrapperData(responseData: Deferred>,vararg needDisposeError:Any): BaseResponse? { 109 | try { 110 | var response = responseData.await() 111 | if (response.isResponseSuccess()) { 112 | return response 113 | } else { 114 | if(needDisposeError.contains(response.getResponseStatus())){//如果包含,不统一处理,在相应的页面特殊处理 115 | return response 116 | }else{ 117 | MessageEvent( EVENTCODE_RESPONSE_FAIL,response.getResponseMessage()).send() 118 | return null 119 | } 120 | } 121 | } catch (e: Throwable) { 122 | var errMsg = "网络异常" 123 | when (e) { 124 | is UnknownHostException -> errMsg = "连接失败" 125 | is ConnectException -> errMsg = "连接失败" 126 | is SocketTimeoutException -> errMsg = "连接超时" 127 | is InterruptedIOException -> errMsg = "连接中断" 128 | is SSLHandshakeException -> errMsg = "证书验证失败" 129 | is JSONException -> errMsg = "数据解析错误" 130 | is JsonSyntaxException -> errMsg = "数据解析错误" 131 | is NoNetworkException -> errMsg = "无可用网络" 132 | is HttpException -> { 133 | when (e.code()) { 134 | UNAUTHORIZED, FORBIDDEN -> {//这两个一般会要求重新登录 135 | MessageEvent(EVENTCODE_RELOGIN,errMsg).send() 136 | return null 137 | } 138 | } 139 | } 140 | else -> errMsg = e.message.toString() 141 | } 142 | MessageEvent(EVENTCODE_RESPONSE_FAIL, errMsg).send() 143 | } 144 | return null 145 | } 146 | 147 | 148 | override fun initRetrofit() { 149 | initClient() 150 | mRetrofitBuilder = Retrofit.Builder() 151 | mRetrofit = mRetrofitBuilder?.run { 152 | baseUrl(GlobalConfig.httpConfigProxy?.baseUrl ?: GlobalConfig.httpConfigProxy?.baseUrls!!.values.first())//如果项目就一个域名,可以直接使用baseUrl,baseUrls可以不用管 153 | .addConverterFactory(GsonConverterFactory.create()) 154 | .addCallAdapterFactory(CoroutineCallAdapterFactory()) 155 | .client(mOkHttpClientBuilder!!.build()) 156 | .build() 157 | build() 158 | } 159 | } 160 | 161 | private var mRetrofitServices = hashMapOf() 162 | 163 | @Suppress("UNCHECKED_CAST") 164 | override fun create(clazz: Class): T { 165 | var key = clazz.canonicalName 166 | var mRetrofitService = mRetrofitServices[key] 167 | if (mRetrofitService == null) { 168 | mRetrofitService = mRetrofit!!.create(clazz) 169 | mRetrofitServices[key!!] = mRetrofitService!! 170 | } 171 | return mRetrofitService as T 172 | } 173 | 174 | private fun initClient() { 175 | mOkHttpClientBuilder = OkHttpClient.Builder() 176 | mOkHttpClientBuilder?.run { 177 | if (GlobalConfig.isDebug) { 178 | val loggingInterceptor = HttpLoggingInterceptor() 179 | loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY 180 | //设置 Debug Log 模式 181 | addInterceptor(loggingInterceptor) 182 | } 183 | connectTimeout(TIME_OUT, TimeUnit.SECONDS) 184 | readTimeout(TIME_OUT, TimeUnit.SECONDS) 185 | writeTimeout(TIME_OUT, TimeUnit.SECONDS) 186 | 187 | //错误重连 188 | retryOnConnectionFailure(true) 189 | addInterceptor(CacheInterceptor()) 190 | addInterceptor(HeaderInterceptor()) 191 | addInterceptor(MultiUrlInterceptor()) 192 | 193 | } 194 | } 195 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/customconfig/ShowUIConfig.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.customconfig 2 | 3 | 4 | import com.tbright.ktbaselibrary.event.MessageEvent 5 | import com.tbright.ktbaselibrary.extension.showToast 6 | import com.tbright.ktbaselibrary.proxy.ShowUIProxy 7 | import com.tbright.ktbaselibrary.utils.ActivityUtils.getTopActivity 8 | import com.tbright.ktbaseproject.demo.extensions.hideLoadingDialog 9 | import com.tbright.ktbaseproject.demo.extensions.reLogin 10 | import com.tbright.ktbaseproject.demo.extensions.showLoadingDialog 11 | 12 | 13 | class ShowUIConfig : ShowUIProxy { 14 | override fun parseResponseFailMessage(messageEvent: MessageEvent) { 15 | when (messageEvent.code) { 16 | EVENTCODE_RESPONSE_FAIL -> { 17 | hideLoading() 18 | if (messageEvent.data != null) { 19 | var errorMessage = messageEvent.data as String 20 | showError(errorMessage) 21 | } else { 22 | showError("网络错误") 23 | } 24 | } 25 | EVENTCODE_RELOGIN -> {//重新登录 26 | hideLoading() 27 | getTopActivity().reLogin() 28 | } 29 | } 30 | } 31 | 32 | override fun showLoading() { 33 | getTopActivity().showLoadingDialog() 34 | } 35 | 36 | override fun hideLoading() { 37 | getTopActivity().hideLoadingDialog() 38 | } 39 | 40 | override fun showError(errorMessage: String) { 41 | errorMessage.showToast() 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/extensions/ActivityExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.extensions 2 | 3 | import android.app.Activity 4 | import android.view.Gravity 5 | import android.view.LayoutInflater 6 | import android.widget.FrameLayout 7 | import androidx.appcompat.app.AppCompatActivity 8 | import com.tbright.ktbaselibrary.utils.AppUtils 9 | import com.tbright.ktbaseproject.demo.R 10 | 11 | //重新登录 12 | fun Activity.reLogin() { 13 | 14 | } 15 | 16 | private val processView = LayoutInflater.from(AppUtils.mApplication).inflate(R.layout.loading_dialog_view, null, false) 17 | 18 | fun Activity.showLoadingDialog() { 19 | if (this is AppCompatActivity) { 20 | var decorView = this.window.decorView as FrameLayout 21 | var lp = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT) 22 | lp.gravity = Gravity.CENTER 23 | if (decorView.indexOfChild(processView) != -1) { 24 | decorView.removeView(processView) 25 | } 26 | decorView.addView(processView, lp) 27 | } 28 | } 29 | 30 | fun Activity.hideLoadingDialog() { 31 | if (this is AppCompatActivity) { 32 | var decorView = this.window.decorView as FrameLayout 33 | if (decorView.indexOfChild(processView) != -1) { 34 | decorView.removeView(processView) 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/net/api/ApiServices.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.net.api 2 | 3 | import com.tbright.ktbaselibrary.extension.create 4 | import com.tbright.ktbaseproject.demo.bean.MusicBean 5 | import com.tbright.ktbaseproject.demo.net.response.BaseMagicResponse 6 | import kotlinx.coroutines.Deferred 7 | import retrofit2.http.* 8 | 9 | interface ApiServices { 10 | 11 | companion object { 12 | val instance: ApiServices by lazy { 13 | create(ApiServices::class.java) 14 | } 15 | } 16 | 17 | @GET("singlePoetry/") 18 | fun singlePoetry(): Deferred> 19 | 20 | @GET("musicBroadcasting/") 21 | fun getMusicList(): Deferred?>> 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/net/api/GankServices.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.net.api 2 | 3 | import com.tbright.ktbaselibrary.extension.create 4 | import com.tbright.ktbaselibrary.net.interceptor.MULTI_URL_HEADER 5 | import com.tbright.ktbaseproject.demo.bean.Gank 6 | import com.tbright.ktbaseproject.demo.customconfig.GANK_URL 7 | import com.tbright.ktbaseproject.demo.net.response.BaseGankResponse 8 | import kotlinx.coroutines.Deferred 9 | import retrofit2.http.GET 10 | import retrofit2.http.Headers 11 | 12 | interface GankServices { 13 | 14 | companion object { 15 | val instance: GankServices by lazy { 16 | create(GankServices::class.java) 17 | } 18 | } 19 | 20 | @GET("api/v2/categories/Girl") 21 | @Headers(MULTI_URL_HEADER + GANK_URL) //多域名header设置 22 | fun getGanHuo(): Deferred>> 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/net/response/BaseGankResponse.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.net.response 2 | 3 | import com.tbright.ktbaselibrary.base.BaseResponse 4 | 5 | class BaseGankResponse : BaseResponse() { 6 | 7 | var data: T? = null 8 | 9 | var msg: String? = null 10 | 11 | var status: Int = 100 12 | 13 | override fun isResponseSuccess(): Boolean { 14 | return status == 100 15 | } 16 | 17 | override fun getResponseData(): T? { 18 | return data 19 | } 20 | 21 | override fun getResponseMessage(): String? { 22 | return if (status == 100) "请求成功!!!" else msg 23 | } 24 | 25 | override fun getResponseStatus(): Any? { 26 | return status 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/net/response/BaseMagicResponse.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.net.response 2 | 3 | import com.tbright.ktbaselibrary.base.BaseResponse 4 | 5 | class BaseMagicResponse : BaseResponse() { 6 | 7 | var result: T? = null 8 | 9 | var message : String? = null 10 | 11 | var code = 200 12 | 13 | override fun isResponseSuccess(): Boolean { 14 | return code == 200 15 | } 16 | 17 | override fun getResponseData(): T? { 18 | return result 19 | } 20 | 21 | override fun getResponseMessage(): String? { 22 | return message 23 | } 24 | 25 | override fun getResponseStatus(): Any? { 26 | return code 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/TestProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui 2 | 3 | import android.content.ContentProvider 4 | import android.content.ContentValues 5 | import android.content.UriMatcher 6 | import android.database.Cursor 7 | import android.database.MatrixCursor 8 | import android.net.Uri 9 | import com.blankj.utilcode.util.SPUtils 10 | 11 | class TestProvider : ContentProvider() { 12 | companion object{ 13 | const val TEST_URI = "content://com.tbright.ktbaseproject.demo/insert" 14 | private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH) 15 | init { 16 | uriMatcher.addURI("com.tbright.ktbaseproject.demo", "insert", 0) 17 | } 18 | } 19 | 20 | override fun insert(uri: Uri, values: ContentValues?): Uri? { 21 | when (uriMatcher.match(uri)) { 22 | 0->{ 23 | SPUtils.getInstance().put("AAA","AAA") 24 | context?.contentResolver?.notifyChange(uri, null) 25 | } 26 | } 27 | return uri 28 | } 29 | 30 | override fun query(uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? { 31 | var cursor: Cursor? = null 32 | when (uriMatcher.match(uri)) { 33 | 0->{ 34 | val matrixCursor = MatrixCursor(arrayOf("AAA")) 35 | matrixCursor.addRow(arrayOf(SPUtils.getInstance().getString("AAA"))) 36 | cursor = matrixCursor 37 | } 38 | } 39 | 40 | return cursor 41 | } 42 | 43 | override fun onCreate(): Boolean { 44 | return false 45 | } 46 | 47 | override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int { 48 | return 1 49 | } 50 | 51 | override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int { 52 | return 1 53 | } 54 | 55 | override fun getType(uri: Uri): String? { 56 | return null 57 | } 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui.activity 2 | 3 | import android.Manifest 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import com.blankj.utilcode.util.SizeUtils 7 | import com.tbright.ktbaselibrary.dialog.BottomCommonDialog 8 | import com.tbright.ktbaselibrary.dialog.CommonDialog 9 | import com.tbright.ktbaselibrary.extension.showToast 10 | import com.tbright.ktbaselibrary.mvp.BaseMvpActivity 11 | import com.tbright.ktbaselibrary.utils.contentresolver.ContentObserverUri 12 | import com.tbright.ktbaselibrary.utils.contentresolver.ContentResolverManager 13 | import com.tbright.ktbaselibrary.utils.permission.checkPermissions 14 | import com.tbright.ktbaseproject.demo.R 15 | import com.tbright.ktbaseproject.demo.ui.TestProvider 16 | import com.tbright.ktbaseproject.demo.ui.fragment.MyFragmentActivity 17 | import kotlinx.android.synthetic.main.activity_main.* 18 | import kotlinx.android.synthetic.main.dialog_mian.* 19 | 20 | 21 | class MainActivity : BaseMvpActivity(), 22 | MainContract.MainView { 23 | 24 | 25 | override fun getLayoutId(): Int { 26 | return R.layout.activity_main 27 | } 28 | 29 | override fun initView(savedInstanceState: Bundle?) { 30 | 31 | } 32 | 33 | override fun initData() { 34 | btGotoFragment.setOnClickListener { 35 | MyFragmentActivity.start(this,"修改前") 36 | } 37 | 38 | btGetNews.setOnClickListener { 39 | mPresenter?.singlePoetry() 40 | } 41 | 42 | btParallelRequest.setOnClickListener { 43 | mPresenter?.parallelRequest() 44 | } 45 | btChange.setOnClickListener { 46 | mPresenter?.changeBaseUrl() 47 | } 48 | btPermission.setOnClickListener { 49 | requestPer() 50 | } 51 | btDialog.setOnClickListener { 52 | CommonDialog(this,R.layout.dialog_mian).show { 53 | with(mContentView){//如果是自己自定义的布局可以使用这种方式。如果是框架内部请使用使用 message = "修改之后提示" 54 | tvMainMessage.text = "修改之后提示" 55 | tvMainIKnow.setOnClickListener { 56 | dismiss() 57 | } 58 | } 59 | } 60 | 61 | //这个用的是框架内部布局,不能使用上面那种方式。因为kotlin-android-extensions不支持 62 | // CommonDialog(this).show { 63 | // //如果是自己自定义的布局可以使用这种方式。如果是框架内部请使用使用 message = "修改之后提示" 64 | // message = "修改之后提示" 65 | // positiveClickListener { 66 | // dismiss() 67 | // } 68 | // } 69 | } 70 | btBottomDialog.setOnClickListener { 71 | BottomCommonDialog(R.layout.bottom_dialog_mian).show(supportFragmentManager) { 72 | setPeekHeight(SizeUtils.dp2px(250f)) 73 | } 74 | } 75 | 76 | //注册内容观察者 77 | ContentResolverManager.register(this) 78 | contentResolverManager.setOnClickListener { 79 | //向内容提供者里面插入一条数据 80 | contentResolver.insert(Uri.parse(TestProvider.TEST_URI),null) 81 | } 82 | } 83 | 84 | 85 | //当观察的uri发生了变化,此方法会被触发 86 | @ContentObserverUri(TestProvider.TEST_URI)//在注解上填写需要观察的uri 87 | fun contentResolver(uri : String){ 88 | when(uri){ 89 | TestProvider.TEST_URI->{ 90 | var result = "" 91 | var cursor = contentResolver.query(Uri.parse(TestProvider.TEST_URI),null,null,null,null) 92 | if (cursor != null) { 93 | while (cursor.moveToNext()) { 94 | result = cursor.getString(0) 95 | } 96 | } 97 | result.showToast() 98 | } 99 | } 100 | } 101 | 102 | private fun requestPer() { 103 | checkPermissions(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) { 104 | tvShow.text = if (it) "有权限" else "没有权限" 105 | } 106 | } 107 | 108 | override fun showResult(result: String) { 109 | tvShow.text = result 110 | } 111 | 112 | override fun onDestroy() { 113 | super.onDestroy() 114 | ContentResolverManager.unregister(this) 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/activity/MainContract.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui.activity 2 | 3 | import com.tbright.ktbaselibrary.mvp.BaseModel 4 | import com.tbright.ktbaselibrary.mvp.BasePresenter 5 | import com.tbright.ktbaselibrary.mvp.BaseView 6 | 7 | interface MainContract { 8 | 9 | abstract class MainPresenter : BasePresenter(){ 10 | 11 | abstract fun singlePoetry() 12 | 13 | //并行请求 14 | abstract fun parallelRequest () 15 | 16 | //并行请求 17 | abstract fun changeBaseUrl () 18 | } 19 | 20 | interface MainView : BaseView{ 21 | fun showResult(result : String) 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/activity/MainPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui.activity 2 | 3 | import com.tbright.ktbaselibrary.extension.create 4 | import com.tbright.ktbaselibrary.extension.response 5 | import com.tbright.ktbaseproject.demo.net.api.ApiServices 6 | import com.tbright.ktbaseproject.demo.net.api.GankServices 7 | import kotlinx.coroutines.async 8 | import kotlinx.coroutines.launch 9 | 10 | class MainPresenter : MainContract.MainPresenter() { 11 | 12 | 13 | override fun singlePoetry() { 14 | mView?.showLoading() 15 | mainScope.launch { 16 | val singlePoetry = ApiServices.instance.singlePoetry().response() 17 | if (singlePoetry != null) { 18 | mView?.showResult(singlePoetry) 19 | } 20 | mView?.hideLoading() 21 | } 22 | } 23 | 24 | //并行请求。当一个页面有多个请求的时候,可以并行请求 25 | override fun parallelRequest() { 26 | mView?.showLoading() 27 | mainScope.launch { 28 | 29 | //使用 async 并行网络 请求 30 | var singlePoetry = async { ApiServices.instance.singlePoetry().response() } 31 | 32 | var musicList = async { ApiServices.instance.getMusicList().response() } 33 | 34 | var result = "${singlePoetry.await().toString()}------${musicList?.await()?.first()?.title}" 35 | 36 | mView?.showResult(result) 37 | 38 | mView?.hideLoading() 39 | } 40 | } 41 | 42 | override fun changeBaseUrl() { 43 | mView?.showLoading() 44 | mainScope.launch { 45 | var gank = GankServices.instance.getGanHuo().response() 46 | gank?.let { 47 | mView?.showResult(it.first().title!!) 48 | 49 | mView?.hideLoading() 50 | } 51 | } 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/fragment/MainFragment.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui.fragment 2 | 3 | import android.Manifest 4 | import android.os.Bundle 5 | import com.blankj.utilcode.util.SizeUtils 6 | import com.tbright.ktbaselibrary.dialog.BottomCommonDialog 7 | import com.tbright.ktbaselibrary.dialog.CommonDialog 8 | import com.tbright.ktbaselibrary.extension.gone 9 | import com.tbright.ktbaselibrary.mvp.BaseMvpFragment 10 | import com.tbright.ktbaselibrary.utils.permission.checkPermissions 11 | import com.tbright.ktbaseproject.demo.R 12 | import kotlinx.android.synthetic.main.activity_main.* 13 | import kotlinx.android.synthetic.main.dialog_mian.* 14 | 15 | class MainFragment : BaseMvpFragment(), MainFragmentContract.MainView { 16 | 17 | companion object { 18 | fun newInstance() = MainFragment() 19 | } 20 | 21 | override fun getLayoutId(): Int { 22 | return R.layout.activity_main 23 | } 24 | 25 | override fun initView(savedInstanceState: Bundle?) { 26 | btGotoFragment.gone() 27 | btGetNews.setOnClickListener { 28 | mPresenter?.singlePoetry() 29 | } 30 | btParallelRequest.setOnClickListener { 31 | mPresenter?.parallelRequest() 32 | } 33 | btChange.setOnClickListener { 34 | mPresenter?.changeBaseUrl() 35 | } 36 | btPermission.setOnClickListener { 37 | requestPer() 38 | } 39 | btDialog.setOnClickListener { 40 | CommonDialog(activity!!, R.layout.dialog_mian).show { 41 | with(mContentView) { //如果是自己自定义的布局可以使用这种方式。如果是框架内部请使用使用 message = "修改之后提示" 42 | tvMainMessage.text = "修改之后提示" 43 | tvMainIKnow.setOnClickListener { 44 | dismiss() 45 | } 46 | } 47 | } 48 | 49 | //这个用的是框架内部布局,不能使用上面那种方式。因为kotlin-android-extensions不支持 50 | // CommonDialog(this).show { 51 | // //如果是自己自定义的布局可以使用这种方式。如果是框架内部请使用使用 message = "修改之后提示" 52 | // message = "修改之后提示" 53 | // positiveClickListener { 54 | // dismiss() 55 | // } 56 | // } 57 | } 58 | btBottomDialog.setOnClickListener { 59 | BottomCommonDialog(R.layout.bottom_dialog_mian).show(childFragmentManager) { 60 | setPeekHeight(SizeUtils.dp2px(250f)) 61 | } 62 | } 63 | } 64 | 65 | override fun initData() { 66 | 67 | } 68 | 69 | 70 | private fun requestPer() { 71 | checkPermissions(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) { 72 | tvShow.text = if (it) "有权限" else "没有权限" 73 | } 74 | } 75 | 76 | override fun showResult(result: String) { 77 | tvShow.text = result 78 | } 79 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/fragment/MainFragmentContract.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui.fragment 2 | 3 | import com.tbright.ktbaselibrary.mvp.BasePresenter 4 | import com.tbright.ktbaselibrary.mvp.BaseView 5 | 6 | interface MainFragmentContract { 7 | 8 | abstract class MainPresenter : BasePresenter(){ 9 | 10 | abstract fun singlePoetry() 11 | 12 | //并行请求 13 | abstract fun parallelRequest () 14 | 15 | //并行请求 16 | abstract fun changeBaseUrl () 17 | } 18 | 19 | interface MainView : BaseView{ 20 | fun showResult(result : String) 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/fragment/MainFragmentModel.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui.fragment 2 | 3 | import com.tbright.ktbaselibrary.extension.response 4 | import com.tbright.ktbaselibrary.mvp.BaseModel 5 | import com.tbright.ktbaseproject.demo.net.api.ApiServices 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.launch 8 | 9 | class MainFragmentModel : BaseModel() { 10 | 11 | suspend fun singlePoetry(): String? { 12 | return ApiServices.instance.singlePoetry().response() 13 | } 14 | 15 | fun parallelRequest(result: (result: String?) -> Unit) { 16 | mainScope.launch { 17 | var singlePoetry = async { ApiServices.instance.singlePoetry().response() } 18 | 19 | var musicList = async { ApiServices.instance.getMusicList().response() } 20 | 21 | var mResult = "${singlePoetry.await().toString()}------${musicList?.await()?.first()?.title}" 22 | 23 | result.invoke(mResult) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/fragment/MainFragmentPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui.fragment 2 | 3 | import com.tbright.ktbaselibrary.extension.response 4 | import com.tbright.ktbaseproject.demo.net.api.GankServices 5 | import kotlinx.coroutines.launch 6 | 7 | class MainFragmentPresenter : MainFragmentContract.MainPresenter() { 8 | 9 | override var mModel: MainFragmentModel? = MainFragmentModel() 10 | 11 | override fun singlePoetry() { 12 | mView?.showLoading() 13 | mainScope.launch { 14 | var singlePoetry = mModel?.singlePoetry() 15 | singlePoetry?.let { 16 | mView?.showResult(it) 17 | } 18 | mView?.hideLoading() 19 | } 20 | } 21 | 22 | //并行请求。当一个页面有多个请求的时候,可以并行请求 23 | override fun parallelRequest() { 24 | mView?.showLoading() 25 | mModel?.parallelRequest { result -> 26 | if (result != null) { 27 | mView?.showResult(result) 28 | mView?.hideLoading() 29 | } 30 | } 31 | } 32 | 33 | override fun changeBaseUrl() { 34 | mView?.showLoading() 35 | mainScope.launch { 36 | var gank = GankServices.instance.getGanHuo().response() 37 | gank?.let { 38 | mView?.showResult(it.first().title!!) 39 | 40 | mView?.hideLoading() 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tbright/ktbaseproject/demo/ui/fragment/MyFragmentActivity.kt: -------------------------------------------------------------------------------- 1 | package com.tbright.ktbaseproject.demo.ui.fragment 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.util.Log 7 | import android.widget.Toast 8 | import com.tbright.ktbaselibrary.base.BaseActivity 9 | import com.tbright.ktbaselibrary.extension.addFragment 10 | import com.tbright.ktbaselibrary.extension.extraDelegate 11 | import com.tbright.ktbaselibrary.extension.showToast 12 | import com.tbright.ktbaseproject.demo.R 13 | import kotlinx.android.synthetic.main.activity_fragment.* 14 | 15 | class MyFragmentActivity : BaseActivity() { 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_fragment) 20 | } 21 | 22 | override fun getLayoutId(): Int { 23 | return R.layout.activity_fragment 24 | } 25 | 26 | private var content by extraDelegate("content", "") 27 | 28 | override fun initView(savedInstanceState: Bundle?) { 29 | Log.e("MyFragmentActivity",content) 30 | addFragment(R.id.contain, MainFragment.newInstance()) 31 | content = "修改后" 32 | Log.e("MyFragmentActivity",content) 33 | } 34 | 35 | override fun initData() { 36 | 37 | } 38 | 39 | companion object { 40 | fun start(context: Context, content: String) { 41 | context.startActivity(Intent(context, MyFragmentActivity::class.java).apply { 42 | putExtra("content", content) 43 | }) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 |