“我正在参加「掘金·启航计划」” 1.最近接收公司Android 项目 其中发现项目中每个Activity 类都继承了一个基类把 所有 的Activity 基本的方法都实现 感觉不错 这里记录一下也分享给大家
首先是BASEDBActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import com.weiaiyun.baselib.base.viewmodel.WayBaseViewModel
/**
* 项目名称:
* 类名称:WayBaseDbActivity
* 类描述:DataBindingActivity基类,,自动把ViewModel注入Activity和Databind注入进来了需要使用Databind的清继承它
* 作者:AlanPaine
* 创建时间: 2022/03/01-16:48
* 邮箱:AlanPaine@163.COM
* 修改简介:
*/
abstract class BaseDbActivity <VM : BaseViewModel, DB : ViewDataBinding> :BaseActivity<VM>(){
lateinit var mDatabind: DB
override fun onCreate(savedInstanceState: Bundle?) {
setUserDataBinding(true)
super.onCreate(savedInstanceState)
}
/**
* 创建DataBinding
*/
override fun initDataBind() {
mDatabind = DataBindingUtil.setContentView(this, getLayoutId())
mDatabind.lifecycleOwner = this
}
}
2 . BaseViewModel
import androidx.lifecycle.ViewModel
open class WayBaseViewModel : ViewModel() {
}
3.BaseActivity
这个类是 把Activity 绑定xml 和一些事件的方法抽出来
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.weiaiyun.baselib.action.BundleAction
import com.weiaiyun.baselib.action.ClickAction
import com.weiaiyun.baselib.action.HandlerAction
import com.weiaiyun.baselib.base.viewmodel.WayBaseViewModel
import com.weiaiyun.baselib.ext.getVmClazz
import com.weiaiyun.baselib.ext.hideSoftKeyboard
import java.util.*
abstract class BaseActivity <VM : BaseViewModel> : AppCompatActivity(), HandlerAction,
BundleAction, ClickAction {
lateinit var mViewModel: VM
/**
* startActivityForResult 方法优化
*/
private var mActivityCallback: OnActivityCallback? = null
private var mActivityRequestCode = 0
/**
* 是否需要使用DataBinding 供子类BaseVmDbActivity修改,用户请慎动
*/
private var isUserDb = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initLayout()
onIntentData()//获取数据
onViewCreated(savedInstanceState)//界面创建完成
createObserver()
initData()
}
/**
* 获取getIntent();数据
*/
open fun onIntentData() {
}
/**
* 获取布局id
*/
abstract fun getLayoutId(): Int
/**
* 初始化view
*/
abstract fun onViewCreated(savedInstanceState: Bundle?)
/**
* 创建观察者
*/
open fun createObserver(){}
/**
* 初始化数据
*/
open fun initData() {
}
/**
* 初始化布局
*/
protected open fun initLayout() {
mViewModel = createViewModel()
if (!isUserDb) {
setContentView(getLayoutId())
} else {
initDataBind()
}
initSoftKeyboard()
}
/**
* 如果当前的 Activity(singleTop 启动模式) 被复用时会回调
*/
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
// 设置为当前的 Intent,避免 Activity 被杀死后重启 Intent 还是最原先的那个
setIntent(intent)
}
fun setUserDataBinding(isUserDb: Boolean) {
this.isUserDb = isUserDb
}
/**
* 供子类BaseVmDbActivity 初始化Databinding操作
*/
open fun initDataBind() {}
/**
* 创建viewModel
*/
private fun createViewModel(): VM {
return ViewModelProvider(this).get(getVmClazz(this))
}
/**
* 初始化软键盘
*/
protected fun initSoftKeyboard() {
// 点击外部隐藏软键盘,提升用户体验
getContentView()?.setOnClickListener { v: View? -> hideSoftKeyboard(this) }
}
/**
* 和 setContentView 对应的方法
*/
fun getContentView(): ViewGroup? {
return findViewById(Window.ID_ANDROID_CONTENT)
}
fun startActivityForResult(
clazz: Class<out Activity?>?,
callback: OnActivityCallback
) {
startActivityForResult(Intent(this, clazz), null, callback)
}
fun startActivityForResult(intent: Intent?, callback: OnActivityCallback) {
startActivityForResult(intent, null, callback)
}
fun startActivityForResult(
intent: Intent?,
options: Bundle?,
callback: OnActivityCallback
) {
// 回调还没有结束,所以不能再次调用此方法,这个方法只适合一对一回调,其他需求请使用原生的方法实现
if (mActivityCallback == null) {
mActivityCallback = callback
// 随机生成请求码,这个请求码必须在 2 的 16 次幂以内,也就是 0 - 65535
mActivityRequestCode = Random().nextInt(Math.pow(2.0, 16.0).toInt())
startActivityForResult(intent, mActivityRequestCode, options)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (mActivityCallback != null && mActivityRequestCode == requestCode) {
mActivityCallback?.onActivityResult(resultCode, data)
mActivityCallback = null
} else{
super.onActivityResult(requestCode, resultCode, data)
}
}
override fun startActivityForResult(intent: Intent?, requestCode: Int, options: Bundle?) {
hideSoftKeyboard(this)
// 查看源码得知 startActivity 最终也会调用 startActivityForResult
super.startActivityForResult(intent, requestCode, options)
}
interface OnActivityCallback {
/**
* 结果回调
*
* @param resultCode 结果码
* @param data 数据
*/
fun onActivityResult(resultCode: Int, data: Intent?)
}
override fun finish() {
hideSoftKeyboard(this)
super.finish()
}
override fun onDestroy() {
removeCallbacks()
super.onDestroy()
}
}
4.BaseActivity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.SparseArray
import android.view.KeyEvent
import android.view.ViewGroup
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import com.weiaiyun.baselib.action.*
import com.weiaiyun.baselib.base.fragment.BaseFragment
import java.util.*
import kotlin.math.pow
/**
* author : Android 轮子哥
* github : https://github.com/getActivity/AndroidProject-Kotlin
* time : 2018/10/18
* desc : Activity 技术基类
*/
abstract class BaseActivity : AppCompatActivity(), ActivityAction,
ClickAction, HandlerAction, BundleAction, KeyboardAction {
companion object {
/** 错误结果码 */
const val RESULT_ERROR: Int = -2
}
/** Activity 回调集合 */
private val activityCallbacks: SparseArray<OnActivityCallback?> by lazy { SparseArray(1) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initActivity()
}
protected open fun initActivity() {
initLayout()
initView()
initData()
}
/**
* 获取布局 ID
*/
protected abstract fun getLayoutId(): Int
/**
* 初始化控件
*/
protected abstract fun initView()
/**
* 初始化数据
*/
protected abstract fun initData()
/**
* 初始化布局
*/
protected open fun initLayout() {
if (getLayoutId() > 0) {
setContentView(getLayoutId())
initSoftKeyboard()
}
}
/**
* 初始化软键盘
*/
protected open fun initSoftKeyboard() {
// 点击外部隐藏软键盘,提升用户体验
getContentView()?.setOnClickListener {
// 隐藏软键,避免内存泄漏
hideKeyboard(currentFocus)
}
}
override fun onDestroy() {
super.onDestroy()
removeCallbacks()
}
override fun finish() {
super.finish()
// 隐藏软键,避免内存泄漏
hideKeyboard(currentFocus)
}
/**
* 如果当前的 Activity(singleTop 启动模式) 被复用时会回调
*/
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
// 设置为当前的 Intent,避免 Activity 被杀死后重启 Intent 还是最原先的那个
setIntent(intent)
}
override fun getBundle(): Bundle? {
return intent.extras
}
/**
* 和 setContentView 对应的方法
*/
open fun getContentView(): ViewGroup? {
return findViewById(Window.ID_ANDROID_CONTENT)
}
override fun getContext(): Context {
return this
}
override fun startActivity(intent: Intent) {
return super<AppCompatActivity>.startActivity(intent)
}
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
val fragments: MutableList<Fragment?> = supportFragmentManager.fragments
for (fragment: Fragment? in fragments) {
// 这个 Fragment 必须是 BaseFragment 的子类,并且处于可见状态
if (fragment !is BaseFragment<*> || fragment.getLifecycle().currentState != Lifecycle.State.RESUMED) {
continue
}
// 将按键事件派发给 Fragment 进行处理
if (fragment.dispatchKeyEvent(event)) {
// 如果 Fragment 拦截了这个事件,那么就不交给 Activity 处理
return true
}
}
return super.dispatchKeyEvent(event)
}
@Suppress("deprecation")
override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) {
// 隐藏软键,避免内存泄漏
hideKeyboard(currentFocus)
// 查看源码得知 startActivity 最终也会调用 startActivityForResult
super.startActivityForResult(intent, requestCode, options)
}
/**
* startActivityForResult 方法优化
*/
open fun startActivityForResult(clazz: Class<out Activity>, callback: OnActivityCallback?) {
startActivityForResult(Intent(this, clazz), null, callback)
}
open fun startActivityForResult(intent: Intent, callback: OnActivityCallback?) {
startActivityForResult(intent, null, callback)
}
@Suppress("deprecation")
open fun startActivityForResult(intent: Intent, options: Bundle?, callback: OnActivityCallback?) {
// 请求码必须在 2 的 16 次方以内
val requestCode: Int = Random().nextInt(2.0.pow(16.0).toInt())
activityCallbacks.put(requestCode, callback)
startActivityForResult(intent, requestCode, options)
}
@Suppress("deprecation")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
var callback: OnActivityCallback?
if ((activityCallbacks.get(requestCode).also { callback = it }) != null) {
callback?.onActivityResult(resultCode, data)
activityCallbacks.remove(requestCode)
return
}
super.onActivityResult(requestCode, resultCode, data)
}
interface OnActivityCallback {
/**
* 结果回调
*
* @param resultCode 结果码
* @param data 数据
*/
fun onActivityResult(resultCode: Int, data: Intent?)
}
}
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.databinding.ViewDataBinding
import com.amap.api.location.AMapLocation
import com.amap.api.location.AMapLocationClient
import com.amap.api.location.AMapLocationClientOption
import com.amap.api.location.AMapLocationClientOption.AMapLocationMode
import com.amap.api.location.AMapLocationClientOption.AMapLocationProtocol
import com.gyf.immersionbar.ImmersionBar
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.weiaiyun.baselib.base.activity.WayBaseDbActivity
import com.weiaiyun.baselib.base.dialog.WayBaseDialog
import com.weiaiyun.baselib.base.viewmodel.WayBaseViewModel
import com.weiaiyun.commonlib.action.TitleBarAction
import com.weiaiyun.commonlib.ext.showToast
import com.weiaiyun.dialoglib.HintDialog
import com.weiaiyun.dialoglib.WaitDialog
import com.weiaiyun.module_main.R
import com.weiaiyun.widgetlib.bar.TitleBar
abstract class BaseDbActivity<VM : BaseViewModel, DB : ViewDataBinding> :
BaseDbActivity<VM, DB>(),
TitleBarAction {
private var mImmersionBar: ImmersionBar? = null
private var mDialog: WayBaseDialog? = null
private var mDialogTotal = 0
public var mLocation: AMapLocation? = null
private var mLocationListener:LocationListener?=null
private var mTitleBar: TitleBar? = null
private var locationClient: AMapLocationClient? = null
private var locationOption: AMapLocationClientOption? = null
override fun initLayout() {
super.initLayout()
if (titleBar != null) {
titleBar?.setOnTitleBarListener(this)
}
if (isStatusBarEnabled()) {
getStatusBarConfig()?.init()
if (titleBar != null) {
ImmersionBar.setTitleBar(this, titleBar)
} else {
if (setStatusBarLayout() != null) {
ImmersionBar.setTitleBar(this, setStatusBarLayout())
}
}
}
}
override fun onViewCreated(savedInstanceState: Bundle?) {
initLocation()
}
open fun setLocationListener(listener: LocationListener) {
mLocationListener = listener
}
private fun initLocation() {
//初始化client
try {
locationClient = AMapLocationClient(this.applicationContext)
locationOption = getDefaultOption()
//设置定位参数
locationClient?.setLocationOption(locationOption)
// 设置定位监听
locationClient?.setLocationListener {
Log.d("xxx","$it")
mLocation =it
mLocationListener?.onAMapLocationListener(it)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun getDefaultOption(): AMapLocationClientOption? {
val mOption = AMapLocationClientOption()
mOption.locationMode =
AMapLocationMode.Hight_Accuracy //可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
mOption.isGpsFirst = false //可选,设置是否gps优先,只在高精度模式下有效。默认关闭
mOption.httpTimeOut = 30000 //可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
mOption.interval = 2000 //可选,设置定位间隔。默认为2秒
mOption.isNeedAddress = true //可选,设置是否返回逆地理地址信息。默认是true
mOption.isOnceLocation = false //可选,设置是否单次定位。默认是false
mOption.isOnceLocationLatest =
false //可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
AMapLocationClientOption.setLocationProtocol(AMapLocationProtocol.HTTP) //可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
mOption.isSensorEnable = false //可选,设置是否使用传感器。默认是false
mOption.isWifiScan =
true //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差
mOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
mOption.geoLanguage =
AMapLocationClientOption.GeoLanguage.DEFAULT //可选,设置逆地理信息的语言,默认值为默认语言(根据所在地区选择语言)
return mOption
}
open fun startLocation(listener: LocationListener) {
this.mLocationListener = listener
XXPermissions.with(this)
//.permission(Permission.Group.STORAGE)
.permission(Permission.ACCESS_COARSE_LOCATION, Permission.ACCESS_FINE_LOCATION)
.request(object : OnPermissionCallback {
override fun onGranted(permissions: MutableList<String>?, all: Boolean) {
if (all) {
try {
// 设置定位参数
locationClient?.setLocationOption(locationOption)
// 启动定位
locationClient?.startLocation()
} catch (e: java.lang.Exception) {
showToast(HintDialog.ICON_ERROR, e.message)
//e.printStackTrace()
}
}
}
override fun onDenied(permissions: MutableList<String>?, never: Boolean) {
if (never) {
showToast(R.string.txt_common_permission_fail)
XXPermissions.startPermissionActivity(this@BaseDbActivity, permissions)
} else {
showToast(R.string.txt_common_permission_hint)
}
}
})
}
open fun stopLocation() {
try {
// 停止定位
locationClient?.stopLocation()
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
open fun isShowDialog(): Boolean {
return mDialog != null && mDialog?.isShowing!!
}
open fun showDialog(text: String?) {
mDialogTotal++
postDelayed({
if (mDialogTotal > 0 && !isFinishing) {
if (mDialog == null) {
mDialog = WaitDialog.Builder(this)
.setMessage(text)
.setCancelable(false)
.create()
}
mDialog?.let {
if (!it.isShowing) {
it.show()
}
}
}
}, 300)
}
open fun hideDialog() {
if (mDialogTotal > 0) {
mDialogTotal--
}
mDialog?.let {
if (mDialogTotal == 0 && it.isShowing && !isFinishing) {
it.dismiss()
}
}
}
override fun getBundle(): Bundle? {
return intent.extras
}
override fun setTitle(id: Int) {
title = getString(id)
}
override fun setTitle(title: CharSequence?) {
if (titleBar != null) {
titleBar?.title = title
}
}
override fun getTitleBar(): TitleBar? {
if (mTitleBar == null) {
mTitleBar = obtainTitleBar(getContentView())
}
return mTitleBar
}
override fun onLeftClick(v: View?) {
onBackPressed()
}
protected open fun setStatusBarLayout(): View? {
return null
}
protected open fun isStatusBarEnabled(): Boolean {
return true
}
protected open fun isStatusBarDarkFont(): Boolean {
return true
}
protected open fun createStatusBarConfig(): ImmersionBar {
return ImmersionBar.with(this)
.transparentStatusBar()
.statusBarDarkFont(isStatusBarDarkFont())
.navigationBarColor(R.color.white)
}
open fun getStatusBarConfig(): ImmersionBar? {
if (mImmersionBar == null) {
mImmersionBar = createStatusBarConfig()
}
return mImmersionBar
}
override fun startActivityForResult(intent: Intent?, requestCode: Int, options: Bundle?) {
super.startActivityForResult(intent, requestCode, options)
overridePendingTransition(R.anim.right_in_activity, R.anim.right_out_activity)
}
override fun finish() {
super.finish()
overridePendingTransition(R.anim.left_in_activity, R.anim.left_out_activity)
}
interface LocationListener {
fun onAMapLocationListener(location: AMapLocation) {
}
}
private fun destroyLocation() {
if (null != locationClient) {
locationClient?.onDestroy()
locationClient = null
locationOption = null
}
}
override fun onDestroy() {
if (isShowDialog()) {
hideDialog()
}
mDialog = null
destroyLocation()
super.onDestroy()
}
}
这个类有引用 高德地图的方法 如果有同学使用的话 把报错的AMAP 的方法删除就可以了
这样整个BaseActivy 基类就抽出来了 我们来看一下使用
class MainActivity : BaseDbActivity<BaseViewModel, ActivityMainBinding>() {
/*
所有的Activity 都继承与这个 BaseDbActivity
*/
override fun getLayoutId(): Int { return R.layout.activity_main } getLayoutId 绑定xml 视图
}
onViewCreated 视图创建完成后
mDatabind 来绑定XMl 的组件
大功告成