Search code examples
androidlistadapter

Why am I getting an NPE error when using my custom listview adapter?


This would be a lengthy question with lots of code in it so to those who would take time to read it Thank you so much!

So basically I have an application made using Eclipse. The MAIN ACTIVITY is extended as FragmentActivity, called MenuMain.java. This activity have three fragments defined in its xml. And the one I am having problems with is the third one.

What I want to do is when the user clicks a button on the middle fragment, it would add content into a custom listview which is the third fragment.

Here is my class for displaying the content on the middle fragment.

ImageFragment.java

package com.thesis.menubook;

import java.util.ArrayList;

import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class ImageFragment extends Fragment {

      ProgressDialog pDialog;
      private  int imageResourceId;
      private ArrayList<String> menu_id =  new ArrayList<String>();
      private ArrayList<String> menu_name =  new ArrayList<String>();
      private ArrayList<String> menu_description =  new ArrayList<String>();
      int page = 0;
      String orderQuantity = "";
      EditText quantity;
      ListView lv;
    public ImageFragment(int imageResource, ArrayList<String> mid, ArrayList<String> mname, ArrayList<String> mdesc, int pg) {
        this.imageResourceId = imageResource;    
        this.menu_id = mid;
        this.menu_name = mname;
        this.menu_description = mdesc;
        this.page = pg;
    }

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

    }

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

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.layout_menu, container, false);

        Button next = (Button)view.findViewById(R.id.next);
        Button back = (Button)view.findViewById(R.id.back);
        Button add = (Button)view.findViewById(R.id.add);

        quantity = (EditText) view.findViewById(R.id.editText1);

        RelativeLayout layout = (RelativeLayout) view.findViewById(R.id.main_layout);
        layout.setBackgroundResource(imageResourceId);

        //Change ID on Layout
        TextView id = (TextView) view.findViewById(R.id.menu_id);
        id.setText(menu_id.get(page));

        //Change name on layout
        TextView name = (TextView) view.findViewById(R.id.menu_name);
        name.setText(menu_name.get(page));

        //change description on layout
        TextView desc = (TextView) view.findViewById(R.id.menu_description);
        desc.setText(menu_description.get(page));

        // set next page button listener
                next.setOnClickListener(new View.OnClickListener(){
                    @Override
                    public void onClick(View v){
                        if(page < menu_id.size()-1)
                        {
                            page++;
                            Toast.makeText(getActivity(), "Next", Toast.LENGTH_LONG).show();
                            loadMenuItem(page);
                        }
                        else
                        {
                            Toast.makeText(getActivity(), "You are at the end of the page", Toast.LENGTH_LONG).show();
                        }
                    }
                });
        // set back page button listener
                back.setOnClickListener(new View.OnClickListener(){
                    @Override
                    public void onClick(View v){
                        if(page != 0)
                        {
                            page--;
                            Toast.makeText(getActivity(), "Next", Toast.LENGTH_LONG).show();
                            loadMenuItem(page);
                        }
                        else
                        {
                            Toast.makeText(getActivity(), "You are at the start of the page", Toast.LENGTH_LONG).show();
                        }
                    }
                });

                //set add to orderlist button listener
                add.setOnClickListener( new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        if(quantity.getText().toString() != "" || quantity.getText().toString() != "0" || quantity.getText().toString() != "00"){
                            lv = (ListView) v.findViewById(R.id.orderListView);
                            new AddToList().execute("");
                        }
                        else
                        {
                            Toast.makeText(getActivity(), "Please put quantity", Toast.LENGTH_LONG).show();
                        }
                    }
                });

        return view;


}
    public void loadMenuItem(int pahina) {

        FragmentManager fm = getFragmentManager();

        if (fm != null) {

            FragmentTransaction ft = fm.beginTransaction();
            ft.replace(R.id.menu_fragment, new ImageFragment(R.drawable.caesar_salad, menu_id, menu_name,menu_description, pahina));
            ft.commit();
        }
    }

    class AddToList extends AsyncTask<String, String, String> {
        ArrayList<DataArray> dataArray = new ArrayList<DataArray>();
        DataArray data = new DataArray();
        /**
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() {
             super.onPreExecute();
             pDialog = new ProgressDialog(getActivity());
             Log.d("Activity Context", getActivity().toString() + "");
             pDialog.setMessage("Adding to list. Please wait...");
             pDialog.setIndeterminate(false);
             pDialog.setCancelable(false);
             pDialog.show();
        }

        /**
         * Getting product details in background thread
         * */
        protected String doInBackground(String... param) {

            data.setID(menu_id.get(page));
            data.setName(menu_name.get(page));
            data.setQuantity(quantity.getText().toString());
            dataArray.add(data);
            Log.d("Order Data ID: ", data.getID() + "");
            Log.d("Order Data Name: ", data.getName() + "");
            Log.d("Order Data Quantity: ", data.getQuantity() + "");
            return null;
        }

        /**
         * After completing background task Dismiss the progress dialog
         * **/
        @Override
        protected void onPostExecute(String result) {
            pDialog.dismiss();
            lv.setAdapter(new MyCustomAdapter(getActivity(), dataArray));
        }

    }

} 

I get an error here when I call my custom adapter in this line lv.setAdapter(new MyCustomAdapter(getActivity(), dataArray)); which is on the onPostExecute()

I define my custom adapter like this

MyCustomAdapter.java

package com.thesis.menubook;

import java.util.ArrayList;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MyCustomAdapter extends BaseAdapter {
    private static ArrayList<DataArray> orderData;

    private LayoutInflater mInflater;

    public MyCustomAdapter(Context context, ArrayList<DataArray> passed) {
        orderData = passed;
        mInflater = LayoutInflater.from(context);
    }

    public int getCount() {
        return orderData.size();
    }

    public Object getItem(int position) {
        return orderData.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.custom_order_list, null);
            holder = new ViewHolder();
            holder.txtID = (TextView) convertView.findViewById(R.id.id);
            holder.txtName = (TextView) convertView.findViewById(R.id.name);
            holder.txtQuantity = (TextView) convertView.findViewById(R.id.quantity);

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

        holder.txtID.setText(orderData.get(position).getID());
        holder.txtName.setText(orderData.get(position).getName());
        holder.txtQuantity.setText(orderData.get(position).getQuantity());

        return convertView;
    }

    static class ViewHolder {
        TextView txtID;
        TextView txtName;
        TextView txtQuantity;
    }
}

And my custom variable DataArray.java is like this. I have no problems with DataArray though as it logs content so I am sure the NPE error does not refer to my use of this class

package com.thesis.menubook;

public class DataArray {

    private String menu_ID = "";
    private String menu_name = "";
    private String quantity = "";

    public void setID(String ID) {
     this.menu_ID = ID;
    }

    public String getID() {
     return menu_ID;
    }

    public void setName(String menu_name) {
     this.menu_name = menu_name;
    }

    public String getName() {
     return menu_name;
    }
    public void setQuantity(String quantity) {
     this.quantity = quantity;
    }
    public String getQuantity(){
        return quantity;
    }

}

I think the problem is because of the getActivity() in this line lv.setAdapter(new MyCustomAdapter(getActivity(), dataArray)); on ImageFragment. I have tried:

getActivity().getApplicationCOntext()
getActivity().getBaseContext()
getActivity().getParent().getApplicationContext()
getActivity().getParent().getBaseContext()

to NO avail.

So how do I get around this?

Here are the other less important classes and xml files which you may need to analyze to help me.

OrderListFragment.java

package com.thesis.menubook;

import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class OrderListFragment extends Fragment{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.activity_order_list, container, false);
        return view;
    }
}

activity_order_list.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/orderlist"
        android:layout_width="505dp"
        android:layout_height="wrap_content"
        android:paddingLeft="6dip"
        android:paddingTop="6dip"
        android:text="@string/orderlist"
        android:textSize="17sp"
        android:textStyle="bold" />
    <ListView
        android:id="@+id/orderListView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

custom_order_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:paddingBottom="10dip"
    android:paddingLeft="10dip"
    android:paddingTop="10dip" >

    <TextView
        android:id="@+id/id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#C20000"
        android:textSize="14sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/quantity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

activity_menu_main.xml

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

     <fragment
         android:id="@+id/menu_category_fragment"
         android:name="com.thesis.menubook.MenuCategory"
         android:layout_width="0dip"
         android:layout_height="match_parent"
         android:layout_weight="0.14"
         layout="@layout/activity_menu_category" />

     <fragment
         android:id="@+id/menu_fragment"
         android:name="com.thesis.menubook.MenuFragment"
         android:layout_width="0dip"
         android:layout_height="match_parent"
         android:layout_weight="0.71"
         layout="@layout/activity_menu_fragment" />


     <fragment
         android:id="@+id/orderlist_fragment"
         android:name="com.thesis.menubook.OrderListFragment"
         android:layout_width="167dp"
         android:layout_height="match_parent"
         layout="@layout/activity_order_list" />

</LinearLayout>

layout_menu.xml (the middle fragment content xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/caesar_salad"
    android:gravity="top|bottom|center_vertical"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    android:visibility="visible" >

    <TextView 
        android:id="@+id/menu_name" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="@string/menu_name" 
        android:textSize="40sp"
        android:background="#2f000000" android:textColor = "@android:color/white"/>

    <TextView 
        android:id="@+id/menu_id" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="@string/menu_name" 
        android:textSize="40sp"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@+id/menu_name"
        android:background="#2f000000" android:textColor = "@android:color/white"
        android:visibility="invisible"/>

    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tableLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_below="@+id/menu_name"
    android:layout_marginTop="20dp" >


    <TableRow
        android:id="@+id/tableRow1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

       <TextView 
        android:id="@+id/menu_description" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:background="#2f000000"  
        android:textColor="@android:color/white" 
        android:textSize="20sp" 
        android:textStyle="italic" 
        android:typeface="sans"
        android:text ="@string/menu_description"
        android:layout_margin="10dp">

    </TextView>

         <TextView 
        android:id="@+id/menu_price" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:background="#2f000000"  
        android:textColor="@android:color/white" 
        android:textSize="20sp" 
        android:textStyle="italic" 
        android:typeface="sans"
        android:text ="@string/menu_price"
        android:layout_margin="10dp"/>


        </TableRow>

    </TableLayout>


    <TextView 
        android:id="@+id/quantity" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignLeft="@+id/menu_description" 
        android:layout_alignParentBottom="true" 
        android:layout_marginBottom="20dp" 
        android:background="#2f000000" 
        android:text="@string/quantity" 
        android:textColor="@android:color/white" 
        android:textSize="25sp" 
        android:textStyle="italic" 
        android:typeface="sans"/>


    <EditText 
        android:id="@+id/editText1" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignBottom="@+id/quantity" 
        android:layout_alignTop="@+id/quantity" 
        android:layout_centerHorizontal="true" 
        android:layout_toRightOf="@+id/quantity" 
        android:layout_marginLeft="5dp" 
        android:background="@android:color/white" 
        android:ems="2" 
        android:maxLength="2"
        android:inputType="number">
        <requestFocus />
    </EditText>

    <Button 
        android:id="@+id/add" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignBaseline="@+id/editText1" 
        android:layout_toRightOf="@+id/editText1" 
        android:layout_centerHorizontal="true" 
        android:text="@string/add" 
        android:textColor="@android:color/white"/>

    <Button
        android:id="@+id/next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/tableLayout1"
        android:layout_alignRight="@+id/tableLayout1"
        android:layout_marginRight="42dp"
        android:text="@string/next"
        android:textSize="20sp" />

    <Button
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/tableLayout1"
        android:layout_marginRight="26dp"
        android:layout_toLeftOf="@+id/next"
        android:text="@string/back"
        android:textSize="20sp" />

</RelativeLayout>

Here is my LogCat

02-16 13:25:25.541: D/Order Data ID:(502): 001
02-16 13:25:25.541: D/Order Data Name:(502): Chicken
02-16 13:25:25.541: D/Order Data Quantity:(502): 8
02-16 13:25:25.865: E/AndroidRuntime(502): FATAL EXCEPTION: main
02-16 13:25:25.865: E/AndroidRuntime(502): java.lang.NullPointerException
02-16 13:25:25.865: E/AndroidRuntime(502):  at com.thesis.menubook.ImageFragment$AddToList.onPostExecute(ImageFragment.java:182)
02-16 13:25:25.865: E/AndroidRuntime(502):  at com.thesis.menubook.ImageFragment$AddToList.onPostExecute(ImageFragment.java:1)
02-16 13:25:25.865: E/AndroidRuntime(502):  at android.os.AsyncTask.finish(AsyncTask.java:590)
02-16 13:25:25.865: E/AndroidRuntime(502):  at android.os.AsyncTask.access$600(AsyncTask.java:149)
02-16 13:25:25.865: E/AndroidRuntime(502):  at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:603)
02-16 13:25:25.865: E/AndroidRuntime(502):  at android.os.Handler.dispatchMessage(Handler.java:99)
02-16 13:25:25.865: E/AndroidRuntime(502):  at android.os.Looper.loop(Looper.java:132)
02-16 13:25:25.865: E/AndroidRuntime(502):  at android.app.ActivityThread.main(ActivityThread.java:4025)
02-16 13:25:25.865: E/AndroidRuntime(502):  at java.lang.reflect.Method.invokeNative(Native Method)
02-16 13:25:25.865: E/AndroidRuntime(502):  at java.lang.reflect.Method.invoke(Method.java:491)
02-16 13:25:25.865: E/AndroidRuntime(502):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
02-16 13:25:25.865: E/AndroidRuntime(502):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
02-16 13:25:25.865: E/AndroidRuntime(502):  at dalvik.system.NativeStart.main(Native Method)
02-16 13:25:26.587: D/dalvikvm(502): GC_CONCURRENT freed 126K, 7% free 7635K/8199K, paused 23ms+35ms
02-16 13:25:32.642: I/Process(502): Sending signal. PID: 502 SIG: 9

Solution

  • I'm not entirely sure I understand what you are trying to accomplish but it seems to me that your list view is actually null. If I'm not mistaken you only initialize it on the add button onclicklistener and use the view that is passed along to look for the list in its hierarchy. The onClickListener is passed the actual view that was clicked and, as far as I know, you can't have a list view as a child of that button view and so the findViewById method returns null. Either initialize the list view along with the buttons or make sure you get the proper parent view of the list in order to load it at the button click.