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.
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 do replace inside MyPrefenceActivity class after content was set for the container.
If you need too, 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