Adam Lee
Adam Lee

Reputation: 576

Android Fragment Error: No view found for id 0x7f08009e (com.example.myapplication:id/preferenceFragment) for fragment

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

Answers (3)

Oleg Gryb
Oleg Gryb

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

mostafa3dmax
mostafa3dmax

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

tynn
tynn

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

Related Questions