16

I am developing app with minSdkVersion="11", that is app for tablets and Android 4.0 and newer. I have scrutinized internet on this topic, but have not found much.

To implement custom layout for previous versions of Android SDK we just have to create layout (say preference.xml) with ListView and its id equals to android.R.id.list and use setContentView method.

preference.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" > 
    <ListView android:id="@android:id/list"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent" /> 
</RelativeLayout>

In Android 3.0 things have changed and Preferences are implemented with use of fragments. That is how my preference_headers.xml file looks like:

<preference-headers
        xmlns:android="http://schemas.android.com/apk/res/android">

    <header android:fragment="com.example.MyPreferenceActivity$GeneralSettingsFragment" 
            android:title="General"
            android:summary="Common settings." />
    <header  
            android:title="Example.com" >
        <intent android:action="android.intent.action.VIEW"
                android:data="http://www.example.com" />
    </header> 

</preference-headers>

MyPreferenceActivity.java:

public class MyPreferenceActivity extends PreferenceActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.preference);
        // Add a button to the header list.
        if (hasHeaders()) {
            Button button = new Button(this); 
            button.setText("Log out");
            setListFooter(button);

        }

    }


    /**
     * Populate the activity with the top-level headers.
     */
    @Override
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.preference_headers, target);
    }

    public static class GeneralSettingsFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Load the preferences from an XML resource
            addPreferencesFromResource(R.xml.fragmented_preferences);

        }
    }
}

Now if I run MyPreferenceActivity I will see this error in LogCat:

> java.lang.IllegalArgumentException: No view found for id 0x10202be for
> fragment GeneralSettingsFragment{4077f8c0 #0 id=0x10202be}
> E/AndroidRuntime(17103): at
> android.app.FragmentManagerImpl.moveToState(FragmentManager.java:729)
> E/AndroidRuntime(17103): at
> android.app.FragmentManagerImpl.moveToState(FragmentManager.java:926)
> E/AndroidRuntime(17103): at
> android.app.FragmentManagerImpl.moveToState(FragmentManager.java:909)
> E/AndroidRuntime(17103): at
> android.app.FragmentManagerImpl.dispatchStart(FragmentManager.java:1584)
> E/AndroidRuntime(17103): at
> android.app.Activity.performStart(Activity.java:4377)
> E/AndroidRuntime(17103): at
> android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1724)
> E/AndroidRuntime(17103):  ... 11 more

I know what causes this problem. FragmentManager just cannot find a view to insert fragment GeneralSettingsFragment in. But I don't know how to solve it.

By the way, if I run the same app on Android 4.0, then I can see the first Preference Activity with headers. But if I click on General, app will crash and I will receive similar error in LogCat:

java.lang.IllegalArgumentException: No view found for id 0x10202cd for fragment GeneralSettingsFragment{4134b4e0 #0 id=0x10202cd}
E/AndroidRuntime(2170):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:789)
E/AndroidRuntime(2170):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:998)
E/AndroidRuntime(2170):     at android.app.BackStackRecord.run(BackStackRecord.java:622)
E/AndroidRuntime(2170):     at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1330)
E/AndroidRuntime(2170):     at android.app.Activity.performStart(Activity.java:4474)
E/AndroidRuntime(2170):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1928)
morphium
  • 676
  • 1
  • 6
  • 13
  • What are you trying to do? Why do you need a custom layout? – alexanderblom Oct 21 '11 at 15:55
  • I want to have more precise control over preference Activity. Besides, I want it to be compatible with newer versions of Android SDK as much as possible, that is I need to extend PreferenceActivity, but not implementing it myself from scratch. – morphium Oct 24 '11 at 02:25

3 Answers3

4

I had the same issue than you.

I tried a lot of stuff but here is my full code:

https://github.com/iRail/BeTrains-for-Android/blob/master/src/tof/cv/mpp/MyPreferenceActivity.java

The trick is to add the setContentView in the onBuildHeaders section, but NOT in the onCreate.

I also made some tests in fragment and not perfectly sure why this is working, but I promise you: I have a custom layout on tablet header section!

https://github.com/iRail/BeTrains-for-Android/blob/master/src/tof/cv/mpp/view/StockPreferenceFragment.java

Waza_Be
  • 39,545
  • 47
  • 176
  • 256
  • the link is broken, but I was able to find it: https://github.com/iRail/BeTrains-for-Android/blob/master/BeTrains/src/main/java/tof/cv/mpp/MyPreferenceActivity.java – Glaucus May 14 '16 at 02:53
  • However, I didn't see a call to setContentView in onBuildHeaders. So not sure what to think. – Glaucus May 14 '16 at 02:53
2

i tried this code for my application

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory android:title="@string/PreferencesActivity.GeneralSettingsCategoryTitle">
        <Preference
            android:title="yor title"
            android:summary="your summary"
            android:key="key to access preference" />       
        <Preference
            android:title="@string/"
            android:summary="@string/"
            android:key="key2" />
        <PreferenceScreen
            android:key="key3"
            android:title="@string/"
            android:summary="@string/">
            <CheckBoxPreference
                android:title="@string/"
                android:defaultValue="false"
                android:summary="@string/"
                android:key="key4" />
            <CheckBoxPreference
                android:title="@string/"
                android:defaultValue="true"
                android:summary="@string/"
                android:key="key5" />

            <ListPreference
                android:title="@string/"
                android:summary="@string/"
                android:key="key6"
                android:defaultValue="buttons"
                android:entries="@array/"
                android:entryValues="@array/" />
            ....


                </prefefenceScreen>
      </preferenceCategory>
</preferenceScreen>



enter code here
Pratik Popat
  • 2,857
  • 17
  • 29
-1

you do not need to setContenView. in this example case the layout population is done via headers and associated fragments, another words automatically.

Eugene
  • 11
  • I know I don't necessary need it. But in this example I added Button to the List footer. Now I want to customize the view more precisely. Maybe by adding logo in the top of the Activity, etc. That is, I need it. I just don't understand, there are a lot of examples and tutorials about customization of PreferenceActivity for pre-Android 3.0 apps. Is it impossible to make it work for API SDK greater than 10? – morphium Oct 24 '11 at 02:22