-1

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

enter image description here

menu updates

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")


}
Dr Mido
  • 2,414
  • 4
  • 32
  • 72
  • 3
    AppCompatActivity extends ComponentActivity, so just keep using AppCompatActivity. – ianhanniballake Jul 22 '22 at 02:48
  • 1
    And putting the layout in the superconstructor call is just an alternative to using `setContentView()`. If you choose to use the superconstructor way of doing it, you need to use your binding's `bind()` function instead of its `inflate()` function to bind to the already-inflated view. If you're using view binding, it's probably simpler to do it using `inflate` instead of passing the layout to the superconstructor. – Tenfour04 Jul 22 '22 at 03:21
  • @ianhanniballake If I keep using AppCompatActivity then How can I use the new menus implementation in fragment? `val menuHost: MenuHost = requireActivity()` it is related with extended of ComponentActivity ? – Dr Mido Jul 22 '22 at 11:34
  • 1
    You'd have to be using a very, very, very old version of AppCompat and Fragment to not have `FragmentActivity` and `AppCompatActivity` extend `ComponentActivity`. Please include the `dependencies` block from your `build.gradle` file if you'd like us to look at what versions you are using. – ianhanniballake Jul 22 '22 at 16:58
  • @ianhanniballake I edited my question and add dependencies block, please check – Dr Mido Jul 22 '22 at 21:23
  • 1
    Yep, your `FragmentActivity` definitely extends `ComponentActivity` and therefore has access to the `MenuHost` interface that `ComponentActivity` implements. – ianhanniballake Jul 22 '22 at 22:21
  • @ianhanniballake no all fragment extends the regular fragment class `androidx.fragment.app`, If I would update to last menus API, I implement `MenuProvider` but the only problem now is I can't declare this `val menuHost: MenuHost = requireActivity()` – Dr Mido Jul 22 '22 at 22:56

1 Answers1

3

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).

Gaming.ingrs
  • 271
  • 1
  • 13
  • @gaming-ingrs thank you, so the trick for this problem was in casting `as MenuHost` simple like that :D , so to complete the answer to this question Can you edit your answer and add how to use the `ComponentActivity(R.layout.activity_example)` in activity with viewBinding and `setSupportActionBar` and `supportFragmentManager` because I used this in my app – Dr Mido Jul 25 '22 at 17:31
  • I am not sure why do you want to use ComponentActivity directly as AppCompatActivity extends FragmentActivity which extends ComponentActivity? You should revert it to AppCompatActivity and if you have any error after that please let me know. – Gaming.ingrs Jul 26 '22 at 09:48
  • Updated my answer based on my comment above so please check it out. – Gaming.ingrs Jul 26 '22 at 09:58
  • @gaming-ingrs I am not sure if you understand my previous reply, but you can check this [answer](https://stackoverflow.com/a/71965674/7639296) to relate He used `class ExampleActivity : ComponentActivity(R.layout.activity_example)` in activity so I thought to use new menus API "Using the addMenuProvider() API directly in your Activity" it should extend `ComponentActivity` not `AppCompatActivity` – Dr Mido Jul 26 '22 at 16:34
  • Please check my update. – Gaming.ingrs Jul 27 '22 at 09:37