Search code examples
androidandroid-fragmentslistadapterandroid-listfragment

ListFragment Not Rendering and getView() in Adapter Not Being Called


From what I can gather it appears that this might be because my ListView is not being displayed, I've verified that getCount is returning a value not zero, but I can't see what I'm doing wrong.

Everything loads and acts like it's working but the ListView never appears, I put a background color on the fragment reference in mixed.xml and it is there and taking up the full screen, but when I set a background color on my ListView it does not appear, it's like it's not being rendered at all.

More odd, getView is not being called in my adapter, and this is all working code from regular activities that I ported to fragments.

I've tried calling notifyDataSetChanged which didn't changed anything, debugging shows the adapter is filled with data and getCount is indeed returning an accurate count greater than 0.

Thanks for any help, I'm stuck.

Project is open and can be viewed here http://code.google.com/p/shack-droid/source/browse/#svn%2FTrunk but I'm also including the pertinent code here.

This is the ListFragment:

    public class FragmentTopicView extends ListFragment implements ShackGestureEvent {

        private ArrayList<ShackPost> posts;
        private String storyID = null;

        private String errorText = "";
        private Integer currentPage = 1;
        private Integer storyPages = 1;
        private String loadStoryID = null;
        private Boolean threadLoaded = true;
        private Hashtable<String, String> postCounts = null;
        private AdapterLimerifficTopic tva;

        public FragmentTopicView() {

        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
                // TODO Auto-generated method stub
                super.onCreate(savedInstanceState);

                this.setRetainInstance(true);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

                return inflater.inflate(R.layout.topics, null);
        }

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
                super.onActivityCreated(savedInstanceState);

                final ShackGestureListener listener = Helper.setGestureEnabledContentView(R.layout.topics, getActivity());
                if (listener != null) {
                        listener.addListener(this);
                }

                if (savedInstanceState == null) {
                        // get the list of topics
                        GetChattyAsyncTask chatty = new GetChattyAsyncTask(getActivity());
                        chatty.execute();
                }

                ListView lv = getListView();
                lv.setOnScrollListener(new OnScrollListener() {

                        @Override
                        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                                // start loading the next page
                                if (threadLoaded && firstVisibleItem + visibleItemCount >= totalItemCount && currentPage + 1 <= storyPages) {

                                        // get the list of topics
                                        currentPage++;
                                        GetChattyAsyncTask chatty = new GetChattyAsyncTask(getActivity());
                                        chatty.execute();

                                }
                        }

                        @Override
                        public void onScrollStateChanged(AbsListView view, int scrollState) {

                        }

                });



        }



    class GetChattyAsyncTask extends AsyncTask<String, Void, Void> {
                protected ProgressDialog dialog;
                protected Context c;

                public GetChattyAsyncTask(Context context) {
                        this.c = context;
                }

                @Override
                protected Void doInBackground(String... params) {

                        threadLoaded = false;

                        try {
                                final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
                                final String feedURL = prefs.getString("shackFeedURL", getString(R.string.default_api));
                                final URL url;

                                if (loadStoryID != null) {
                                        if (currentPage > 1)
                                                url = new URL(feedURL + "/" + loadStoryID + "." + currentPage.toString() + ".xml");
                                        else
                                                url = new URL(feedURL + "/" + loadStoryID + ".xml");
                                }
                                else {
                                        if (currentPage > 1)
                                                url = new URL(feedURL + "/" + storyID + "." + currentPage.toString() + ".xml");
                                        else
                                                url = new URL(feedURL + "/index.xml");
                                }

                                // Get a SAXParser from the SAXPArserFactory.
                                final SAXParserFactory spf = SAXParserFactory.newInstance();
                                final SAXParser sp = spf.newSAXParser();

                                // Get the XMLReader of the SAXParser we created.
                                final XMLReader xr = sp.getXMLReader();
                                // Create a new ContentHandler and apply it to the XML-Reader
                                SaxHandlerTopicView saxHandler = new SaxHandlerTopicView(c, "topic");

                                xr.setContentHandler(saxHandler);

                                // Parse the xml-data from our URL.
                                xr.parse(new InputSource(HttpHelper.HttpRequestWithGzip(url.toString(), c)));

                                // Our ExampleHandler now provides the parsed data to us.
                                if (posts == null) {
                                        posts = saxHandler.GetParsedPosts();
                                }
                                else {
                                        ArrayList<ShackPost> newPosts = saxHandler.GetParsedPosts();
                                        newPosts.removeAll(posts);
                                        posts.addAll(posts.size(), newPosts);

                                }

                                storyID = saxHandler.getStoryID();

                                storyPages = saxHandler.getStoryPageCount();

                                if (storyPages == 0) // XML returns a 0 for stories with only
                                                                                // one page
                                        storyPages = 1;

                        }
                        catch (Exception ex) {
                                // TODO: implement error handling

                        }

                        return null;
                }

                @Override
                protected void onPreExecute() {
                        super.onPreExecute();

                        if (currentPage == 1)
                                dialog = ProgressDialog.show(getActivity(), null, "Loading Chatty", true, true);
                        else
                                SetLoaderVisibility(View.VISIBLE);
                }

                @Override
                protected void onPostExecute(Void result) {
                        super.onPostExecute(result);

                        ShowData();

                        SetLoaderVisibility(View.GONE);

                        try {
                                dialog.dismiss();
                        }
                        catch (Exception e) {
                        }

                }

        }



     private void ShowData() {

                if (posts != null) {
                        Hashtable<String, String> tempHash = null;

                        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
                        final String login = prefs.getString("shackLogin", "");
                        final int fontSize = Integer.parseInt(prefs.getString("fontSize", "12"));

                        try {
                                postCounts = GetPostCache();
                        }
                        catch (Exception ex) {

                        }
                        if (postCounts != null)
                                tempHash = new Hashtable<String, String>(postCounts);

                        if (tva == null) {
                                tva = new AdapterLimerifficTopic(getActivity(), R.layout.lime_topic_row, posts, login, fontSize, tempHash);
                                setListAdapter(tva);
                        }
                        else {
                                tva.SetPosts(posts);
                                tva.notifyDataSetChanged();
                        }

                        final ListView lv = getListView();
                        lv.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
                                @Override
                                public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
                                        menu.setHeaderTitle("Options");
                                        menu.add(0, 1, 0, "Copy Post Url to Clipboard");
                                        menu.add(0, 2, 0, "Watch Thread");
                                        menu.add(0, 3, 0, "Thread Expires In?");
                                        menu.add(0, 4, 0, "Shacker's Chatty Profile");
                                }
                        });

                        // update the reply counts for the listing of topics
                        try {
                                UpdatePostCache();

                        }
                        catch (Exception e) {

                        }

                }
                else {
                        if (errorText.length() > 0) {

                                try {
                                        new AlertDialog.Builder(getActivity()).setTitle("Error").setPositiveButton("OK", null).setMessage(errorText).show();
                                }
                                catch (Exception ex) {
                                        // could not create a alert for the error for one reason
                                        // or another
                                        Log.e("ShackDroid", "Unable to create error alert ActivityTopicView:468");
                                }
                        }
                }
                threadLoaded = true;
        }

}

Here's my FragmentActivity:

  public class FragmentActivityTopic extends FragmentActivity {
        @Override
        protected void onCreate(Bundle arg) {
                // TODO Auto-generated method stub
                super.onCreate(arg);

                setContentView(R.layout.mixed);
        }
}

This is the Adapter I'm using, and as mentioned above getView is not being called:

public class AdapterLimerifficTopic extends BaseAdapter {

        // private Context context;
        private List<ShackPost> topicList;
        private final int rowResouceID;
        private final String shackLogin;
        private final Typeface face;
        private final int fontSize;
        private final Hashtable<String, String> postCache;
        private final String showAuthor;
        private final Resources r;
        private int totalNewPosts = 0;

        LayoutInflater inflate;// = LayoutInflater.from(context);

        public AdapterLimerifficTopic(Context context, int rowResouceID, List<ShackPost> topicList, String shackLogin, int fontSize, Hashtable<String, String> postCache) {
                this.topicList = topicList;
                this.rowResouceID = rowResouceID;
                this.shackLogin = shackLogin;
                this.fontSize = fontSize;
                this.postCache = postCache;
                this.r = context.getResources();

                face = Typeface.createFromAsset(context.getAssets(), "fonts/arial.ttf");

                final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
                showAuthor = prefs.getString("showAuthor", "count");

                inflate = LayoutInflater.from(context);
        }
        public void SetPosts(List<ShackPost> posts)
        {
                topicList = posts;
        }
        @Override
        public int getCount() {
                return topicList.size();
        }

        @Override
        public Object getItem(int position) {
                return topicList.get(position);
        }

        @Override
        public long getItemId(int position) {
                // return position;
                final ShackPost post = topicList.get(position);
                return Long.parseLong(post.getPostID());
        }

        static class ViewHolder {
                TextView posterName;
                TextView datePosted;
                TextView replyCount;
                TextView newPosts;
                TextView postText;
                TextView viewCat;
                RelativeLayout topicRow;
                ImageView postTimer;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

                // TextView tmp;
                // final View v;
                ViewHolder holder;
                final ShackPost post = topicList.get(position);

                if (convertView == null) {
                        convertView = inflate.inflate(rowResouceID, parent, false);
                        holder = new ViewHolder();
                        holder.posterName = (TextView) convertView.findViewById(R.id.TextViewLimeAuthor);
                        holder.datePosted = (TextView) convertView.findViewById(R.id.TextViewLimePostDate);
                        holder.replyCount = (TextView) convertView.findViewById(R.id.TextViewLimePosts);
                        holder.newPosts = (TextView) convertView.findViewById(R.id.TextViewLimeNewPosts);
                        holder.postText = (TextView) convertView.findViewById(R.id.TextViewLimePostText);
                        holder.viewCat = (TextView) convertView.findViewById(R.id.TextViewLimeModTag);
//                      holder.topicRow = (RelativeLayout) convertView.findViewById(R.id.TopicRow);
//                      holder.postTimer = (ImageView) convertView.findViewById(R.id.ImageViewTopicTimer);

//                      holder.posterName.setTypeface(face);
//                      holder.datePosted.setTypeface(face);
//                      holder.replyCount.setTypeface(face);
//                      holder.newPosts.setTypeface(face);
                        holder.postText.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
//                      holder.postText.setTypeface(face);

                        convertView.setTag(holder);
                }
                else {
                        holder = (ViewHolder) convertView.getTag();
                }

//              holder.postTimer.setImageResource(Helper.GetTimeLeftDrawable(post.getPostDate()));
//
                holder.posterName.setText(post.getPosterName());
//
//              if (shackLogin.equalsIgnoreCase(post.getPosterName()))
//                      holder.posterName.setTextColor(Color.parseColor("#00BFF3"));
//              else
//                      holder.posterName.setTextColor(Color.parseColor("#ffba00"));
//
                holder.datePosted.setText(Helper.FormatShackDateToTimePassed(post.getPostDate()));

                holder.replyCount.setText(post.getReplyCount());
//
//              if (showAuthor.equalsIgnoreCase("count") && post.getIsAuthorInThread())
//                      holder.replyCount.setTextColor(Color.parseColor("#0099CC"));
//              else
//                      holder.replyCount.setTextColor(Color.parseColor("#FFFFFF"));
// clipped code
                holder.postText.setText(preview);


//              if (showAuthor.equalsIgnoreCase("topic") && post.getIsAuthorInThread()) {
//                      final Drawable d = r.getDrawable(R.drawable.background_gradient_blue);
//                      holder.topicRow.setBackgroundDrawable(d);
//              }
//              else
//                      holder.topicRow.setBackgroundDrawable(null);


                // TODO: clean this up a little / also replicated in ShackDroidThread ick
                final String postCat = post.getPostCategory();
                holder.viewCat.setVisibility(View.VISIBLE);

                if (postCat.equals("offtopic"))  {
                        holder.viewCat.setText("offtopic");
                        holder.viewCat.setBackgroundColor(Color.parseColor("#444444"));
                }
                else if (postCat.equals("nws")) {
                        holder.viewCat.setText("nws");
                        holder.viewCat.setBackgroundColor(Color.parseColor("#CC0000"));
                }
                else if (postCat.equals("political")) {
                        holder.viewCat.setText("political");
                        holder.viewCat.setBackgroundColor(Color.parseColor("#FF8800"));
                }
                else if (postCat.equals("stupid")) {
                        holder.viewCat.setText("stupid");
                        holder.viewCat.setBackgroundColor(Color.parseColor("#669900"));
                }
                else if (postCat.equals("informative")) {
                        holder.viewCat.setText("interesting");
                        holder.viewCat.setBackgroundColor(Color.parseColor("#0099CC"));
                }
                else 
                        holder.viewCat.setVisibility(View.GONE);                


                return convertView;
        }

        public int getTotalNewPosts() {
                return totalNewPosts;
        }

}

And related XML:

mixed.xml (this is the layout for the fragments, only the one for now)

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" 
    android:id="@+id/LinearLayoutMixed">

    <fragment
        android:id="@+id/MixedThreads"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        class="com.stonedonkey.shackdroid.FragmentTopicView"
        >
    </fragment>

</LinearLayout>

Topics.xml (this contains the ListView as well as a sliding tray and some other stuff.

 <?xml version="1.0" encoding="utf-8"?>
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"  >

            <ListView
                android:id="@android:id/list"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_above="@+id/TopicLoader"
                android:divider="#333333"
                android:dividerHeight="1dip"
                android:textColor="#FFFFFF"

                 />

            <RelativeLayout
                android:id="@+id/TopicLoader"
                android:layout_width="fill_parent"
                android:layout_height="35dip"
                android:layout_alignParentBottom="true"
                android:gravity="center_horizontal"
                android:visibility="gone"
                android:layout_marginTop="5dip" >

                <TextView
                    android:id="@+id/TextViewTopicLoaderText"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:focusable="false"
                    android:focusableInTouchMode="false"
                    android:text="Loading" 

                    >
                </TextView>

                <ImageView
                    android:id="@+id/ImageViewTopicLoader"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_toRightOf="@+id/TextViewTopicLoaderText"
                    android:src="@drawable/ic_action_refresh"
                    android:layout_alignBottom="@+id/TextViewTopicLoaderText"
                     />
            </RelativeLayout>

            <SlidingDrawer
                android:id="@+id/SlidingDrawer01"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_below="@+id/TopicLoader"
                android:animateOnClick="true"
                android:content="@+id/bookMarkParent"
                android:handle="@+id/TextViewTrayHandle"
                android:orientation="vertical"
                android:paddingTop="200dip"
                android:visibility="gone" >

                <TextView
                    android:id="@+id/TextViewTrayHandle"
                    android:layout_width="fill_parent"
                    android:layout_height="35dip"
                    android:background="@drawable/darkgrey_gradient"
                    android:focusable="false"
                    android:focusableInTouchMode="false"
                    android:gravity="center_vertical" >
                </TextView>

                <RelativeLayout
                    android:id="@id/bookMarkParent"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" >

                    <ListView
                        android:id="@+id/ListViewWatchedThreads"
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent"
                        android:divider="#333333"
                        android:dividerHeight="1dip"
                        android:textColor="#FFFFFF" >
                    </ListView>
                </RelativeLayout>
            </SlidingDrawer>

        </RelativeLayout>

and finally lime_topic_row which is my custom row layout for the ListView in the above layout:

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

        <TextView
            android:id="@+id/TextViewLimeModTag"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#FF0000"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="10dip"
            android:textColor="#000000"
            android:padding="2dip"
            android:textSize="10dip"
            />    
        <TextView
            android:id="@+id/TextViewLimePostText"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:minHeight="20dip"
            android:padding="10dip"
            android:layout_below="@+id/TextViewLimeModTag"
            android:textColor="#FFFFFF" />

        <TextView
            android:id="@+id/TextViewLimeAuthor"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/TextViewLimePostText"
            android:paddingBottom="10dip"
            android:paddingLeft="10dip"
            android:textColor="#0099CC" />

        <TextView
            android:id="@+id/TextViewPosted"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/TextViewLimePostText"
            android:layout_toRightOf="@+id/TextViewLimeAuthor"
            android:paddingBottom="10dip"
            android:text=" posted " />

        <TextView
            android:id="@+id/TextViewLimePostDate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/TextViewLimePostText"
            android:layout_toRightOf="@+id/TextViewPosted"
            android:paddingBottom="10dip"
            android:paddingRight="10dip"
            android:textColor="#FF8800" />



        <TextView
            android:id="@+id/TextViewLimePosts"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBaseline="@+id/TextViewLimePostDate"
            android:layout_marginRight="3dip"
            android:layout_below="@+id/TextViewLimePostText"
            android:layout_marginBottom="15dip"
            android:layout_toLeftOf="@+id/TextViewLimeNewPosts"
            android:background="#BBBBBB"
            android:padding="3dip"
            android:minWidth="25dip"
            android:gravity="center"
            android:textColor="#000000" />

        <TextView
            android:id="@+id/TextViewLimeNewPosts"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBaseline="@+id/TextViewLimePostDate"
            android:layout_below="@+id/TextViewLimePostText"
            android:layout_marginBottom="15dip"
            android:layout_marginRight="10dip"
            android:background="#669900"
            android:padding="3dip"
            android:minWidth="25dip"
            android:gravity="center"
            android:layout_alignParentRight="true"
            android:textColor="#000000" />

    </RelativeLayout>

Solution

  • I think I found the problem. The issue appears because of the ShackGestureListener that you setup at the start of the onActivityCreated method in the FragmentTopicView:

    final ShackGestureListener listener = Helper.setGestureEnabledContentView(R.layout.topics, getActivity());
    if (listener != null) {
        listener.addListener(this);
    }
    

    In the setGestureEnabledContentView() method you check to see if the user enabled the gestures in the preferences or if the android version is bigger then 3. Either way, true or false you set the content view for the FragmentActivityTopic again(with the layout of the FragmentTopicView). Setting the content view again will, unfortunately, cover the current layout which holds the ListView with data(ListView that populates with no problems). When you run those AsyncTasks to get the data, at the end you set the data on the correct ListView(returned by getListView) because the getListView will hold a reference to the old correct ListView which was set in the onCreateView method, but you don't see anything because in the setGestureEnabledContentView you cover this ListView.

    This behavior is easy to see if you simple comment out(or remove) the lines that set the content view for the activity in the Helper and HelperAPI4 classes. Another way to see that your ListView is covered is, for example to set the adapter for the ListView(tva) using getListView and using the getActivity().findViewById(android.R.id.list)(I've done this on selecting one of your menus items, so I can control when I replace the adapter):

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Intent intent;
        switch (item.getItemId())
        {
        case R.id.topic_menu_newpost: // Launch post form
    //this doesn't work as the getListView will return a reference to the old ListView
    ListView lv = getListView();
    lv.setAdapter(tva);
    // this will work as you get a reference to the new ListView on top
    ListView lv = (ListView) getActivity().findViewById(android.R.id.list);
    lv.setAdapter(tva);
    

    I don't know what to recommend as a solution as I don't quite understand what you're doing, but I doubt that it requires to set the content view for the activity again(and you should work from this).