当前位置: 首页 > article >正文

【Android】创建基类BaseActivity和BaseFragment

目的

在 Android 开发中,创建基类的 Activity 和 Fragment 主要是为了提高代码的复用性、可维护性和一致性。通过定义基类,可以将多个 Activity 和 Fragment 中共享的功能和行为提取出来,避免重复代码,从而简化开发过程。

项目需求

一个项目里面是Java代码编写,然后现在引入Kotlin 进行开发,但是里面的原来的代码还是尽量不要动。

需求实现

现在有两种实现UI的布局,一种是使用ViewBinding的,一种是不使用的。
需要在基类里面进行处理。

项目代码
abstract class BaseActivity<VB : ViewBinding, VM : ViewModel> : AppCompatActivity() {

    protected var binding: VB? = null
    protected var viewModel: VM? = null

    private val activityList = arrayListOf<Activity>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        MyApplication.activityTasks.add(this)

        binding = getMyViewBinding()
        if (binding != null) {
            setContentView(binding!!.root)
        } else {
            setContentView(getContentViewId())
        }
        viewModel = getMyViewModel()


        val toolbar = findViewById<Toolbar>(R.id.toolbar)
        toolbar?.let {
            setSupportActionBar(it)
            supportActionBar?.setDisplayShowTitleEnabled(false)
            supportActionBar?.setDisplayHomeAsUpEnabled(true)
            initToolbar(ToolbarHelper(toolbar))
        }
        initData()
        activityList.add(this)
    }


    /**
     * 修复全屏页面状态下因为某些操作导致UI改变之后的全屏显示失效问题
     */
    override fun onWindowFocusChanged(hasFocus: Boolean) {
        val decorView = window.decorView
        decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                or View.SYSTEM_UI_FLAG_FULLSCREEN
                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
        super.onWindowFocusChanged(hasFocus)
    }

    override fun onDestroy() {
        MyApplication.activityTasks.remove(this)
        activityList.remove(this)
        super.onDestroy()
        binding = null
    }
    
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId == android.R.id.home) {
            finish()
        }
        return super.onOptionsItemSelected(item)
    }

    //跳转到指定activity
    open fun startActivity(cls: Class<out Activity?>?) {
        startActivity(Intent(this, cls))
    }

    open fun clearAllActivity() {
        for (activity in activityList) {
            activity.finish()
        }
        activityList.clear()
    }


    /**
     * Binding布局,使用ViewBinding的话要重写这个方法
     */
    protected open fun getMyViewBinding(): VB? {
        return null
    }

    /**
     * 普通布局,不使用ViewBinding的话要重写这个方法
     */
    protected open fun getContentViewId(): Int {
        return 0
    }

    /**
     * 默认返回 null,可以让子类选择是否使用 ViewModel
     */
    protected open fun getMyViewModel(): VM? {
        return null
    }

    /**
     * 初始化数据,子类必须实现这个抽象方法
     */
    protected abstract fun initData()

    /**
     * 使用ActionBar要重写这个方法
     */
    protected open fun initToolbar(toolbarHelper: ToolbarHelper) {}


    /**
     * 添加或切换Fragment的方法
     * 这个是可以添加和切换,用于多个Fragment管理的
     */
    fun addOrReplaceFragment(containerId: Int, fragment: Fragment) {
        // 获取FragmentManager
        val transaction = supportFragmentManager.beginTransaction()
        // 检查该Fragment是否已经存在
        val existing = supportFragmentManager.findFragmentByTag(fragment::class.java.simpleName)

        if (existing == null) {
            // 如果Fragment不存在,则添加
            transaction.replace(containerId, fragment, fragment::class.java.simpleName)
            //fragmentTransaction.addToBackStack(fragment::class.java.simpleName) // 添加到回退栈
        } else {
            // 如果Fragment已经存在,则切换到该Fragment
            transaction.show(existing)
            supportFragmentManager.fragments.forEach { frag ->
                if (frag != existing) {
                    transaction.hide(frag) // 隐藏其他Fragment
                }
            }
        }
        // 提交事务
        transaction.commit()

    }

这样一个可以满足大多数需求的基类就好了,如果是一个不使用ViewBinding的子类的话,直接就可以这样写

public class ConnectionActivity extends BaseActivity {

    @Override
    protected int getContentViewId() {
        return R.layout.activity_coodinate_system;
    }

    @Override
    protected void initData() {

    }

    @Override
    protected void initToolbar(ToolbarHelper toolbarHelper) {
        toolbarHelper.setTitle(getString(R.string.connectSetting));
    }

但是要是使用ViewBinding的话,就这样写

public class SysSettingActivity extends BaseActivity<ActivitySysSettingBinding, SystemViewModel> {

   @Nullable
    @Override
    protected ActivitySysSettingBinding getMyViewBinding() {
        return ActivitySysSettingBinding.inflate(getLayoutInflater());
    }

    @Nullable
    @Override
    protected SystemViewModel getMyViewModel() {
        return new ViewModelProvider(this).get(SystemViewModel.class);
    }

    @Override
    protected void initToolbar(@NonNull ToolbarHelper toolbarHelper) {
        toolbarHelper.setTitle(getString(R.string.sys_setting));
    }

    @Override
    protected void initData() {

    }
}

注意:要是使用Kotlin写子类,但是又不使用ViewBinding的话,子类需要这样写

class WelcomeActivity : BaseActivity<Nothing, Nothing>(){

   override fun getContentViewId(): Int {
        return R.layout.activity_welcome
    }

    override fun initData() {

    }
}

同样的,基类的BaseFragment写法也是很相似的

abstract class BaseFragment<VB : ViewBinding, VM : ViewModel> : Fragment() {

    protected var binding: VB? = null
    protected var viewModel: VM? = null

    private var rootView: View? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        getOnCreateView()
        binding = getMyViewBinding()
        if (binding != null) {
            return binding!!.root
        } else {
            rootView = inflater.inflate(getMYLayoutId(), null)
            return rootView
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = getMyViewModel()
        initData()
    }

    /**
     * 只给有需要的使用,在 onCreateView 里面使用的
     */
    protected open fun getOnCreateView() {}

    /**
     * Binding布局,使用ViewBinding的话要重写这个方法
     */
    protected open fun getMyViewBinding(): VB? {
        return null
    }

    /**
     * 普通布局,不使用ViewBinding的话要重写这个方法
     */
    protected open fun getMYLayoutId(): Int {
        return 0
    }

    /**
     * 在普通布局时获取View
     */
    protected open fun getMyView(): View? {
        return rootView;
    }

    /**
     * 默认返回 null,可以让子类选择是否使用 ViewModel
     */
    protected open fun getMyViewModel(): VM? {
        return null
    }

    /**
     * 初始化数据
     */
    protected abstract fun initData()

    //跳转到指定activity
    open fun startActivity(cls: Class<out Activity?>?) {
        startActivity(Intent(context, cls))
    }
}

后面我们也可以根据自己的项目需求,在基类里面加入一些其他的功能代码,比如权限判定啊、加载框等等。


http://www.kler.cn/a/514882.html

相关文章:

  • 【若依】添加数据字典
  • 【时时三省】(C语言基础)文件的顺序读写
  • C语言程序设计十大排序—选择排序
  • 用JAVA写算法之输入输出篇
  • 使用tritonserver完成clip-vit-large-patch14图像特征提取模型的工程化。
  • StarRocks强大的实时数据分析
  • Spring注解篇:@RestController详解
  • AI大模型-提示工程学习笔记11-思维树
  • 【线性代数】列主元法求矩阵的逆
  • 云原生架构下的AI智能编排:ScriptEcho赋能前端开发
  • 2025_1_22_进程替换
  • Simula语言的云计算
  • C语言进阶习题【1】指针和数组(4)——指针笔试题3
  • RabbitMQ的消息可靠性保证
  • 网络(一)
  • C语言程序环境与预处理—从源文件到执行程序,这里面有怎么的工序?绝对0基础!
  • 【 MySQL 学习4】排序
  • Kafka 源码分析(一) 日志段
  • java中的String类、StringBuffer类、StringBuilder类的详细讲解(包含相互之间的比较)
  • BUG解决:安装问题transformer_engine+pytorch
  • 基于springboot+vue的高校社团管理系统的设计与实现
  • docker ubuntu:20.04构建c++ grpc环境
  • es的date类型字段按照原生格式进行分组聚合
  • QILSTE H13-320B2W高亮白光LED灯珠 发光二极管LED
  • 如何使用CRM数据分析和洞察来支持业务决策和市场营销?
  • 开源鸿蒙开发者社区记录