Search code examples
androidjsonlistviewhashmapandroid-arrayadapter

ListView can't be populated with an adaptor that uses HashMap filled with JSON object


I seem not to be able to load a JSON object into a ListView. When the code reaches the line list.setAdaptor(..) I get an InvocationTargetException.

Step by step debugging I think the JSON object is initialized perfectly fine. The HashMap is filled correctly. I think the problem is with my ArrayAdaptor but I don't know what is going wrong.

I'm new to Android and this is my first time dealing with Adaptors and AsyncTask and JSON. So I will be so thankful for any help. Even if you think you are stating the obvious please don't hesitate to mention whatever it is you think I am approaching the wrong way.

Here is the code to my child activity in which I am trying to populate the ListView using the JSONObject:

(if you think any other part of the code is needed please comment. I will add it right away)

    public class SearchResultListActivity extends ActionBarActivity implements OnItemClickListener{
    // for json
        private ProgressDialog progress;
        ListView list;
        TextView ver;
        TextView name;
        TextView api;
        Button Btngetdata;
        ArrayList<HashMap<String, String>> oslist = new ArrayList<HashMap<String, String>>();
        //URL to get JSON Array
        private static String url = "http://api.learn2crack.com/android/jsonos/";
        //JSON Node Names
        private static final String TAG_OS = "android";
        private static final String TAG_VER = "ver";
        private static final String TAG_NAME = "name";
        private static final String TAG_API = "api";
        JSONArray jsonArray = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search_result_list);
        if (savedInstanceState == null) {
         //zzz commented for let json run. uncomment when remove json   getSupportFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();
        }
        new JSONParse().execute();
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.search_result_list, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will automatically handle clicks on the Home/Up button, so long as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    @Override
    public void onItemClick(AdapterView<?> arg0, View textView, int rowNumber, long arg3) {
        Intent intent = new Intent(this, PropertyDetailActivity.class);
        startActivity(intent);
    }
    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onActivityCreated(savedInstanceState);
        }
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_search_result_list, container, false);
            return rootView;
        }
    }
    // This is the custom adapter class where you will manage the behavior of your ListView content
    public class MyArrayAdapter extends ArrayAdapter<String>{
        Context context; 
        int layoutResourceId; // This is the layout you created for the list items   
        String data[] = null; // the array with the data to populate the listview
        public MyArrayAdapter(Context context, int layoutResourceId, String[] data) {
            super(context, layoutResourceId, data);
            this.layoutResourceId = layoutResourceId;
            this.context = context;
            this.data = data;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = convertView;
            LayoutInflater inflater = ((Activity) getContext()).getLayoutInflater();    
            row = inflater.inflate(layoutResourceId, parent, false);
            TextView txtTitle = (TextView)row.findViewById(R.id.listViewSearchResultTxtTitle);
            txtTitle.setText(data[position]);
            return row;
        }
    }
  //*********************************** inner class
    public class JSONParse extends AsyncTask<String, String, JSONObject> {
        private ProgressDialog pDialog;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            ver = (TextView)findViewById(R.id.listViewSearchResultTxtTitle);
            name = (TextView)findViewById(R.id.listViewSearchResultTxtBody1);
            api = (TextView)findViewById(R.id.listViewSearchResultTxtBody2);
        }
        @Override
        protected JSONObject doInBackground(String... args) {
            JSONParser jParser = new JSONParser();
            JSONObject json = jParser.getJSONFromUrl(url);
            return json;
        }
        @Override
        protected void onPostExecute(JSONObject json) {
            //pDialog.dismiss();
            Toast.makeText(getApplicationContext(), " 2000 "+json.toString() , Toast.LENGTH_LONG).show();
            try {
            // Getting JSON Array from URL
                jsonArray = json.getJSONArray(TAG_OS);
                for(int i = 0; i < jsonArray.length(); i++){
                    JSONObject c = jsonArray.getJSONObject(i);
                    // Storing  JSON item in a Variable
                    String ver = c.getString(TAG_VER);
                    String name = c.getString(TAG_NAME);
                    String api = c.getString(TAG_API);
                    //Adding value HashMap key => value
                    HashMap<String, String> map = new HashMap<String, String>();
                    map.put(TAG_VER, ver);
                    map.put(TAG_NAME, name);
                    map.put(TAG_API, api);
                    oslist.add(map);
                }
                ListAdapter adapter = new SimpleAdapter( getApplicationContext() , oslist, R.layout.list_view_items, new String[] { TAG_VER,TAG_NAME, TAG_API }, new int[] {
                    //R.id.listViewSearchResultTxtTitle,
                R.id.listViewSearchResultTxtBody1, R.id.listViewSearchResultTxtBody2});
                list=(ListView)findViewById(R.id.listViewSearchResult);
                list.setAdapter(adapter);
            } 
            catch (JSONException e) {
              e.printStackTrace();
            }
        }
        public void showProgressDialog(final String msg) {
            runOnUiThread(new Runnable() {
                public void run() {
                    if (progress == null || !progress.isShowing()) {
                        progress = ProgressDialog.show(getApplicationContext(), "", msg);
                    }
                }
            });
        }
        public void hideProgressDialog() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        if (progress.isShowing())
                            progress.dismiss();
                    } 
                    catch (Throwable e) {
                    }
                }
            });
        }
    }
    //json end

}

Here is the LogCat error. (when I debug I get InvocationTargetException, and LogCat gives me NullPointerException. I don't now why they differ :S)

    6-03 08:11:56.412: E/AndroidRuntime(5681): FATAL EXCEPTION: main
06-03 08:11:56.412: E/AndroidRuntime(5681): Process: com.****, PID: 5681
06-03 08:11:56.412: E/AndroidRuntime(5681): java.lang.NullPointerException
06-03 08:11:56.412: E/AndroidRuntime(5681):     at com...SearchResultListActivity$JSONParse.onPostExecute(SearchResultListActivity.java:162)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at com..SearchResultListActivity$JSONParse.onPostExecute(SearchResultListActivity.java:1)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at android.os.AsyncTask.finish(AsyncTask.java:632)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at android.os.AsyncTask.access$600(AsyncTask.java:177)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at android.os.Handler.dispatchMessage(Handler.java:102)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at android.os.Looper.loop(Looper.java:136)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at android.app.ActivityThread.main(ActivityThread.java:5017)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at java.lang.reflect.Method.invokeNative(Native Method)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at java.lang.reflect.Method.invoke(Method.java:515)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
06-03 08:11:56.412: E/AndroidRuntime(5681):     at dalvik.system.NativeStart.main(Native Method)

fragment_search_result_list.xml:

<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" 
android:orientation="vertical"
tools:context="com..SearchResultListActivity$PlaceholderFragment">
    <ListView
    android:id="@+id/listViewSearchResult"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    </ListView>
</LinearLayout>

activity_search_result_list.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:context="com..SearchResultListActivity"
    tools:ignore="MergeRootFrame"/>

Solution

  • ListView belongs to the Fragment Layout while you initialize it in AsyncTask invoked from Activity's onCreate.

    You either initialize listview in Fragment or set the fragment layout to the Activity.

    I would suggest you initialize listview in Fragment. To get the context use getActivity().

      @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_search_result_list, container, false);
            list=(ListView)rootView.findViewById(R.id.listViewSearchResult);
              new JSONParse(getActivity()).execute(); 
            return rootView;
        }
    

    Then

       Context mContext;  
       public JSONParse(Context context)
       {
           mContext= context;
       }
    

    Then

      new SimpleAdapter(mContext...
    

    Do Read

    NullPointerException accessing views in onCreate()