Reputation: 576
I am trying to create a settings menu (PreferenceScreen) that opens when the user clicks on an item in the MainActivity's toolbar. However, when the user clicks on the "Settings" item in the MainActivity's toolbar, the following error appears:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 20257
java.lang.IllegalArgumentException: No view found for id 0x7f08009e (com.example.myapplication:id/preferenceFragment) for fragment MyPreferenceFragment{212e66e (2406d527-5781-4a6b-845c-e7ed6f2b1d9a) id=0x7f08009e}
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:875)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7045)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
Below is the code in MainActivity where I launch the Activity for the PreferenceScreen
:
// Launch the menus when the user clicks on one of the menu items
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle presses on the action bar menu items
when (item.itemId) {
R.id.settings -> { // User pressed "Settings" button
try {
val settingsFragment:Fragment = MyPreferenceFragment() // Create the Settings Fragment
val transaction:FragmentTransaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.preferenceFragment, settingsFragment)
transaction.addToBackStack(null)
transaction.commit()
}
catch (ex:Exception) {
println("Exception: " + ex.toString())
}
return true
}
R.id.about -> { // User pressed "About" button
println("ABOUT BUTTON CLICKED")
return true
}
R.id.share -> { // User pressed "Share" button
println("SHARE BUTTON PRESSED")
return true
}
}
return super.onOptionsItemSelected(item)
}
Below is my code for the Fragment (MyPreferenceFragment
):
package com.example.myapplication;
import android.os.Bundle;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SeekBarPreference;
import com.example.myapplication.R;
public class MyPreferenceFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
final SeekBarPreference fontSizeSeekBar = (SeekBarPreference) findPreference("font_size");
}
}
Below is my code for the Fragment Activity (MyPreferencesActivity.kt
):
package com.example.myapplication
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MyPreferencesActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pref)
}
}
Below is my code for AndroidManifest.xml
(where I have included the Preference
activity):
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MyPreferencesActivity"></activity>
</application>
</manifest>
Below is my XML code for my preferences page (preferences.xml)
:
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.preference.SeekBarPreference
android:key="font_size"
android:title="Font Size"
android:min="12"
android:max="32"
android:defaultValue="14" />
</androidx.preference.PreferenceScreen>
Below is the code for my fragment which contains the preferences page (activity_pref.xml
):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:id="@+id/preferenceFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.myapplication.MyPreferenceFragment" />
</FrameLayout>
My activity_main.xml
layout does not include preferences.xml
or activity_pref.xml
.
Note: I am looking for an answer that must be able to have a user click on an item in the MainActivity's toolbar and launch a preferences screen that contains a SeekBarPreference (which can be retrieved pro-grammatically i.e. final SeekBarPreference fontSizeSeekBar = (SeekBarPreference) findPreference("font_size");). Answers that launch a fragment but cannot pro-grammatically retrieve the SeekBarPreference will not be accepted.
Upvotes: 2
Views: 333
Reputation: 5249
You have two activities: MainActivity and MyPreferencesActivity. It's absolutely not clear from the published code where and how you launch the latter. You setContent in MyPreferencesActivity, but replacing fragment in MainActivity. Since container is not set through setContent in MainActivity, id/preferenceFragment can't be found and replaced.
You need to launch MyPrefenceActivity first, e.g. through creating and starting an intent, and then replace the view inside MyPrefenceActivity class after content was set for the container.
If you need to, you can also create a toolbar with menu, which is specific to your MyPreferencesActivity and process onOptionsItemSelected inside of this activity.
I've described the latter scenario in details here: add an actionbar for each fragment
Upvotes: 3
Reputation: 1017
You should use this code in the Activity that contains preferenceFragment
in it's layout file :
try {
val settingsFragment:Fragment = MyPreferenceFragment() // Create the Settings Fragment
val transaction:FragmentTransaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.preferenceFragment, settingsFragment)
transaction.addToBackStack(null)
transaction.commit()
}
catch (ex:Exception) {
println("Exception: " + ex.toString())
}
You get exception because you used transaction.replace(R.id.preferenceFragment, settingsFragment)
in the activity that dos not have preferenceFragment
in it's layout file!
So,you must start another activity when R.id.settings
button clicked that the activity contains preferenceFragment
in it's layout file .then use this code :
transaction.replace(R.id.preferenceFragment, settingsFragment)
so do this : package com.example.myapplication
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MyPreferencesActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pref)
val settingsFragment:Fragment = MyPreferenceFragment()
getSupportFragmentManager().beginTransaction()
.replace(R.id.preferenceFragment, settingsFragment)
.commit()
}
}
and change this R.id.settings
onclick to this:
R.id.settings -> { // User pressed "Settings" button
try {
val settingActivityIntent = Intent(this,
MyPreferencesActivity::class.java)
startActivity(settingActivityIntent)
}
catch (ex:Exception) {
println("Exception: " + ex.toString())
}
return true
}
Upvotes: 0
Reputation: 39843
If you replace a fragment with a transaction, you need to provide an id for the container. This container needs to be in the layout and will become the parent of the view of the fragment.
transaction.replace(R.id.preferenceFragment, settingsFragment)
The preferenceFragment
id is the id of the preference fragment in a different layout. If you want to add the MyPreferenceFragment
as a child to the main activity, you need to provide the container id instead of preferenceFragment
.
If you want to show the MyPreferencesActivity
instead, you only need to start this activity instead of a fragment transaction. The MyPreferenceFragment
is automatically added with the layout you provided.
startActivity(Intent(this, MyPreferencesActivity::class.java))
Upvotes: 0