0

In a TabActivity, one TabSpec consists of a few TextViews and below, a ListView element. I would like to populate the ListView with an AsyncTask from an external database. In all other parts of my app with 'standard' layouts, this works fine, but here it seems that the nested ListView creates a problem. If I load my data - supposedly into the ListView of the TabSpec - the app instead creates a new 'window' on top of the TabActivity, so the "back" button brings me back to the (empty) TabSpec.

Here is my code:

TabHost (venueview.xml):

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TabWidget
        android:id="@android:id/tabs"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <FrameLayout
        android:id="@android:id/tabcontent"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>
</LinearLayout>
</TabHost>

TabSpec with the ListView (venueviewreviews.xml):

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

<TextView
    android:id="@+id/txtvname_r"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="txtvname" />
<RatingBar
    android:id="@+id/ratingBar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
<Button
    android:id="@+id/btnRatingSubmit"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
<ListView
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</LinearLayout>

Here is the code creating the TabHost:

public class VViewActivity extends TabActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.venueview);

    TabHost tabHost = getTabHost();

    TabSpec vinfospec = tabHost.newTabSpec("Info");
    vinfospec.setIndicator("Info",
            getResources().getDrawable(R.drawable.ic_info));
    Intent vinfoIntent = new Intent(this, VViewBasicActivity.class);
    vinfospec.setContent(vinfoIntent);

    TabSpec vmapspec = tabHost.newTabSpec("Map");
    vmapspec.setIndicator("Location",
            getResources().getDrawable(R.drawable.ic_map));
    Intent vmapIntent = new Intent(this, VViewMapActivity.class);
    vmapspec.setContent(vmapIntent);

    TabSpec vreviewsspec = tabHost.newTabSpec("Reviews");
    vreviewsspec.setIndicator("Reviews",
            getResources().getDrawable(R.drawable.ic_review));
    Intent vreviewsIntent = new Intent(this, VViewReviewsActivity.class);
    vreviewsspec.setContent(vreviewsIntent);

    // Adding all TabSpec to the TabHost for display
    tabHost.addTab(vinfospec);
    tabHost.addTab(vmapspec);
    tabHost.addTab(vreviewsspec);

}

}

And here comes the part where I think there must be something the source of my problem (pun intended) - the code behind setting up the TabSpec with the ListView to be filled and displayed properly:

public class VViewReviewsActivity extends Activity {
private RatingBar ratingBar;
private TextView txtvname_r;
private Button btnRatingSubmit;
private ListView lvComments;
private static ListAdapter laComments;
String vid;
String vname;
String rating;

private static ArrayList<HashMap<String, String>> commentsList;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.venueviewreviews);

    ListView lvComments = (ListView)findViewById(R.id.list);

    Intent lc = new Intent(this, GetVenueComments.class);
    lc.putExtra("vid",vid);
    startActivity(lc);

}


public static class GetVenueComments extends ListActivity {
    JSONParser jParser = new JSONParser();
    JSONArray comments = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.venueviewreviews);

        commentsList = new ArrayList<HashMap<String, String>>();
        new LoadAllVenues().execute();

    }

    /**
     * Background Async Task to Load all venues via HTTP Request
     * */
    class LoadAllVenues extends AsyncTask<String, String, String> {

        protected String doInBackground(String... args) {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            Intent iCurr = getIntent();
            JSONObject json = jParser.makeHttpRequest(
                    getString(R.string.urlVenueComments), "GET", params);

            try {
                // Checking for SUCCESS TAG
                int success = json.getInt(TAG_SUCCESS);
                if (success == 1) {
                    // products found

                    // Getting Array of Products
                    comments = json.getJSONArray(TAG_COMMENTS);

                    // looping through All Products
                    for (int i = 0; i < comments.length(); i++) {
                        JSONObject c = comments.getJSONObject(i);


                        // creating new HashMap
                        HashMap<String, String> hashmap = new HashMap<String, String>();

                        // adding each child node to HashMap key => value
                        hashmap.put(TAG_COMMENTS_ID, cid);
                        hashmap.put(TAG_COMMENTS_COMMENT, ctext);

                        // adding HashList to ArrayList
                        commentsList.add(hashmap);
                    }
                } else {
                    // cut to save space
                }
            } catch (JSONException e) {
                // cut to save space
            }

            return null;
        }

        /**
         * After completing background task Dismiss the progress dialog
         * **/
        protected void onPostExecute(String file_url) {
            // updating UI from Background Thread
            runOnUiThread(new Runnable() {
                public void run() {
                    // Updating parsed JSON data into ListView
                    laComments = new SimpleAdapter(
                            GetVenueComments.this,
                            commentsList,
                            R.layout.commentlistitem,
                            new String[] { TAG_COMMENTS_ID,
                                                                            TAG_COMMENTS_COMMENT }, new int[] {
                                    R.id.CommentList_id,
                                                                            R.id.CommentList_comment });
                    // updating listview
                    setListAdapter(laComments);
                }
            });

        }

    }
}

}

Any idea what I have to fix to have the comment ListView display right within the TabSpec instead of in a separately opened window/activity?

richey
  • 3,890
  • 9
  • 35
  • 49
  • I think its not possible to add ListActivity inside Activity,make this VViewReviewsActivity as ListActivity then try – Pradeep Jun 02 '12 at 13:22
  • @Pradeep: thanks, but that didn't help. It is still creating another window / Activity on top of the TabHost. – richey Jun 05 '12 at 03:09
  • HI Richey I slightly modified your code try that it may work.. – Pradeep Jun 05 '12 at 06:10

3 Answers3

0

Your listview is defined in an Activity, not a ListActivity. The method to set adapters is different...

Maybe your call for setting the adapter should be:

lvComments.setAdapter(laComments);

Or change to a ListActivity instead of an Activity.

Barak
  • 16,318
  • 9
  • 52
  • 84
  • I have changed VViewActivity from an Activity into a ListActivity, and on top of that, changed "setListAdapter(laComments);" to "lvComments.setAdapter(laComments);" but now I get an NullPointerException (btw, regardless if I define VViewActivity as ListActivity or just Activity). – richey Jun 05 '12 at 03:08
  • Exactly the line above: setListAdapter(laComments); ;-) The interesting thing is: meanwhile I discovered a tutorial for (almost) exactly the functionality I need: http://www.androidhive.info/2012/05/android-combining-tab-layout-and-list-view/ - but as you can see from my comment named "ROB" there, I get a NullPointerException at almost exactly the same spot as soon as I am using a TextView element in a tab containing a ListView... funnily enough, I get it in the tab NOT containing the ListView. I have no idea what's going on there … just adding one TextView in a TabSpec breaks the code! – richey Jun 05 '12 at 10:40
0

Calling ListActivity Inside Activity is creating new Window for u.. To avoid that directly register your ListActivity (GetVenueComments) in TabActivity(VViewActivity).. I did it below check it

public class VViewActivity extends TabActivity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.venueview);

TabHost tabHost = getTabHost();

TabSpec vinfospec = tabHost.newTabSpec("Info");
vinfospec.setIndicator("Info",
        getResources().getDrawable(R.drawable.ic_info));
Intent vinfoIntent = new Intent(this, VViewBasicActivity.class);
vinfospec.setContent(vinfoIntent);

TabSpec vmapspec = tabHost.newTabSpec("Map");
vmapspec.setIndicator("Location",
        getResources().getDrawable(R.drawable.ic_map));
Intent vmapIntent = new Intent(this, VViewMapActivity.class);
vmapspec.setContent(vmapIntent);

TabSpec vreviewsspec = tabHost.newTabSpec("Reviews");
vreviewsspec.setIndicator("Reviews",
        getResources().getDrawable(R.drawable.ic_review));
Intent vreviewsIntent = new Intent(this, GetVenueComments.class);
vreviewsspec.setContent(vreviewsIntent);

// Adding all TabSpec to the TabHost for display
tabHost.addTab(vinfospec);
tabHost.addTab(vmapspec);
tabHost.addTab(vreviewsspec);

 tabHost.setCurrentTab(2);

 }

}



public static class GetVenueComments extends ListActivity {
JSONParser jParser = new JSONParser();
JSONArray comments = null;

private RatingBar ratingBar;
private TextView txtvname_r;
private Button btnRatingSubmit;
private ListView lvComments;
private static ListAdapter laComments;
String vid;
String vname;
String rating;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.venueviewreviews);

    ListView lvComments = (ListView)findViewById(R.id.list);

    commentsList = new ArrayList<HashMap<String, String>>();
    new LoadAllVenues().execute();

}

/**
 * Background Async Task to Load all venues via HTTP Request
 * */
class LoadAllVenues extends AsyncTask<String, String, String> {

    protected String doInBackground(String... args) {
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        Intent iCurr = getIntent();
        JSONObject json = jParser.makeHttpRequest(
                getString(R.string.urlVenueComments), "GET", params);

        try {
            // Checking for SUCCESS TAG
            int success = json.getInt(TAG_SUCCESS);
            if (success == 1) {
                // products found

                // Getting Array of Products
                comments = json.getJSONArray(TAG_COMMENTS);

                // looping through All Products
                for (int i = 0; i < comments.length(); i++) {
                    JSONObject c = comments.getJSONObject(i);


                    // creating new HashMap
                    HashMap<String, String> hashmap = new HashMap<String, String>();

                    // adding each child node to HashMap key => value
                    hashmap.put(TAG_COMMENTS_ID, cid);
                    hashmap.put(TAG_COMMENTS_COMMENT, ctext);

                    // adding HashList to ArrayList
                    commentsList.add(hashmap);
                }
            } else {
                // cut to save space
            }
        } catch (JSONException e) {
            // cut to save space
        }

        return null;
    }

    /**
     * After completing background task Dismiss the progress dialog
     * **/
    protected void onPostExecute(String file_url) {
        // updating UI from Background Thread
        runOnUiThread(new Runnable() {
            public void run() {
                // Updating parsed JSON data into ListView
                laComments = new SimpleAdapter(
                        GetVenueComments.this,
                        commentsList,
                        R.layout.commentlistitem,
                        new String[] { TAG_COMMENTS_ID,
                                                                        TAG_COMMENTS_COMMENT }, new int[] {
                                R.id.CommentList_id,
                                                                        R.id.CommentList_comment });
                // updating listview
                setListAdapter(laComments);
            }
        });

    }

  }
 }
Pradeep
  • 2,530
  • 26
  • 37
  • In order to make this work, should I remove all "list-filling" code from the current VViewReviewsActivity.class? Because if I simply add the code above to the VViewActivity class, it still creates the view on top of the other window. I could find a tutorial for my requirements as mentioned in my comment on /Barak/'s answer above, but it also gives me a NullPointerException simply as soon as I add a TextView to a TabSpec containing a ListView. It is really strange, I don't understand it… – richey Jun 05 '12 at 10:45
  • Thanks Pradeep! But now the ListView isn't loading any entries at all, the Async/Background tasks are never called. – richey Jun 05 '12 at 16:34
0

I think I found the solution: somehow TabHost/TabSpec handles Views very differently, so having a TextView or another element apart from the ListView that is to be filled in TabHost, messes up the context stack.

So what I did was to refresh the variables referencing the Buttons and TextViews in an overridden onContentChanged() method, as "Chris" has explained here:

@Override
public void onContentChanged() {
    // refresh with current view, otherwise NullPointerException on
    // OnPostExecute() when trying to set value of the field with
    // setText()!!
    super.onContentChanged();

    btnRatingSubmit = (Button) VViewReviewsActivity.this
            .findViewById(R.id.btnRatingSubmit);
    txtvname_r = (TextView) VViewReviewsActivity.this
            .findViewById(R.id.txtvname_r);
    ratingBar = (RatingBar) VViewReviewsActivity.this
            .findViewById(R.id.ratingBar);
}
Community
  • 1
  • 1
richey
  • 3,890
  • 9
  • 35
  • 49