前言
其实写BaseActivity
的时候,都需要结合不同的App
的需求以及应用架构来实现的,没有固定的实现方式。所以这里结合前面几篇文章来写一个BaseActivity
思路
结合前面的文章说的,BaseActivity
应该有下面这些内容
-
IProgressDialog
接口的实现,实现加载框动画 -
FragmentManager
方便操作Fragment
使用 -
CompositeDisposable
网络绑定和解绑在BaseActivity
的生命周期里面统一处理 -
Realm
和RealmAsyncTask
Realm
的实例和异步处理通知监听事件结合BaseActivity
的生命周期处理 -
ToolBar
统一处理应用的ToolBar
-
initView
和initListener
两个模板方法
ProgressDialog
应用中往往少不了加载动画,所以BaseActivity
也应该写一个公共的显示和隐藏加载框的方法,结合前文的IProgressDialog
接口。由于Android
的ProgressDialog
注解过时,Google
不推荐使用,那么这里就通过AlertDialog+ProgressBar
简单实现下面的效果
我们都知道AlertDialog
是有一个底色背景的,所以这里先写一个Style
让底色背景透明
<style name="ProgressDialog" parent="Theme.AppCompat.Dialog">
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
接下来就是这个弹框的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/progress_shape"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
android:id="@+id/iv_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp" />
<TextView
android:id="@+id/tv_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="加载中..."
android:textColor="@android:color/white"
android:textSize="16sp" />
</LinearLayout>
然后就是创建AlertDialog
设置布局
object AlertDialogUtils {
private var mAlertDialog:AlertDialog? = null
@SuppressLint("InflateParams")
fun showProgressDialog(context: Context,tip:String = ""){
if(mAlertDialog==null)
mAlertDialog = AlertDialog.Builder(context,R.style.ProgressDialog).create()
val loadView = context.layoutInflater.inflate(R.layout.alert_progress,null)
mAlertDialog!!.setView(loadView,0,0,0,0)
mAlertDialog!!.setCanceledOnTouchOutside(false)
mAlertDialog!!.show()
if(TextUtils.isEmpty(tip).not())
loadView.find<TextView>(R.id.tv_tip).text = tip
}
fun dismiss(){
if(mAlertDialog!=null&&mAlertDialog!!.isShowing)
mAlertDialog?.dismiss()
}
}
把前面的Style
在创建AlertDialog.Builder()
传入即可让底色背景透明,然后通过AlertDialog
的setView()
方法就可以自定义布局了。
FragmentManager
val fm: FragmentManager by lazy(LazyThreadSafetyMode.NONE) { supportFragmentManager }
定义一个FragmentManager
方便操作Fragment
的时候使用
CompositeDisposable
对应Rx1.x
版本的CompositeSubscription
,将请求接口统一绑定起来
val sub = CompositeSubscription()
然后在onDestroy()
进行统一的解绑
override fun onDestroy() {
sub.clear()
super.onDestroy()
}
Realm
结合前文封装的RealmHelper
帮助类,实现Realm
的实例并且定义一个RealmAsyncTask
val mRealm = RealmHelper.getRealmInstance(AppRealmMigrateImpl())
val mRealmAsyncList = mutableListOf<RealmAsyncTask>()
然后在onStop
里面进行清除
override fun onStop() {
mRealmAsyncList.forEach {
if(!it.isCancelled) it.cancel()
}
mRealmAsyncList.clear()
super.onStop()
}
ToolBar
首先会在BaseActivity
定义一个默认的布局act_single_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize" />
<include layout="@layout/toolbar_layout" />
</FrameLayout>
其中content
是用来放置内容的区域,然后toolbar_layout.xml
是ToolBar
的布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:elevation="0dp">
<android.support.v7.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:foreground="@android:color/transparent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Dark"
app:contentInsetStart="5dp">
<FrameLayout
android:id="@+id/custom_view"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
提供一个方法供外部实现ToolBar
样式,默认是TitleFragment
open fun toolbarCustomView(): Fragment? = TitleFragment()
TitleFragment
就是一个简单的头部样式,如图
class TitleFragment : BaseFragment(){
var onBackListener:BackClickListener? = null
override fun layoutResID()= R.layout.toolbar_title_layout
override fun initView(view: View) {
super.initView(view)
tvTitle.text = activity.title
}
override fun initListener() {
super.initListener()
ivBack.onClick {
onBackListener?.onBack(ivBack)
}
}
fun setTitle(title: CharSequence?) {
tvTitle?.text = title
}
interface BackClickListener{
fun onBack(view:View)
}
}
最后处理返回键的回调方法
private fun configToolBar(){
supportActionBar?.setDisplayShowTitleEnabled(false)
toolbarCustomView()?.apply{
mToolBarLayout = this
fm.beginTransaction().replace(R.id.custom_view, this).commitAllowingStateLoss()
(this as? TitleFragment)?.apply {
this.onBackListener = object:TitleFragment.BackClickListener{
override fun onBack(view: View) {
onBackClick(view)
}
}
}
}
}
BaseActivity
通过上面的说明,最终BaseActivity
如下
abstract class BaseActivity:AppCompatActivity(), IProgressDialog {
val fm: FragmentManager by lazy(LazyThreadSafetyMode.NONE) { supportFragmentManager }
val sub = CompositeDisposable()
val mRealm = RealmHelper.getRealmInstance(AppRealmMigrateImpl())
val mRealmAsyncList = mutableListOf<RealmAsyncTask>()
private val mToolBar by lazy { findOptional<Toolbar>(R.id.tool_bar) }
private var mToolBarLayout:Fragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val layoutResID = layoutResID()
if(layoutResID>0){
setContentView(layoutResID)
}
val layoutView = layoutView()
if(layoutView!=null){
setContentView(layoutView)
}
if(mToolBar!=null){
setSupportActionBar(mToolBar)
configToolBar()
}
if (!isFinishing) {
initView()
}
if (!isFinishing) {
initListener()
}
}
protected open fun initView() {
}
protected open fun initListener() {
}
@LayoutRes open fun layoutResID():Int = R.layout.act_single_fragment
open fun layoutView(): View? = null
open fun toolbarCustomView(): Fragment? = TitleFragment()
open fun onBackClick(v: View?) = finish()
private fun configToolBar(){
supportActionBar?.setDisplayShowTitleEnabled(false)
toolbarCustomView()?.apply{
mToolBarLayout = this
fm.beginTransaction().replace(R.id.custom_view, this).commitAllowingStateLoss()
(this as? TitleFragment)?.apply {
this.onBackListener = object:TitleFragment.BackClickListener{
override fun onBack(view: View) {
onBackClick(view)
}
}
}
}
}
override fun showLoading() {
AlertDialogUtils.showProgressDialog(this)
}
override fun dismissLoading() {
AlertDialogUtils.dismiss()
}
override fun updateNextPage(haveNext: Boolean) {
}
override fun setTitle(title: CharSequence?) {
super.setTitle(title)
}
override fun setTitle(titleId: Int) {
title = getString(titleId)
}
override fun onStop() {
mRealmAsyncList.forEach {
if(!it.isCancelled) it.cancel()
}
mRealmAsyncList.clear()
super.onStop()
}
override fun onDestroy() {
sub.clear()
super.onDestroy()
}
}