According to this question, I tried to update my deprecated menus codes like , setHasOptionsMenu
onCreateOptionsMenu
and onOptionsItemSelected
in my fragments and all app, but I should replace AppCompatActivity
to ComponentActivity(R.layout.activity_example)
but after doing this I see there's some problem, first I confused about how to use ViewBinding with it when I should remove setContentView(binding.root)
from activity second the method setSupportActionBar(binding.appBarMain.toolbar)
is not found, and I couldn't use the navigation components like supportFragmentManager
and setupActionBarWithNavController
the third thing I couldn't"t declare this
val menuHost: MenuHost = requireActivity()
in onCreateView
in fragment I see it's Required:
MenuHost
but Found:
FragmentActivity
here's my MainActivity code before edits
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMainBinding
private lateinit var navController: NavController
private lateinit var postViewModel: PostViewModel
private lateinit var navGraph: NavGraph
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
postViewModel = ViewModelProvider(this)[PostViewModel::class.java]
postViewModel.getCurrentDestination()
setSupportActionBar(binding.appBarMain.toolbar)
val drawerLayout: DrawerLayout = binding.drawerLayout
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
if (navHostFragment != null) {
navController = navHostFragment.navController
}
navGraph = navController.navInflater.inflate(R.navigation.mobile_navigation)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_accessory,
R.id.nav_arcade, R.id.nav_fashion,
R.id.nav_food, R.id.nav_heath,
R.id.nav_lifestyle, R.id.nav_sports, R.id.nav_favorites, R.id.about
), drawerLayout
)
// setupActionBarWithNavController(navController, appBarConfiguration)
// navView.setupWithNavController(navController)
setupActionBarWithNavController(this, navController, appBarConfiguration)
setupWithNavController(binding.navView, navController)
// determineAdvertisingInfo()
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
and this the implementation of menus in fragments
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
setHasOptionsMenu(true)
return binding.root
}
....................................................................................
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.main, menu)
super.onCreateOptionsMenu(menu, inflater)
val searchManager =
requireContext().getSystemService(Context.SEARCH_SERVICE) as SearchManager
val searchView = menu.findItem(R.id.app_bar_search).actionView as SearchView
searchView.setSearchableInfo(searchManager.getSearchableInfo(requireActivity().componentName))
searchView.queryHint = resources.getString(R.string.searchForPosts)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(keyword: String): Boolean {
if (keyword.isEmpty()) {
Snackbar.make(
requireView(),
"please enter keyword to search",
Snackbar.LENGTH_SHORT
).show()
}
// itemArrayList.clear()
if (Utils.hasInternetConnection(requireContext())) {
postViewModel.getItemsBySearch(keyword)
postViewModel.searchedPostsResponse.observe(viewLifecycleOwner) { response ->
when (response) {
is NetworkResult.Success -> {
hideShimmerEffect()
itemArrayList.clear()
binding.progressBar.visibility = View.GONE
response.data?.let {
itemArrayList.addAll(it.items)
}
adapter.notifyDataSetChanged()
}
is NetworkResult.Error -> {
hideShimmerEffect()
// loadDataFromCache()
Toast.makeText(
requireContext(),
response.toString(),
Toast.LENGTH_LONG
).show()
}
is NetworkResult.Loading -> {
if (postViewModel.recyclerViewLayout.value == "titleLayout" ||
postViewModel.recyclerViewLayout.value == "gridLayout"
) {
hideShimmerEffect()
} else {
showShimmerEffect()
}
}
}
}
} else {
postViewModel.getItemsBySearchInDB(keyword)
postViewModel.postsBySearchInDB.observe(viewLifecycleOwner) { items ->
if (items.isNotEmpty()) {
hideShimmerEffect()
binding.progressBar.visibility = View.GONE
itemArrayList.clear()
itemArrayList.addAll(items)
adapter.notifyDataSetChanged()
}
}
}
return false
}
override fun onQueryTextChange(newText: String): Boolean {
return false
}
})
searchView.setOnCloseListener {
if (Utils.hasInternetConnection(requireContext())) {
Log.d(TAG, "setOnCloseListener: called")
itemArrayList.clear()
requestApiData()
} else {
noInternetConnectionLayout()
}
false
}
postViewModel.searchError.observe(viewLifecycleOwner) { searchError ->
if (searchError) {
Toast.makeText(
requireContext(),
"There's no posts with this keyword", Toast.LENGTH_LONG
).show()
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.change_layout) {
changeAndSaveLayout()
return true
}
return super.onOptionsItemSelected(item)
}
build.gradle dependencies
dependencies {
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation ('com.google.android.material:material:1.6.1') {
exclude(group: 'androidx.recyclerview', module: 'recyclerview')
exclude(group: 'androidx.recyclerview', module: 'recyclerview-selection')
}
implementation "androidx.recyclerview:recyclerview:1.2.1"
// For control over item selection of both touch and mouse driven selection
implementation "androidx.recyclerview:recyclerview-selection:1.1.0"
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// //Moshi
// implementation("com.squareup.moshi:moshi:1.13.0")
// implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
// kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"
implementation 'com.github.bumptech.glide:glide:4.12.0'
implementation 'org.jsoup:jsoup:1.14.1'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'org.apache.commons:commons-lang3:3.8.1'
implementation 'org.ocpsoft.prettytime:prettytime:4.0.1.Final'
implementation "androidx.browser:browser:1.4.0"
implementation 'androidx.multidex:multidex:2.0.1'
configurations {
all*.exclude group: 'com.google.guava', module: 'listenablefuture'
}
//Room
implementation "androidx.room:room-runtime:2.4.2"
kapt "androidx.room:room-compiler:2.4.2"
implementation "androidx.room:room-ktx:2.4.2"
androidTestImplementation "androidx.room:room-testing:2.4.2"
//Dagger - Hilt
implementation 'com.google.dagger:hilt-android:2.42'
kapt 'com.google.dagger:hilt-android-compiler:2.42'
//SDP & SSP
implementation 'com.intuit.sdp:sdp-android:1.0.6'
implementation 'com.intuit.ssp:ssp-android:1.0.6'
// Shimmer
implementation 'com.facebook.shimmer:shimmer:0.5.0'
//firebase & analytics
implementation platform('com.google.firebase:firebase-bom:28.4.0')
implementation 'com.google.firebase:firebase-analytics'
//crashlytics
implementation 'com.google.firebase:firebase-crashlytics'
implementation 'com.google.firebase:firebase-analytics'
// DataStore
implementation 'androidx.datastore:datastore-preferences:1.0.0'
implementation("androidx.datastore:datastore-preferences-rxjava3:1.0.0")
//admob
implementation 'com.google.android.gms:play-services-ads:21.1.0'
implementation platform('com.google.firebase:firebase-bom:30.2.0')
implementation project(':nativetemplates')
implementation("androidx.ads:ads-identifier:1.0.0-alpha04")
// Used for the calls to addCallback() in the snippets on this page.
implementation("com.google.guava:guava:28.0-android")
implementation 'com.google.firebase:firebase-analytics'
implementation("androidx.activity:activity-ktx:1.5.0")
}
Simplest solution from top of my head (hopefully it will work for you):
val menuHost: MenuHost = requireActivity() as MenuHost
This example is for fragment but I guess you can easily apply it to activity:
First extend fragment with MenuProvider:
class SomeFragment : SomethingIfYouHave(), MenuProvider { /* Your code */ }
Now in onCreateView:
val menuHost: MenuHost = requireActivity() as MenuHost
menuHost.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
Later in code override onCreateMenu and onMenuItemSelected.
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.info_menu, menu)
}
override fun onMenuItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.something-> {
// Do something here
true
}
else -> false
}
}
AppCompatActivity extends FragmentActivity which extends ComponentActivity, why to use ComponentActivity directly?
Please revert it to:
class MainActivity : AppCompatActivity() { /* Your code here */ }
I think your only problem was in this line:
val menuHost: MenuHost = requireActivity() as MenuHost
------------------- UPDATE
*ComponentActivity has all you need for a Compose-only app. If you need AppCompat APIs, an AndroidView which works with AppCompat or MaterialComponents theme, or you need Fragments then use AppCompatActivity.
You are not using purely ComposeUI, so that is why you need AppCompat and not ComponentActivity.
If you want to use ComponentActivity without AppCompat you need to get rid off supportFragmentManager.
This would go out of the scope but please check ComposeUI Fragments if you want to switch on ComposeUI (I didn't write article).