0

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)
Cœur
  • 37,241
  • 25
  • 195
  • 267
logray
  • 2,332
  • 1
  • 29
  • 30
  • You can see from logcat that the activity is trying to create a `ListFragment` when the error happens. Can you post all layout files for those `ListFragment`? Also, the correct form of id should be `android:id="@android:id/list", Bishan's answer, as stated below, is incorrect. – Lawrence Choy Jan 15 '13 at 01:55
  • Thanks @LawrenceChoy for your comment, I uploaded the layout files here: http://pastebin.com/2xnG1VfF. Both ListFragments are almost identical. – logray Jan 15 '13 at 02:41
  • Please see my answer below. – Lawrence Choy Jan 15 '13 at 04:07
  • I always set View IDs to `@+id/id_name`. I think the [View page](http://developer.android.com/reference/android/view/View.html#attr_android:id) on Android developers site has a good explanation. Also, as the [**First app** tutorial](http://developer.android.com/training/basics/firstapp/building-ui.html) states _The plus sign (+) before the resource type is needed only when you're defining a resource ID for the first time._ I'm guessing that you are defining it for the first time? – Niklas Ekman Jan 16 '13 at 15:54
  • @NiklasEkman, thanks for your comment. For a ListView in a ListFragment, this is a very special case, and one must not use @+id when defining the ListView. According to the documentation you are ONLY to use android:id="@android:id/list". Anyhow, that really was/is not the source of the problem I'm having (the missing 'android.R.id.list' Exception being thrown is misleading), as the core problem looks to be related to references to the ViewGroup within each ListFragment and/or the way the Fragments are being instantiated. – logray Jan 16 '13 at 16:30

5 Answers5

5

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);
SeanPONeil
  • 3,901
  • 4
  • 29
  • 42
  • and change the android:id back to "@android:id/list". Bishan's answer is incorrect. – SeanPONeil Jan 14 '13 at 17:33
  • I fast tracked this into release and should know by tomorrow or the next day, since I'm seeing several of these exceptions each day. Thanks again, hope this works. – logray Jan 14 '13 at 20:57
  • This seems to have resolved the problem, I'm not seeing this crash anymore with the updated release and your suggestion implemented. Now to award the bounty to you and try to learn about why this fixed the problem. – logray Jan 16 '13 at 16:41
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.

Lawrence Choy
  • 6,088
  • 1
  • 20
  • 30
  • Thank you, I do appreciate your answer and time. I see the way you've changed from using the static constructor newInstance and moved to using instantiate (which I'm still reading about the differences). Also I see how you've moved the bundle code around. I also see you suggested the same thing as SeanPONeil on inflating the view, to use null for the container. I currently have his suggestion in production and have not seen the exception thrown, but still need to give it a day or so. Oh also, yes I also could not reproduce this issue on 4 different devices or emulators. – logray Jan 15 '13 at 15:38
0

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"

Bishan
  • 15,211
  • 52
  • 164
  • 258
  • Well, it's not crashing on my test devices or emulators when I use your code. However it wasn't crashing before when I was using id/list without the +. Is there an explanation why + will not produce a crash but not using the + does? I've read too many conflicting posts about this same issue, and I'm not sure which to use. Thanks – logray Jan 08 '13 at 05:03
  • read answer on this [quetion](http://stackoverflow.com/questions/5025910/difference-between-id-and-id-in-android) – Bishan Jan 08 '13 at 05:16
  • Thanks, I did read through that one before and I suppose I'm just as confused as I was before. Everything I've read says use @android:id/list, and considering both work on my test devices I'm not convinced this is the right answer. Thanks again. – logray Jan 08 '13 at 15:24
  • This was the comment that confused me the most! "The '+' means to create the symbol if it doesn't already exist. You don't need it (and shouldn't use it) when referencing android: symbols, because those are already defined for you by the platform and you can't make your own in that namespace anyway." – logray Jan 08 '13 at 15:44
  • Sorry, your answer did not resolve the problem. I get the same exception even with android:id="@+id/android:list". – logray Jan 11 '13 at 21:57
  • This is incorrect. See the developer docs for [ListFragment](http://developer.android.com/reference/android/app/ListFragment.html) – SeanPONeil Jan 14 '13 at 17:36
0

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".

Vsw10
  • 143
  • 3
  • 10
  • Thanks for the answer, but this is basically just duplicating what has already been said and is also incorrect according to two others. Also I never used "@+id/list". I believe you are incorrect on the second part, "@+id/list1" nor @id/android:list should be used in my case. Check out the docs here http://developer.android.com/reference/android/app/ListFragment.html posted as a comment by SeanPONeil on Bishan's answer. – logray Jan 15 '13 at 15:26
  • i have mentioned above lines of code to create id in ListView . I haven't compared it with your lines of code. If you implemented according to my lines of code you will get the desired result.. – Vsw10 Jan 16 '13 at 04:00
  • Well thanks again for your answer and comment, but it doesn't make any sense related to the content of my question. – logray Jan 16 '13 at 15:04
0

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!

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
Lekh Raj
  • 1
  • 1