范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

androidMVVM基础类深入封装及使用

  本篇 文章主要遵循Android mvvm进行代码架构构建 ,使代码耦合度高,扩展性强。本篇文章建议初级开发者阅读,大佬请忽略~~~~。 MVVM基础架构封装1.基础类BaseActivitypackage com.example.studymvvmproject01.base import android.content.pm.ActivityInfo import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.viewbinding.ViewBinding import com.example.studymvvmproject01.R import com.gyf.immersionbar.ImmersionBar abstract class BaseActivity : AppCompatActivity() { protected open var mBinding: VB? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = getViewBinding() setContentView(mBinding?.root) requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT//竖屏 initialize() } open fun initialize() { } abstract fun getViewBinding(): VB? override fun onDestroy() { super.onDestroy() mBinding = null }
  }
  2.BaseFragment 封装abstract class BaseFragment:Fragment() { protected open var binding:VB?=null protected open val mBinding get()= binding!! override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { binding = getViewBinding() return mBinding?.root } abstract fun getViewBinding(): VB? override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initialize() } open fun initialize() { } override fun onDestroy() { super.onDestroy() binding=null } }
  3.BaseViewModel 层封装typealias Block = suspend (CoroutineScope) -> T typealias Error = suspend (Exception) -> Unit typealias Cancel = suspend (Exception) -> Unit open class BaseViewModel : ViewModel() { var TAG="BaseViewModel" val needLogin = MutableLiveData().apply { value = false } protected fun launch( block: Block, error: Error? = null, cancel: Cancel? = null, showErrorToast: Boolean = true, ): Job { return viewModelScope.launch { try { block.invoke(this) } catch (e: Exception) { when (e) { is CancellationException -> { cancel?.invoke(e) } else -> { onError(e, showErrorToast) error?.invoke(e) } } } } } /** * 统一处理错误 * @param e 异常 * @param showErrorToast 是否显示错误吐司 */ @SuppressLint("WrongConstant") private fun onError(e: Exception, showErrorToast: Boolean) { when (e) { is ApiException -> { when (e.code) { -1001 -> { if (showErrorToast) { Toast.makeText(AppHelper.mContext,e.message,1000).show() } needLogin.value = true } // 其他错误 else -> { if (showErrorToast) Toast.makeText(AppHelper.mContext,e.message,1000).show() } } Log.e(TAG,e.toString()) } // 网络请求失败 is ConnectException, is SocketTimeoutException, is UnknownHostException, is HttpException -> { if (showErrorToast) Toast.makeText(AppHelper.mContext,"网络请求失败",1000).show() Log.e(TAG,"网络请求失败"+e.toString()) } // 数据解析错误 is JsonParseException -> { Log.e(TAG,"数据解析错误"+e.toString()) } // 其他错误 else -> { Log.e(TAG,"其他错误"+e.toString()) } } } }
  trip:关于 CoroutineScope 的介绍可以参考 zhuanlan.zhihu.com/p/2975435084.BaseVmActivity封装abstract class BaseVmActivity : BaseActivity() { protected open lateinit var mViewModel: VM //加载数量 protected open val mTotalCount = 20 protected open var mCurrentSize = 0//当前加载数量 protected open var mCurrentPage = 0//当前加载页数 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initViewModel() observer() initView() initData() setListener() } open fun setListener() { } open fun initData() { } open fun initView() { } /** * 订阅退出登录逻辑 */ private fun observer() { mViewModel.needLogin.observe(this, { //如果未登录,跳转到登录页面 if (it) { SpUtil.setBoolean(MyConfig.IS_LOGIN, false) //跳转登录页面 } }) } private fun initViewModel() { mViewModel = ViewModelProvider(this).get(viewModelClass()) } abstract fun viewModelClass(): Class override fun onDestroy() { super.onDestroy() mCurrentSize = 0 mCurrentPage = 0 } }5.BaseVMFragment封装abstract class BaseVMFragment : BaseFragment() { protected lateinit var mViewModel: VM private var lazyLoaded = false //分页参数 protected open val mTotalCount = 20//每次加载数量 protected open var mCurrentSize = 0//当前加载数量 protected open var mCurrentPage = 0//当前加载页数 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initViewModel() observe() initView() initData() setListener() } open fun setListener() { } open fun initData() { } open fun initView() { } open fun observe() { mViewModel.needLogin.observe(viewLifecycleOwner, { if (it) { SpUtil.setBoolean(MyConfig.IS_LOGIN, false) } }) } private fun initViewModel() { mViewModel = ViewModelProvider(this).get(viewModelClass()) } abstract fun viewModelClass(): Class override fun onResume() { super.onResume() if(!lazyLoaded){ lazyLoadData() lazyLoaded=true } } open fun lazyLoadData() { } }6.BaseRepository封装open class BaseRepository{ protected fun apiService(): Api { return RetrofitClient.create(Api::class.java) } }7.网络架构封装(1)RetrofitClient类object RetrofitClient{ private const val CALL_TIMEOUT = 10L private const val CONNECT_TIMEOUT = 20L private const val IO_TIMEOUT = 20L private val mRetrofit:Retrofit init { val loggingInterceptor = HttpLoggingInterceptor { Log.d("httpLog", it) } loggingInterceptor.level=HttpLoggingInterceptor.Level.BODY /** * OkHttpClient */ val okHttpClient=OkHttpClient.Builder() .callTimeout(CALL_TIMEOUT, TimeUnit.SECONDS) .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(IO_TIMEOUT, TimeUnit.SECONDS) .writeTimeout(IO_TIMEOUT, TimeUnit.SECONDS) //添加头部信息 .addInterceptor(AddCookiesInterceptor()) //拦截接口头部信息 // .addInterceptor(ReceivedCookiesInterceptor()) //日志拦截 .addInterceptor(loggingInterceptor) .retryOnConnectionFailure(true) .build() mRetrofit= Retrofit.Builder().client(okHttpClient) .baseUrl(Api.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build() } fun  create(tClass: Class?): T { return mRetrofit.create(tClass) } }(2)添加头部信息拦截class AddCookiesInterceptor:Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val builder:Request.Builder=chain.request().newBuilder(); val stringSet = SpUtil.getString(MyConfig.COOKIE) builder.addHeader("Authorization","Bearer "+stringSet) return chain.proceed(builder.build()) } }
  提示 此处 Authorization 为后台 jwt 认证服务接口认证
  以上部分为mvvm基础框架封装,下面部分主要讲解如何使用。
  实例接口Apiinterface Api { companion object{ // const val BASE_URL="https://www.wanandroid.com/" const val BASE_URL="http://172.16.7.3:8066/" } //体系数据 @GET("tree/json") suspend fun getTree(): MutableList /** * 获取登录token * 静态Header * @param requestBody body * @return */ @Headers("Authorization:Basic dmlkZW9hbmFseXNpczp2aWRlb2FuYWx5c2lz") @POST("/safeMobileServer/smc/auth/oauth/token") suspend fun toke(@Body requestBody: RequestBody?):LoginBean /** * 那些单位获取电厂作业数据 * @param headers 动态header * @param siteId 站点Id * @return */ @GET("/safeMobileServer/smc/psmgpersonloccur/personCntByType") suspend fun workIndex( @Query("siteId") siteId: Int, ):HomeProadBean }2.LoginBean 实体类class LoginBean { /** * access_token : fd770c91-83ab-414e-b204-1112c26aed55 * token_type : bearer * refresh_token : f5705a7a-914b-4371-ac56-f05f5c22406b * expires_in : 40755 * scope : server * tenant_id : 3 * license : made by kyny * user_id : 300 * site_id : 1 * active : true * dept_id : null * username : 66ADMIN */ private var access_token: String? = null private var token_type: String? = null private var refresh_token: String? = null private var expires_in = 0 private var scope: String? = null private var tenant_id = 0 private var license: String? = null private var user_id = 0 private var site_id = 0 private var active = false private var dept_id: Any? = null private var username: String? = null fun getAccess_token(): String? { return access_token } fun setAccess_token(access_token: String?) { this.access_token = access_token } fun getToken_type(): String? { return token_type } fun setToken_type(token_type: String?) { this.token_type = token_type } fun getRefresh_token(): String? { return refresh_token } fun setRefresh_token(refresh_token: String?) { this.refresh_token = refresh_token } fun getExpires_in(): Int { return expires_in } fun setExpires_in(expires_in: Int) { this.expires_in = expires_in } fun getScope(): String? { return scope } fun setScope(scope: String?) { this.scope = scope } fun getTenant_id(): Int { return tenant_id } fun setTenant_id(tenant_id: Int) { this.tenant_id = tenant_id } fun getLicense(): String? { return license } fun setLicense(license: String?) { this.license = license } fun getUser_id(): Int { return user_id } fun setUser_id(user_id: Int) { this.user_id = user_id } fun getSite_id(): Int { return site_id } fun setSite_id(site_id: Int) { this.site_id = site_id } fun isActive(): Boolean { return active } fun setActive(active: Boolean) { this.active = active } fun getDept_id(): Any? { return dept_id } fun setDept_id(dept_id: Any?) { this.dept_id = dept_id } fun getUsername(): String? { return username } fun setUsername(username: String?) { this.username = username } }3.HomeProadBean实体类class HomeProadBean { /** * code : 0 * msg : 成功获取电厂现场人数分类统计 * data : [ * {"personCnt":11,"typeCode":"OVERALL"} * ,{"personCnt":1,"typeCode":"OVERALL"} * ,{"personCnt":0,"typeCode":"STAFF"}, * {"personCnt":0,"typeCode":"OUTSRC"}, * {"personCnt":6,"typeCode":"OTHERS"}] */ private var code = 0 private var msg: String? = null private var data: List? = null fun getCode(): Int { return code } fun setCode(code: Int) { this.code = code } fun getMsg(): String? { return msg } fun setMsg(msg: String?) { this.msg = msg } fun getData(): List? { return data } fun setData(data: List?) { this.data = data } class DataBean { /** * personCnt : 11 * typeCode : OVERALL */ var personCnt = 0 var typeCode: String? = null var name: String? = null } }3.LoginRepositoryclass LoginRepository:BaseRepository() { suspend fun login()=apiService().getTree() suspend fun token(requestBody: RequestBody? ):LoginBean{ return apiService().toke(requestBody) } suspend fun workIndex(siteId:Int):HomeProadBean{ return apiService().workIndex(siteId) } }4.LoginViewModelclass LoginViewModel : BaseViewModel() { val repository by lazy { LoginRepository() } val loginInfo=MutableLiveData() val homeProadBean=MutableLiveData() fun login(requestBody: RequestBody?) { launch( block = { val token = repository.token(requestBody) loginInfo.value=token } ) } fun workIndex(siteId:Int) { launch( block = { homeProadBean.value= repository.workIndex(siteId) } ) } }5.LoginActivity 实现class LoginActivity : BaseVmActivity() { override fun viewModelClass(): Class { return LoginViewModel::class.java } override fun getViewBinding(): ActivityMain1Binding { return ActivityMain1Binding.inflate(layoutInflater) } override fun initData() { super.initData() //登录 val hashMap = HashMap() hashMap["scope"] = "server" hashMap["username"] = "66admin" hashMap["password"] = "Kyny@2021" hashMap["grant_type"] = "password" val requestBody = RequestUtil.getRequestBody(hashMap); mViewModel.login(requestBody) //登录返回结果数据订阅 mViewModel.workIndex(1) } override fun initView() { super.initView() mViewModel.loginInfo.observe(this, { mBinding?.tvContent?.text = it.getAccess_token() + "," + it.getUsername() //此处为登录接口,获取用户token SpUtil.setString(MyConfig.COOKIE, it.getAccess_token()) }) //此接口为获取正常数据接口,并需要带头部参数认证 mViewModel.homeProadBean.observe(this,{ it.getMsg()?.let { it1 -> Log.e("TAG", it1) } for(data in it.getData()!!){ Log.e("data", data?.personCnt.toString()) } }) } }6.RequestUtil
  此方法是将map集合转换为RequestBody实体类  object RequestUtil { fun getRequestBody(hashMap: HashMap): RequestBody? { val data = StringBuffer() if (hashMap != null && hashMap.size > 0) { val iter: Iterator<*> = hashMap.entries.iterator() while (iter.hasNext()) { val entry = iter.next() as Map.Entry<*, *> val key = entry.key!! val `val` = entry.value!! data.append(key).append("=").append(`val`).append("&") } } val jso = data.substring(0, data.length - 1) return RequestBody.create("application/x-www-form-urlencoded; charset=utf-8".toMediaTypeOrNull(), jso) } }
  end:以上为mvvm架构基础封装,如有不对之处请指教。
  源码地址: https://gitee.com/gxx123/android-mvvm-basic-framework

杜卡迪成为20232026MotoE供应商,市售电动车有望随之登场?Ducati在2021赛季的Misano第二站上与MotoGP主办单位Dorna一同招开记者会,表示将会在2023年到2026年赛季成为MotoE电动车赛事的独家供应商,这则消息一跨界跑旅新篇章,2022款本田NT1100海外发布不久前才正式在影片预告即将发布的HONDANT1100今(1021)日正式在海外登场,这台采用CRF1100LAfricaTwin作为基础架构打造的跨界跑旅车型,以前后17寸胎丰富2022雅马哈MT03钢铁侠版海外发布巴西YAMAHA和MARVEL漫威漫画合作推出一系列特殊彩绘车款,其中包含惊奇队长和黑豹两款彩绘的FAZER250美国队长LANDER250,最新推出的车款则是钢铁人彩绘的MT03刹车片怎么选?全球十大制动品牌一览一。布雷博BREMBO意大利布雷博,1961年创立自意大利的知名高性能制动器设计开发和制造厂商。1975年,法拉利开始在它的F1赛车上装备布雷博制动系统,随后阿斯顿马丁玛莎拉蒂等豪鲁格穆勒,一个价美质优的新兴刹车片品牌最近打算更换一下刹车片和刹车盘,想挑一个性价高制动灵敏又稳定的,而且和宝马的卓越驾驶操纵体验相匹配的刹车产品。国产和进口的品牌看了一大圈,没有看到特别合适的国产的担心性能和工艺跟不上市一周订销破千凯翼轩度实力圈粉年轻人日前,凯翼轩度锋芒来袭,新车主打运动家轿市场,共推六款版型。上市一周,凯翼轩度便凭借高颜值造型和出色的产品实力俘获众多年轻消费者的青睐,斩获订单破千,可见市场表现不俗。有媒体评价凯实力间的较量,凯翼轩度能否成为年轻人的首选?随着9095后年轻一代成为汽车市场的消费主体,各大车企纷纷抢滩年轻市场。而想要赢得年轻用户的青睐,并非易事,产品上需要在各个方面都切中他们的喜好,品牌上亦需要有年轻的气息。譬如说,人力资源技术公司Justworks视觉形象升级Justworks成立于2012年,是美国纽约一家人力资源技术公司,其提供的平台可帮助雇主管理薪资,福利,员工信息以及与雇佣相关的合规性,以使企业更容易启动运行和发展,并为中小型企美国造纸商Crane视觉形象升级Crane成立于1801年,是一家以100纯棉纸和文具闻名的美国造纸商。它的历史可以追溯到1770年,当时StephenCrane收购了马萨诸塞州波士顿附近的自由造纸厂,并成为美国教育培训机构MaydenAcademy视觉形象升级MaydenAcademy成立于2015年,为人们提供为期16周的沉浸式编码课程,其课程涵盖前端后端数据库框架单元测试结对编程和调试等知识。最近,他们推出了一个由英国布里斯托尔Fi商业银行CraftBank视觉形象设计CraftBank成立于2020年,是第一家获得美国佐治亚州银行和财政部以及联邦存款保险公司特许批准在佐治亚州亚特兰大运营的全新银行。该银行通过一个集成的数字化平台,以中小型企业为
家用汽车产品修理更换退货责任规定文件要点国家市场监督管理总局日前发布第43号令,公布家用汽车产品修理更换退货责任规定(以下简称汽车三包规定),自2022年1月1日起施行。该规章在2013年施行的家用汽车产品修理更车险理赔考试1000题(含答案)第六季1。保险公司调度完成,须及时以(ABCD)理赔系统APP等形式通知查勘定损和人伤案件处理人员进行理赔处理。A系统推送B电话C微信D短信2。保险公司可以采取以下模式开展查勘工作。(A轻奢出行,精致到每一处细节!GYXX极地冰冠双肩包体验不管是日常通勤,还是商务出行外出旅行,一款合适的背包总会考验选择的智慧。理想中的背包首先要外观时尚轻便舒适,其次细节方面做工精致容量够大,最好还要有可以保护笔记本ipad等数码设备网友评测丨杰科4K蓝光播放机G5700画质出众,媲美OPPO今年5月,蓝光播放机国民老品牌杰科又新出一款4KUHD蓝光播放机G5700。在各大品牌退局或已经停产,流媒体迅猛发展的情况下,作为蓝光国民老品牌的杰科还能不断出新,这点还是让人值得工业设计设计的系列化每个产品都有自己相应的品牌,而且品牌之下的产品都会发现其血脉相连的家族性。因此在进行产品设计形式上的创作技巧则更加直接和有用。今天为大家分享通过一个共同的元素打造产品系列化设计的优CulliganMOMA反渗透X7系列净水器美国Culligan康丽根80多年一直引领水处理行业的创新与服务,通过专业可靠的产品及售后服务,为用户创造健康,高品质的水环境。康丽根反渗透净水器X7系列产品应用于厨下净水,坚守做RTX30系列锁算力显卡被破解,挖矿软件NBMiner可实现70算力挖矿兼容机之家小牛带你发现更多新潮数码资讯!笔者月初曾写过一篇RTX3060LHR锁算力版被破解的文章,彼时一款名为miniZminer的挖矿软件,通过拉高核心频率调整显存时序等手段,成渝官方高姿态谈合作,民间相互贬低的现状如何打破成渝作为新一线城市中经常被网友拿来比较的两座网红城市,现实生活中两地群众基本不谈相互之间得看法,表现的相亲相爱,而两地居民在网上却是挣得不可开交,可谓川渝一家亲,成渝世代仇。究其原鸿蒙必将成为民族品牌代表数字乡村云平台是由鸿蒙公司独立自主研发打造的云平台,包括党务云政务云商务云村村通以及农产品展馆。按照中国的行政区域布署,国省市区县乡镇以及村,实现了线上线下虚实结合的运行模式,构建马斯克高价收购堂兄的公司,被控中饱私囊,若败诉面临高昂赔偿特斯拉首席执行官埃隆马斯克(ElonMusk)周一为5年前特斯拉以26亿美元收购Solarcity的交易进行了辩护,此前特斯拉股东指责他操纵交易以中饱私囊。如果马斯克败诉,可能面临比特币发电厂把一个1。2万年的冰川湖变成热水池比特币能改变未来吗?这个问题充满争论。但是比特币挖矿对于资源的损耗,和对环境的破坏却有目共睹,已经无可辩驳。最新的例子是,在纽约州北部有着1。2万年历史的冰川塞内卡湖,因为比特币挖