GithubHelp home page GithubHelp logo

ldlywt / fastjetpack Goto Github PK

View Code? Open in Web Editor NEW
605.0 5.0 91.0 225 KB

基于Kotlin、协程、Retrofit的网络请求封装,快速简单轻便。

Kotlin 100.00%
android mvvm android-architecture-components mvvm-architecture kotlin

fastjetpack's People

Contributors

ldlywt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

fastjetpack's Issues

试用了大佬的封装,想请教一个有关ApiResponse类的问题

我这边的数据返回的数据不太规范,或者说后台比较灵活,ApiResponse里data有时候不是data,有时候是多个bean,比如{data1:xx,data2:xx,code:xx,message:xx},我尝试去修改ApiResponse,但是发现不生效,请问能怎么扩展这个ApiResponse呢,我按照以下的写法,参考message的调用方法调用,无法成功,我在调用函数的时候,泛型使用的是UserInfo,但是实际上data拿不到,后台数据是用userInfo包裹的,所以我就加上一个,当然,如果我重写一套Response应该能实现,但是这样就太多样板代码了,总觉得

open class ApiResponse(
open val data: T? = null,
open val userInfo: UserInfo? = null,
open val code: Int? = null,
open val message: String? = null,
open val error: Throwable? = null,
) : Serializable {
val isSuccess: Boolean
get() = (code == 1 || code == 200)
}

data class ApiSuccessResponse(val response: T) : ApiResponse(
data = response
)

data class ApiLoginResponse(override val userInfo: UserInfo?) :
ApiResponse(userInfo = userInfo)

class ApiEmptyResponse : ApiResponse()

data class ApiFailedResponse(override val code: Int?, override val message: String?) :
ApiResponse(code = code, message = message)

data class ApiErrorResponse(val throwable: Throwable) :
ApiResponse(error = throwable)

关于架构设计上有些问题想请教下

1.如:登录;用户输入框的 username、password这种字段 长度、是否为空 之类的参数判断 放在 activity/fragment 中好 还是 viewModel 中好;根据谷歌官方架构指南以及他们提供的demo;我自己的理解好像是放到viewModel中更好;对项目结构设计不太懂。。。

2.如果在当前库的设计的基础上增加 room 缓存 可以提供下思路吗? 我开始参考google提供的demo中的设计;官方项目repo 都是返回的livedata 我觉得按照那样写模板代码太多了;就去掉了livedata 又借鉴您的项目 自己写了个四不像。。。
我自己尝试的写法:
抽象接口 Fetcher

interface Fetcher<ResultType> {

    suspend fun loadFromNetWork(): ResultType

    fun loadFromDb(): ResultType?

    fun shouldFetch(data: ResultType?): Boolean

    fun saveResult(data: ResultType)

    suspend fun getResult(): Result<ResultType>
    
    //异常返回的body处理
    fun parseException(err: HttpException): Result.ErrorBody
}

实现类 SmartFetcher

abstract class SmartFetcher<RequestType> : Fetcher<RequestType> {

    override suspend fun getResult(): Result<RequestType> {
        var dbSource = loadFromDb()
        return if (shouldFetch(dbSource)){
            try {
                var result = loadFromNetWork()
                saveResult(result)
                dbSource = loadFromDb()
                Result.success(dbSource)
            }catch (e: HttpException){
                var error = parseException(e)
                Result.error(error.message?:e.message(), dbSource, error)
            }catch (e: Exception){
                Result.error(e.message?:"unknown error", dbSource)
            }
        }else{
            Result.success(dbSource)
        }
    }

}

调用示例,在Repo中 定义请求方法

    suspend fun request(): Result<Bean> {
        return object : SmartFetcher<Bean>() {
            override suspend fun loadFromNetWork(): Bean {
                TODO("Not yet implemented")
            }

            override fun loadFromDb(): Bean? {
                TODO("Not yet implemented")
            }

            override fun shouldFetch(data: Bean?): Boolean {
                TODO("Not yet implemented")
            }

            override fun saveResult(data: Bean) {
                TODO("Not yet implemented")
            }
        }.getResult()
    }

viewModel 中调用 repo 层:

    var mData = MutableLiveData<Result<Bean>>()

    fun sendEmailCode(){
        viewModelScope.launch(Dispatchers.IO) {
            mData.postValue(commonRepo.request())
        }
    }

activity 中监听

    mViewModel.mSendCode.observe(this, Observer { res ->
            dismissLoadingDialog()
    })

能处理一下返回的数据结构不一致的问题吗?有时候后台返回成功的数据是对象,失败的数据是数组这种怎么处理?

失败返回的数据:
{
"status_code": 9218,
"message": "密码错误,剩余4次输入",
"data": []
}

成功返回的数据:
{
"status_code": 1000,
"message": "成功",
"data": {
"id_no": "BtLhO2qmaOrvQSA5xbYTVqOJGJtd/oHkvIkTChI3c3c=",
"is_verifyed": 0,
"phone": "c59le6L65XK1htExLNic/w==",
}
}
我重写你那个Gson解析器,抛ApiFailedResponse这个函数一直有错,大佬能帮忙看下吗?

继承这个BaseToolBarActivity非要用LinearLayout,好坑

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.fastjetpack/com.aisier.ui.MainActivity}: java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.widget.RelativeLayout
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3455)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3598)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2164)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:241)
at android.app.ActivityThread.main(ActivityThread.java:7582)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:944)
Caused by: java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.widget.RelativeLayout
at com.aisier.databinding.ActivityMainBinding.bind(ActivityMainBinding.java:74)
at com.aisier.ui.MainActivity$special$$inlined$viewBindingActivity$default$1.invoke(ActivityViewBindings.kt:66)
at com.aisier.ui.MainActivity$special$$inlined$viewBindingActivity$default$1.invoke(Unknown Source:2)
at by.kirich1409.viewbindingdelegate.LifecycleViewBindingProperty.getValue(ViewBindingProperty.kt:75)
at by.kirich1409.viewbindingdelegate.LifecycleViewBindingProperty.getValue(ViewBindingProperty.kt:62)
at com.aisier.ui.MainActivity.getMBinding(MainActivity.kt:11)
at com.aisier.ui.MainActivity.init(MainActivity.kt:13)
at com.aisier.architecture.base.BaseToolBarActivity.onCreate(BaseToolBarActivity.kt:18)
at android.app.Activity.performCreate(Activity.java:7822)
at android.app.Activity.performCreate(Activity.java:7811)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1328)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3430)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3598) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2164) 
at android.os.Handler.dispatchMessage(Handler.java:107) 
at android.os.Looper.loop(Looper.java:241) 
at android.app.ActivityThread.main(ActivityThread.java:7582) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:944) 

建议使用扩展函数替代StateLiveData

首先感谢作者的分享,你的封装思路思路让我获益匪浅,我也打算在接下来的项目中参考你的写法(其实大部分都是引用你的代码,哈哈)。但美中不足的是,目前的写法要求所有的LiveData 必须采用自定义的StateLiveData,而这样有数据倒灌的风险,所以为了方便开发者使用其他的LiveData解决数据倒灌的问题,建议采用扩展函数的写法:

fun <T> LiveData<BaseResponse<T>>.observeState(
    owner: LifecycleOwner,
    callback: HttpRequestCallback<T>.() -> Unit
) {
    val requestCallback = HttpRequestCallback<T>().apply(callback)
    observe(owner, object : IStateObserver<T> {
        override fun onStart() {
            requestCallback.startCallback?.invoke()
        }

        override fun onSuccess(data: T) {
            requestCallback.successCallback?.invoke(data)
        }

        override fun onEmpty() {
            requestCallback.emptyCallback?.invoke()
        }

        override fun onFailure(e: ApiException) {
            requestCallback.failureCallback?.invoke(e)
        }

        override fun onError(data: T?, e: ApiException) {
            requestCallback.errorCallback?.invoke(data, e)
        }

        override fun onFinish() {
            requestCallback.finishCallback?.invoke()
        }

    })
}

这里不再使用之前的IStateObserver,而是以匿名内部类的形式传入自定义的Observer。这样一来就只是给LiveData加了一个扩展函数,解耦得更加彻底。

混淆问题

作者你好,我在看到你用 flow封装请求中,尝试写了一下,但是在混淆后安装app, 网络请求总是会回调到 fail函数里 请问应该怎么处理

LeakCanary

2022-04-18 22:04:38.095 26015-26015/com.fastjetpack D/LeakCanary: ​
┬───
│ GC Root: Global variable in native code

├─ android.app.Activity$1 instance
│ Leaking: UNKNOWN
│ Retaining 837.0 kB in 1912 objects
│ Library leak match: instance field android.app.Activity$1#this$0
│ Anonymous subclass of android.app.IRequestFinishCallback$Stub
│ this$0 instance of leakcanary.internal.activity.LeakActivity with mDestroyed = true
│ ↓ Activity$1.this$0
│ ~~~~~~
╰→ leakcanary.internal.activity.LeakActivity instance
​ Leaking: YES (ObjectWatcher was watching this because leakcanary.internal.activity.LeakActivity received
​ Activity#onDestroy() callback and Activity#mDestroyed is true)
​ Retaining 836.5 kB in 1911 objects
​ key = bad1d16c-cfe5-450d-bfc5-bd68a81e02ef
​ watchDurationMillis = 73278
​ retainedDurationMillis = 68278
​ mApplication instance of com.aisier.App
​ mBase instance of android.app.ContextImpl

METADATA

Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: Xiaomi
LeakCanary version: 2.7
App process name: com.fastjetpack
Stats: LruCache[maxSize=3000,hits=3873,misses=55638,hitRate=6%]
RandomAccess[bytes=3008222,reads=55638,travel=27328595255,range=20976546,size=25711956]
Heap dump reason: user request
Analysis duration: 5512 ms

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.