I was following the instructions on docs to use Android Jetpack preference library, but I am getting the following error
java.lang.RuntimeException: Unable to start activity ComponentInfo{ ... activity.SettingsActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f090111 (... :id/settings_container) for fragment SettingsFragment
...
Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f090111 (... :id/settings_container) for fragment SettingsFragment
as I think this usually happens when there is no container to mount the fragment, but in my case there is a container(settings_container).
My code looks like below
SettingsActivity
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings_container, SettingsFragment())
.commit()
}
}
SettingsFragment
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.pref_main, rootKey)
}
activity_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/settings_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.SettingsActivity">
</FrameLayout>
pref_main.xml (shortened)
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
app:key="data_sync_category"
app:title="#string/pref_data_sync_category">
<SwitchPreferenceCompat app:key="data_sync_status"
app:title="#string/pref_data_sync_status_title"
app:summary="#string/pref_data_sync_status_summary"
android:defaultValue="true"
/>
<ListPreference app:key="what_data_sync"
app:title="#string/pref_sync_frequency_title"
app:summary="#string/pref_sync_frequency_summary"
android:entries="#array/pref_sync_frequency_titles"
android:entryValues="#array/pref_sync_frequency_values"
android:defaultValue="30"
android:negativeButtonText="#null"
android:positiveButtonText="#null"
/>
</PreferenceCategory>
</androidx.preference.PreferenceScreen>
As you can see code is almost identical to the code in documentation.
I tried invalidate and restart, did not work.
Please help
No, there isn't a container.
You never use setContentView() in your Activity, so that layout doesn't exist. tools:context is an IDE-only feature.
You need to use
setContentView(R.layout.activity_settings)
right after calling super.onCreate(savedInstanceState).
java.lang.RuntimeException: Unable to start activity ComponentInfo{ ... activity.SettingsActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f090111 (... :id/settings_container) for fragment SettingsFragment
...
Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f090111 (... :id/settings_container) for fragment SettingsFragment
according your code you did't set layout for activity
you are giving reference of settings_container but its not found in activity layout because they dont have layout file so you need to setContentView for your activity
setContentView(R.layout.name)
public void setContentView (int layoutResID)
Set the activity content from a layout resource. The resource will be inflated, adding all top-level views to the activity.
Replace your activity kt file with
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings_container, SettingsFragment())
.commit()
}
}
Related
I have an application composed of one activity and several fragments, as recommanded by Google. Other details here. I would like to keep a menu still and to switch my fragments in the container in the center.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:someProperties="propertiesValues">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:someProperties="propertiesValues" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="#navigation/navigation_map"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:someProperties="propertiesValues" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
println("Activity creation")
val binding = ActivityMainBinding.inflate(layoutInflater)
println("Activity creation part 2")
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
User.initSharedPref(this)
}
Fragment
private lateinit var mylist: MutableList<String>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
println("Fragment creation")
mylist = User.loadScenarioList()
}
User
object User
{
private lateinit var sharedPref : SharedPreferences
fun initSharedPref(context: Context){
sharedPref = context.getSharedPreferences("JeuDePisteKtPreferenceFileKey",Context.MODE_PRIVATE)
}
fun loadList(): MutableList<String>> {
val json = sharedPref.getString(KEY_LIST, "") ?: ""
if (json == "") return mutableListOf()
return Json.decodeFromString(json)
}
}
Problem encountered
When i start the activity, it initialize a variable sharedPref as shown in code.
But when in fragment onCreate i use this variable (mylist = User.loadScenarioList()), the binding line in activity fail with Binary XML file line #31: Error inflating class androidx.fragment.app.FragmentContainerView as shown in logcat below
Logcat & error
Here is the full logcat, we can see the the second sout is missing, but with no error thrown at this point.
The problem here came from the order of creation call
We can see it in the corrected code logcat
The activity onCreate is called first, but the first inflate call the fragment OnCreate, before resuming the activity OnCreate.
So every variable used in the fragment onCreate should be initialized before inflate call
We have a PreferenceFragmentCompat, and with a tap on a preference, we want to switch from the current PreferenceFragmentCompat to a new PreferenceFragmentCompat. (To have certain settings on a new screen).
However, regardless of what we have tried, we keep running into the following error:
Fragment declared target fragment that does not belong to this
FragmentManager
MainActivity.kt
class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback, PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_preferences
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean {
val args = pref.extras
val fragment = supportFragmentManager.fragmentFactory.instantiate(
classLoader,
pref.fragment)
fragment.arguments = args
fragment.setTargetFragment(caller, 0)
// Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment, fragment)
.addToBackStack(null)
.commit()
return true
}
}
PreferenceFragement1.kt
class PreferencesFragment1 : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences1, rootKey)
}
}
PreferenceFragment2.kt
class PreferenceFragment2 : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences2, rootKey)
}
}
Preferences1.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen 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="match_parent">
<PreferenceCategory
android:title="Category"
app:iconSpaceReserved="false">
<Preference
app:key="pref2"
app:iconSpaceReserved="false"
android:title="Open"
app:fragment="com.testapp.ui.preferences.Preference2"/>
</PreferenceCategory>
</PreferenceScreen>
Preferences2.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen 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="match_parent">
</PreferenceScreen>
The stacktrace shows the following:
java.lang.IllegalStateException: Fragment Preference2{496ebb9} (1b91d8df-58c0-485a-96f9-d392fcef528b) id=0x7f09008d} declared target fragment Preference1{b6337c1} (97aa1b0e-d5fa-4995-b0ba-e89ad0ea5ce0) id=0x7f09008d} that does not belong to this FragmentManager!
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1148)
at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1255)
at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1138)
at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:136)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1989)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:491)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
We are using androidx.preference:preference-ktx:1.1.1.
Can some give us a concise explanation what exactly is causing this problem, and how we can solve it?
We already looked at the following (related) posts, without any success:
Fragment declared target fragment that does not belong to this FragmentManager
How to open a new PreferenceFragment from current one, using the new Android-X API?
https://developer.android.com/guide/topics/ui/settings/organize-your-settings
When you create a Fragment via the navigation graph, it is a child fragment of the NavHostFragment. It specifically is not the activity's supportFragmentManager. This is why the target fragment isn't found - you're using the wrong FragmentManager.
However, you should not use app:fragment or onPreferenceStartFragment when you're using Navigation. Instead, your PreferencesFragment1 should set a click listener on your Preference and have it call navigate() directly.
class PreferencesFragment1 : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences1, rootKey)
findPreference<Preference>("pref2")?.setOnPreferenceClickListener {
// Use whatever ID that is associated with
// PreferenceFragment2 in your navigation graph
findNavController().navigate(R.id.pref2)
}
}
}
Preferences1.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen 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="match_parent">
<PreferenceCategory
android:title="Category"
app:iconSpaceReserved="false">
<Preference
app:key="pref2"
app:iconSpaceReserved="false"
android:title="Open"/>
</PreferenceCategory>
</PreferenceScreen>
I have a fragment which is a child of BottomsheetDialogFragment, inside that fragment I have a google map. At first when I open this fragment using arch components NavController it works fine, than if I close this fragment and than try to open it again it crashes.
This is the error log
Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #71 in com.example.com:layout/product_location_fragment: Error inflating class fragment
Caused by: java.lang.IllegalArgumentException: Binary XML file line #71: Duplicate id 0xffffffff, tag mapFragment, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.SupportMapFragment
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:116)
Here is the fragment itself
class ProductLocationFargment : BottomSheetDialogFragment, {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.product_location_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//this also always returns null
val frag = childFragmentManager.findFragmentById(R.id.mapFragment) as? SupportMapFragment
}
}
and layout xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:tag="mapFragment"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="#id/leftGuideView"
app:layout_constraintEnd_toEndOf="#id/rightGuideView" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is how I'm starting that fragment from another fragment
button.setOnClickListener {
val direction = AnotherFragmentDirections.actionAnotherFragmentToProductLocationFargment()
navController.navigate(direction)
}
Try adding the mapFragment to a FrameLayout manually instead of with <fragment tag, but only if if(savedInstanceState == null) { otherwise get it by tag
I followed this guide https://developer.android.com/guide/topics/ui/settings to create my preferences page, but when I navigate to my settings page, I get an empty row in my settings fragment just before the preferencescreen items, like in the picture https://imgur.com/a/KbVrIHr
This is my code;
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings_container, SettingsFragment())
.commit()
}
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences)
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/settings_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.actionbar.settings.SettingsActivity">
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="Theme">
<SwitchPreferenceCompat
app:iconSpaceReserved="false"
app:key="switch"
app:summary="Enable dark theme."
app:title="Dark Theme" />
</PreferenceCategory>
</androidx.preference.PreferenceScreen>
I'm creating an application where it uses the Navigation Architecture, but my navigation has no default host, and can be set based on the selected destination by the user.
So this is the setup of my NavHostFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var finalHost: NavHostFragment? = null
when (bundle) {
REQUEST_FIRST -> {
finalHost = NavHostFragment.create(R.navigation.navigation_first)
}
REQUEST_SECOND -> {
finalHost = NavHostFragment.create(R.navigation.navigation_second)
}
REQUEST_THIRD -> {
finalHost = NavHostFragment.create(R.navigation.navigation_third)
}
}
supportFragmentManager.beginTransaction()
.replace(R.id.fragmentMain, finalHost!!)
.setPrimaryNavigationFragment(finalHost)
.commit()
}
and this is my main activity layout.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/black">
<!-- some stuff -->
<fragment
android:id="#+id/fragmentMain"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
So, my MainActivity is loading correctly but when I start to rotate the screen of the device, It encounters some errors.
java.lang.RuntimeException: Unable to start activity ComponentInfo: android.view.InflateException: Binary XML file line #10: Binary XML file line #10: Error inflating class fragment
the said error is pointing on my setContentView(R.layout.activity_main) and the NavHostFragment <fragment> in layout.
any help is appreciated, Thanks!