luongkhanh luongkhanh - 1 month ago 13
Java Question

Fragment implementing AsyncTask and GridView in android

I using Activity to load data from json with AsyncTask and display in Fragment class.
Display content include: ImageView, TextView, TextView and when user click an item will redirect corresponding item in GridView

In ManufactureFragment includes:


  1. POJO ManufacturerItem

  2. LoadAllManufacturers extends AsyncTask to load data from json

  3. Adapter: call load data from json



My Fragment:

public class ManufacturerFragment extends Fragment {

ProgressDialog pDialog;
JSONParser jsonParser = new JSONParser();

// ALL JSON node names
private static final String TAG_ID = "id";
private static final String TAG_NAME = "name";
private static final String TAG_ICONNAME = "iconName";

// initiliaze adapter variable
MyAdapter adapter;
ArrayList<HashMap<String, String>> manufacturersList = new ArrayList<>();
JSONArray manufacturers = null;

// manufacturers JSON url
private static final String URL_MANUFACTURERS = "http://MYURL";

public ManufacturerFragment() {
// Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.gridview_manufacturer, container, false);

GridView gridView = (GridView) view.findViewById(R.id.gridview);
// gridView.setAdapter(new MyAdapter(getActivity(), manufacturersList));
adapter = new MyAdapter(getActivity(), manufacturersList);
gridView.setAdapter(adapter);

gridView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View view, int arg2, long arg3) {
// on selecting a single manufacturer
// CategoryCarActivity will be launched to show category car inside the manufacturer
Intent i = new Intent(getActivity(), CategoryCarActivity.class);

// send manufacturer id to activity to get list of cars under that manufacturer
String manufacturer_id = ((TextView) view.findViewById(R.id.manufacturer_id)).getText().toString();
i.putExtra("manufacturer_id", manufacturer_id);

startActivity(i);
}
});

return view;
}

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

new LoadAllManufacturers().execute();
}


class LoadAllManufacturers extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(getActivity());
pDialog.setMessage("Loading manufacturers. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
String json = jsonParser.makeHttpRequest(URL_MANUFACTURERS, "GET", params);
// Check your log cat for JSON reponse
Log.d("Manufacturers JSON: ", "> " + json);
try {
manufacturers = new JSONArray(json);

if (manufacturers != null) {
// looping through All Manufacturers
for (int i = 0; i < manufacturers.length(); i++) {
JSONObject c = manufacturers.getJSONObject(i);

// Storing each json item values in variable
String id = c.getString(TAG_ID);
String name = c.getString(TAG_NAME);
String iconName = c.getString(TAG_ICONNAME);

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

// adding each child node to HashMap key => value
map.put(TAG_ID, id);
map.put(TAG_NAME, name);
map.put(TAG_ICONNAME, iconName);

// adding HashList to ArrayList
manufacturersList.add(map);
}
}else{
Log.d("Manufacturers: ", "null");
}

} catch (JSONException e) {
e.printStackTrace();
}

return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);

adapter.notifyDataSetChanged();
// dismiss the dialog after getting all manufacturers
if (pDialog.isShowing())
pDialog.dismiss();
}
}

private class MyAdapter extends BaseAdapter
{
ArrayList<HashMap<String, String>> manufacturersList;
LayoutInflater inflater;
HashMap<String, String> resultp = new HashMap<String, String>();
Context context;

public MyAdapter(Context context, ArrayList<HashMap<String, String>> arrayList)
{
this.context = context;
this.manufacturersList = arrayList;
this.inflater = LayoutInflater.from(context);
}

@Override
public int getCount() {
if (manufacturersList != null)
return manufacturersList.size();
return 0;
}

@Override
public Object getItem(int i)
{
if (manufacturersList != null)
return manufacturersList.get(i);
return null;
}

@Override
public long getItemId(int i)
{
if (manufacturersList != null)
return manufacturersList.get(i).hashCode();
return 0;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup)
{
View v = view;
ImageView picture;
TextView name;

if(v == null)
{
v = inflater.inflate(R.layout.gridview_item, viewGroup, false);
v.setTag(R.id.picture, v.findViewById(R.id.picture));
v.setTag(R.id.text, v.findViewById(R.id.text));
}

picture = (ImageView)v.getTag(R.id.picture);
name = (TextView)v.getTag(R.id.text);

ManufacturerFragment.MyAdapter.ManufacturerItem item = (ManufacturerFragment.MyAdapter.ManufacturerItem)getItem(i);

picture.setImageResource(item.drawableId);
name.setText(item.name);

return v;
}

// POJO ManufacturerItem
private class ManufacturerItem
{
final String name;
final int drawableId;
// Constructor
ManufacturerItem(String name, String cars_count, int drawableId)
{
this.name = name;
this.drawableId = drawableId;
}
}

}
}


My list_item_manufacturers.xml

<?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="wrap_content"
android:orientation="vertical">

<!-- Manufacturer_id / Hidden by default -->
<TextView
android:id="@+id/manufacturer_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone" />

<!-- Manufacturer_name -->
<TextView
android:id="@+id/manufacturer_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16dip"
android:textColor="#000000"
android:paddingTop="15dip"
android:paddingBottom="15dip"
android:paddingLeft="10dip"
android:textStyle="bold"/>

<!-- Logo image -->
<ImageView
android:id="@+id/iconName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="#000000"
android:padding="1dp" />
</RelativeLayout>


My gridview_manufacturer.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:stretchMode="columnWidth"
android:numColumns="2" />
</FrameLayout>


When I debug and build, I see that json load success, but and then it happen a exception at line:

manufacturersList.add(map);


Logcat:

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.totoroads.android.app, PID: 3723
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.util.ArrayList.add(java.lang.Object)' on a null object reference
at com.totoroads.android.app.FeedBackFragment$LoadAllManufacturers.doInBackground(ManufacturerFragment.java:136)
at com.totoroads.android.app.FeedBackFragment$LoadAllManufacturers.doInBackground(ManufacturerFragment.java:89)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
at java.lang.Thread.run(Thread.java:818) 


When I updated source code, I built and Logcat return json result list manufacturer following as:

D/Manufacturers JSON:: > [{"id":3,"name":"Huyndai","content":"chuyên sản xuất các loại xe nhÆ°: Lexus, Camry, Vios, Altis,..","insertDate":"Sep 24, 2016","updateDate":"Sep 24, 2016","iconName":"http://192.168.1.221:9999/restfulspringmvc/images/huyndai.jpg"},{"id":1,"name":"Honda","content":"chuyên sản xuất các loại xe nhu: CRV, Accord,..","insertDate":"Jun 11, 2016","updateDate":"Sep 24, 2016","iconName":"http://192.168.1.221:9999/restfulspringmvc/images/honda.jpg"},{"id":2,"name":"Toyota","content":"chuyên sản xuất các loại xe nhÆ°: Lexus, Camry, Vios, Altis,..","insertDate":"Jun 11, 2016","updateDate":"Sep 24, 2016","iconName":"http://192.168.1.221:9999/restfulspringmvc/images/toyota.jpg"},{"id":4,"name":"BMV","content":"chuyên sản xuất các loại xe nhÆ°: Lexus, Camry, Vios, Altis,..","insertDate":"Sep 24, 2016","updateDate":"Sep 24, 2016","iconName":"http://192.168.1.221:9999/restfulspringmvc/images/bmv.jpg"},{"id":5,"name":"Mercedes","content":"chuyên sản xuất các loại xe nhÆ°: Lexus, Camry, Vios, Altis,..","insertDate":"Sep 24, 2016","updateDate":"Sep 24, 2016","iconName":"http://192.168.1.221:9999/restfulspringmvc/images/mercedes.jpg"},{"id":6,"name":"Kia Morning","content":"chuyên sản xuất các loại xe nhÆ°: Lexus, Camry, Vios, Altis,..","insertDate":"Sep 24, 2016","updateDate":"Sep 24, 2016","iconName":"http://192.168.1.221:9999/restfulspringmvc/images/kiamorning.jpg"},{"id":7,"name":"Luxus","content":"chuyên sản xuất các loại xe nhÆ°: Lexus, Camry, Vios, Altis,..","insertDate":"Sep 24, 2016","updateDate":"Sep 24, 2016","iconName":"http://192.168.1.221:9999/restfulspringmvc/images/luxus.jpg"}]


But Progress dialog is not stop with message:

"Loading manufacturers. Please wait..."


final exception in Logcat:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.totoroads.android.app, PID: 5730
java.lang.ClassCastException: java.util.HashMap cannot be cast to com.totoroads.android.app.ManufacturerFragment$MyAdapter$ManufacturerItem
at com.totoroads.android.app.ManufacturerFragment$MyAdapter.getView(FeedBackFragment.java:226)
at android.widget.AbsListView.obtainView(AbsListView.java:2346)
at android.widget.GridView.onMeasure(GridView.java:1065)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)


at line:

ManufacturerFragment.MyAdapter.ManufacturerItem item = (ManufacturerFragment.MyAdapter.ManufacturerItem)getItem(i);


There are some wrong I can not detect it, How to fix this the exception

Thank you so much!!

Answer

You didn't initialize your ArrayList before calling your AsyncTask. Add this line before executing the AsyncTask in onActivityCreated() :

manufacturersList = new ArrayList<>();

Edit 1: Assign your adapter to the variable:

adapter = new MyAdapter(getActivity(), manufacturersList);
gridView.setAdapter(adapter);

Because now you are notifying an empty adapter with the changes.

Edit 2: Your code never enters onPostExecute because you are not overriding the AsyncTask's onPostExecute method. Your AsyncTask is initialized as AsyncTask<String, String, String>, therefore onPostExecute's parameter should be a String, not a Void.

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);

    adapter.notifyDataSetChanged();
    // dismiss the dialog after getting all manufacturers
    if (pDialog.isShowing())
        pDialog.dismiss();
}

Edit 3: This is a working example of your getView method that you can start with:

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        View v = view;
        ImageView picture;
        TextView name, idTV;

        inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        v = inflater.inflate(R.layout.gridview_item, viewGroup, false);
        picture = (ImageView) v.findViewById(R.id.picture);
        name = (TextView) v.findViewById(R.id.manufacturer_name);
        idTV = (TextView) v.findViewById(R.id.manufacturer_id);

        HashMap<String, String> itemHash = (HashMap<String, String>) getItem(i);
        String nameString = itemHash.get(TAG_NAME);
        String iconUrl = itemHash.get(TAG_ICONNAME);
        String idString = itemHash.get(TAG_ID);

        // Use an image loader to load your Photo from URL.
        Picasso.with(context).load(iconUrl).into(picture);

        idTV.setText("ID: "+idString);
        name.setText("Name: "+nameString);
        return v;
    }