ListFragment RuntimeException 'android.R.id.li

2019-06-11 09:43发布

问题:

Edit 1/16/2013: Problem Resolved! Two days ago, I released an updated version of the app and correctly identified the ListViews as I had originally done, by using android:id="@android:id/list. Really though, the exception being thrown was misleading and that had nothing to do with the actual problem...

The real fix came when I implemented the suggestions by Sean on inflating the ListFragment views by passing null to the ViewGroup. I have not received the same Exception from the new version, and the new version has been downloaded by enough devices to safely say this issue is resolved. However I really appreciate the comments and answer made by Lawrence, and will continue to read about how he is instantiating the Fragments. While he provided the suggestion of passing null to the View inflater, Sean was actually the first to do so, and since his solution seems to have resolved the issue, the bounty will be awarded accordingly. I will update this thread in the future if I learn/read more about the different ways of instantiating the Fragments as suggested by Lawrence's excellent answer. Too bad I can't split the bounty!

Edit 1/14/2013: ListView related XML files are located at http://pastebin.com/2xnG1VfF per @LawrenceChoy's request

Edit 1/13/2013: I released an updated version of my app and used android:id="@+id/android:list instead of android:id="@android:id/list" per Bishan's suggestion, however I am still receiving random exceptions that my Fragment Actvity does not have a ListView whose id attribute is 'android.R.id.list', even though that activity does not have any ListViews. Added another exception from LGE phone.

Edit 1/9/2013: Although Bishan provided an answer, I was hoping for a little more explanation as to why his solution might prevent this exception. After reading further I believe it is because when using a custom ListView, one should use a + symbol. However would like to get confirmation I am correct or to get clarification, especially considering both seem to work on many different devices and emulators. Raising a bounty in about 20 minutes to seek a reputable source/answer on the matter. Thanks.


I'm getting some very odd behavior from a few devices out in the wild after a recent updated release to the play store.

In my new release I have a FragmentActivity (called TabsStyled) that uses a FragmentStatePagerAdapter to manage several fragments. I have a total of 4 fragments, and 2 of those fragments extend ListFragment and have listviews populated by LoaderManager and CursorLoader, all from support.v4 libraries. The other two fragments do not have ListViews and do not extend ListFragment.

I did extensive testing on multiple devices as well as AVDs and never encountered any RuntimeExceptions for missing android.R.id.list.

However, upon release, a few ACRA crashes showed up for the FragmentAcitivty "Your content must have a ListView whose id attribute is 'android.R.id.list'". TabsStyled.class is the FragmentActivity that manages the ListFragments and itself does not have any `ListViews'. This seems very strange to me, since I would think that if this exception were to be thrown, it should be for one of the ListFragments, and not the "parent" FragmentActivity.

Here's the top of the stack trace, and I'm happy to provide any additional code or info as requested rather than paste everything here.

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp.hiddenforsecurity/com.myapp.hiddenforsecurity.TabsStyled}: 
java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list'

A full stack trace available on pastebin here: http://pastebin.com/aiV7pwXP.

The XML for each of the ListFragments which contain the ListViews (a separate ListView in a separate XML for each ListFragment):

<ListView android:id="@android:id/list" 
    <!--the release currently uses "@+id/android:list)-->
    android:layout_width="fill_parent" 
    android:layout_height="0dip" 
    android:layout_weight="45" />

One of the ListFragments (slightly simplified to make this easier to diagnose) uploaded to pastebin (the other ListFragment is very similar): http://pastebin.com/Nts3nVx1

And a slightly simplified full version of TabsStyled (FragmentActivity): http://pastebin.com/ZS4Xg8kP

The devices that created the exceptions thus far (and as of 1/14 they continue to post crashes):

MODEL       BRAND    ANDROID API
GT-I9305    Samsung  4.1.1 (using @android:id/list)
GT-S7562    Samsung  4.0.4 (using @android:id/list)
GalaxyNexus Samsung  4.2.1 (same exception seen with @+id/android:list)
L-01E       LGE      4.0.4 (same exception seen with @+id/android:list)

回答1:

Just a hunch, but try inflating your custom View for your ListFragment without using the ViewGroup. So in your ListFragment change

View logv = inflater.inflate(R.layout.listroot, container, false);

to

View logv = inflater.inflate(R.layout.listroot, null);


回答2:

I have been unable to reproduce your problem with the code you provided, as I do not have any devices that you listed above. My first thought is that it may have something to do with the way you initialize the fragments. Please see my modified nFragmentAdapter class below. I have changed getItem() to initialize fragments in a different way:

nFragmentAdapter:

class nFragmentAdapter extends FragmentStatePagerAdapter {

        public nFragmentAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override        
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }

        @Override
        public Fragment getItem(int position) {

            Fragment f = null;
            Bundle args = new Bundle();
            args.putString("content", TabsStyled.CONTENT[position
                    % TabsStyled.CONTENT.length]);
            switch (position) {
            case 0:
                f = Fragment.instantiate(TabsStyled.this,
                        ReviewFragment.class.getName(), args);
                break;
            case 1:
                f = Fragment.instantiate(TabsStyled.this,
                        MyListFragment.class.getName(), args);
                break;
            case 2:
                f = Fragment.instantiate(TabsStyled.this,
                        SmartFragment.class.getName(), args);
                break;
            case 3:
                f = Fragment.instantiate(TabsStyled.this,
                        MyListFragment.class.getName(), args);
                break;
            case 4:
                f = Fragment.instantiate(TabsStyled.this,
                        f.getClass.getName(), args);
                break;
            case 5:
                f = Fragment.instantiate(TabsStyled.this,
                        f.getClass.getName(), args);
                break;
            case 6:
                f = Fragment.instantiate(TabsStyled.this,
                        f.getClass.getName(), args);
                break;
            }
            return f;
        }

        @Override
        public int getCount() {
            return TabsStyled.CONTENT.length;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return TabsStyled.CONTENT[position % TabsStyled.CONTENT.length].toUpperCase();
        }
    }

And corressponding MyListFragment:

public class MyListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {

        myCursorAdapter mAdapter;
        String orderBy = DBAdapter.activityDateTime + " DESC";

        static final String[] activityQuery = new String[] { DBAdapter.activityRowID, DBAdapter.activityReason, DBAdapter.activityDateTime };

        String content;

    public void refreshView() {
        getLoaderManager().restartLoader(0, null, this);
    }

    @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                Bundle args = getArguments();
                if(args != null)
                    content = args.getString("content");
                View logv = inflater.inflate(R.layout.listroot, null);
                return logv;           
        }      

        @Override
    public void onActivityCreated(Bundle savedInstanceState) {
                  super.onActivityCreated(savedInstanceState);
                mAdapter = new myCursorAdapter(getActivity(), null);
                setListAdapter(mAdapter);              
                getLoaderManager().initLoader(0, null, this);
        }

        @Override
        public void onListItemClick(ListView l, View v, int position, long id) {
        }

        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
                return new CursorLoader(getActivity().getApplicationContext(), myListProvider.activity_URI, activityQuery, null, null, orderBy);
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
                mAdapter.swapCursor(data);             
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
                mAdapter.swapCursor(null);     
        }

    public class myCursorAdapter extends CursorAdapter {

        private final LayoutInflater mInflater;

        public myCursorAdapter(Context context, Cursor c) {
                super(context, c, 0);
                mInflater = LayoutInflater.from(context);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {

            TextView logleft = (TextView) view.findViewById(R.id.logleft);
                        logleft.setText(cursor.getString(cursor.getColumnIndex(DBAdapter.activityDateTime)));

            TextView logcenter = (TextView) view.findViewById(R.id.logcenter);
            logcenter.setText(cursor.getString(cursor.getColumnIndex(DBAdapter.activityReason)));

        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
                View view = null;
                view = mInflater.inflate(R.layout.vlist, parent, false);
            return view;
        }
    }

}

Please update on me if this changes anything.



回答3:

try this.

<ListView android:id="@+id/android:list"
    android:choiceMode="singleChoice" 
    android:paddingTop="4dp" 
    android:paddingBottom="4dp" 
    android:layout_width="fill_parent" 
    android:layout_height="0dip" 
    android:layout_weight="45" />

i have replaced android:id="@android:id/list" with android:id="@+id/android:list"



回答4:

Don't use android:id="@+id/list" inside ListView . Either You can create id by using one more option i.e android:id="@id/android:list" or you can use android:id="@+id/list1".



回答5:

thanks for your posts. I was struggling a bit with this as I have just started with Android programming. Changing it to android:id="@android:id/list" did the trick for me.

Though I have just written a sample program which has only one ListView that I displayed inside the ListFramgment, but finally after reading this post I could make it work. Now I am gonna try & see if instead of displaying array of Strings, can I show some custom object (say comprising of a text & icon in one row) in a list.

Thanks much!