BaseActivity与BaseFragment中Toolbar冗余代码优化方案咨询
Great question! Duplicating toolbar logic across BaseActivity and BaseFragment is such a common pain point—having to update the same code in two places is a recipe for bugs and extra work. Let’s walk through two clean, maintainable solutions to consolidate all that toolbar boilerplate into a single spot:
1. Create a Standalone Toolbar Manager Class
The simplest approach is to extract all toolbar-related logic into a dedicated utility class. This class will handle view lookup, title setting, navigation icon setup, and any other toolbar operations you need. All your base components will then delegate to this manager instead of implementing the logic themselves.
Step 1: Build the ToolbarManager
class ToolbarManager(private val context: Context) { private var toolbar: Toolbar? = null // Initialize the toolbar by finding it in the root view fun init(rootView: View) { toolbar = rootView.findViewById(R.id.toolbar) // Add any universal toolbar setup here (e.g., default text styles) } // Set toolbar title fun setTitle(title: String) { toolbar?.title = title } // Configure navigation icon and click listener fun setNavigationIcon(iconRes: Int, onClick: () -> Unit) { toolbar?.setNavigationIcon(iconRes) toolbar?.setNavigationOnClickListener { onClick() } } // Inflate menu and handle menu interactions fun inflateMenu(menuRes: Int, menuCallback: (Menu) -> Unit) { toolbar?.inflateMenu(menuRes) toolbar?.menu?.let(menuCallback) } // Expose the toolbar instance for Activity-specific setup (like setting as ActionBar) fun getToolbar(): Toolbar? = toolbar }
Step 2: Integrate with BaseActivity
abstract class BaseActivity : AppCompatActivity() { protected val toolbarManager by lazy { ToolbarManager(this) } override fun setContentView(layoutResID: Int) { super.setContentView(layoutResID) // Initialize toolbar using the root content view toolbarManager.init(findViewById(android.R.id.content)) // Set toolbar as ActionBar (Activity-specific logic) toolbarManager.getToolbar()?.let { setSupportActionBar(it) supportActionBar?.setDisplayHomeAsUpEnabled(false) } } // Convenience method for subclasses to set title protected fun setToolbarTitle(title: String) { toolbarManager.setTitle(title) } }
Step 3: Integrate with BaseFragment
abstract class BaseFragment : Fragment() { protected val toolbarManager by lazy { ToolbarManager(requireContext()) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Initialize toolbar using the fragment's root view toolbarManager.init(view) } protected fun setToolbarTitle(title: String) { toolbarManager.setTitle(title) } }
Now all your toolbar logic lives in one place—any updates or fixes only need to be made to ToolbarManager, and both your activities and fragments will automatically get the changes.
2. Use Kotlin Delegation (For Cleaner Interface Implementation)
If you prefer a more interface-driven approach, you can define a ToolbarHandler interface and use Kotlin's class delegation to reuse the implementation across your base classes.
Step 1: Define the ToolbarHandler Interface
interface ToolbarHandler { fun init(rootView: View) fun setTitle(title: String) fun setNavigationIcon(iconRes: Int, onClick: () -> Unit) fun getToolbar(): Toolbar? }
Step 2: Implement the Default Handler
class DefaultToolbarHandler(private val context: Context) : ToolbarHandler { private var toolbar: Toolbar? = null override fun init(rootView: View) { toolbar = rootView.findViewById(R.id.toolbar) } override fun setTitle(title: String) { toolbar?.title = title } override fun setNavigationIcon(iconRes: Int, onClick: () -> Unit) { toolbar?.setNavigationIcon(iconRes) toolbar?.setNavigationOnClickListener { onClick() } } override fun getToolbar(): Toolbar? = toolbar }
Step 3: Delegate in Base Classes
For BaseActivity:
abstract class BaseActivity : AppCompatActivity(), ToolbarHandler { private val toolbarHandler by lazy { DefaultToolbarHandler(this) } override fun init(rootView: View) = toolbarHandler.init(rootView) override fun setTitle(title: String) = toolbarHandler.setTitle(title) override fun setNavigationIcon(iconRes: Int, onClick: () -> Unit) = toolbarHandler.setNavigationIcon(iconRes, onClick) override fun getToolbar(): Toolbar? = toolbarHandler.getToolbar() override fun setContentView(layoutResID: Int) { super.setContentView(layoutResID) init(findViewById(android.R.id.content)) getToolbar()?.let { setSupportActionBar(it) supportActionBar?.setDisplayHomeAsUpEnabled(false) } } }
For BaseFragment:
abstract class BaseFragment : Fragment(), ToolbarHandler { private val toolbarHandler by lazy { DefaultToolbarHandler(requireContext()) } override fun init(rootView: View) = toolbarHandler.init(rootView) override fun setTitle(title: String) = toolbarHandler.setTitle(title) override fun setNavigationIcon(iconRes: Int, onClick: () -> Unit) = toolbarHandler.setNavigationIcon(iconRes, onClick) override fun getToolbar(): Toolbar? = toolbarHandler.getToolbar() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) init(view) } }
This approach keeps your base classes clean and adheres to the interface segregation principle—you can even create different ToolbarHandler implementations if you need specialized behavior for certain screens.
Bonus Tips
- Make sure all your layouts use the same ID for the toolbar (e.g.,
R.id.toolbar) so the manager can reliably find it. - Add a flag in your base classes (like
shouldShowToolbar()) to skip initialization for screens that don't need a toolbar. - Keep Activity-specific logic (like setting the toolbar as an ActionBar) confined to
BaseActivity—fragments shouldn't modify the ActionBar directly.
内容的提问来源于stack exchange,提问作者Nagesh Jatagond

