0

Solved! Look at the edit below!

I am trying to create a list view to show different type of layouts but am getting this error

(I am getting this error when I scroll up, after scrolling down and seeing both types of layouts)

E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.NullPointerException

I can scroll to the bottom and see both types of layouts (couldn't see them both at once (error) when the else statement with the comment "//THIS ONE!" want there)

Code for my adapter is as follows - (edited as with @matiash's suggestions)

    public class NewsAdapter extends ArrayAdapter<NewsXMLData> {

    ImageLoader imageLoader;
    DisplayImageOptions options;

    private static final int TYPE_ITEM = 0;
    private static final int TYPE_SEPARATOR = 1;
    private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;

    private LayoutInflater mInflater;

    public NewsAdapter(Context ctx, int textViewResourceId, List<NewsXMLData> sites) {
        super(ctx, textViewResourceId, sites);




        //Setup the ImageLoader, we'll use this to display our images
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(ctx).build();
        imageLoader = ImageLoader.getInstance();
        imageLoader.init(config);

        //Setup options for ImageLoader so it will handle caching for us.
        options = new DisplayImageOptions.Builder()
                .cacheInMemory()
                .cacheOnDisc()
                .build();


    }
    @Override
    public int getItemViewType(int position) {

       if(getItem(position).getType().equals("image")) {

            return TYPE_ITEM;

       }

       else{

            return TYPE_SEPARATOR;
       }
    }

    @Override
    public int getViewTypeCount() {
        return TYPE_MAX_COUNT;
    }
    public static class ViewHolder {
        public ImageView iconImg = null;
        public TextView contentTxt = null;
        public TextView imageTitleTxt = null ;
        public ProgressBar imageIndicator = null ;
        public TextView textTitleTxt = null ;
        public ProgressBar textIndicator = null;
    }




    String flag;
    //@Override
    public View getView(int pos, View convertView, ViewGroup parent){
        ViewHolder holder =null;
        int type = getItemViewType(pos);
        Log.i("APP", "getView " + pos + " " + convertView + " type = " + type);
        View row = convertView;

        mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        try {

            if (null == row) {
                //No recycled View, we have to inflate one.
                holder = new ViewHolder();
                switch (type){
                    case TYPE_ITEM:
                        row = (RelativeLayout) mInflater.inflate(R.layout.row_news, null);

                        holder.iconImg = (ImageView) row.findViewById(R.id.newsImageView);
                        holder.imageTitleTxt = (TextView) row.findViewById(R.id.newsTitleText);
                        holder.imageIndicator = (ProgressBar) row.findViewById(R.id.newsProgressBar);
                        holder.iconImg.setVisibility(View.INVISIBLE);
                        holder.imageIndicator.setVisibility(View.VISIBLE);
                        holder.imageTitleTxt.setVisibility(View.INVISIBLE);
                        //Setup a listener we can use to swtich from the loading indicator to the Image once it's ready
                        ImageLoadingListener listener = new ImageLoadingListener() {


                            @Override
                            public void onLoadingStarted(String arg0, View arg1) {
                                // TODO Auto-generated method stub

                            }

                            @Override
                            public void onLoadingCancelled(String arg0, View arg1) {
                                // TODO Auto-generated method stub

                            }

                            @Override
                            public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) {

                            }

                            @Override
                            public void onLoadingFailed(String arg0, View arg1, FailReason arg2) {
                                // TODO Auto-generated method stub
                            }

                        };
                        holder.iconImg.setVisibility(View.VISIBLE);
                        holder.imageIndicator.setVisibility(View.INVISIBLE);
                        holder.imageTitleTxt.setVisibility(View.VISIBLE);
                         //Load the image and use our options so caching is handled.
                        imageLoader.displayImage(getItem(pos).getImgUrl(), holder.iconImg, options, listener);
                        //Set the relavent text in our TextViews
                        holder.imageTitleTxt.setText(getItem(pos).getTitle());
                        break;
                    case TYPE_SEPARATOR:
                        row = (RelativeLayout) mInflater.inflate(R.layout.row_news_text, null);
                        holder.contentTxt = (TextView) row.findViewById(R.id.newsTextContentText);
                        holder.textTitleTxt = (TextView) row.findViewById(R.id.newsTextTitleText);
                        holder.textIndicator = (ProgressBar) row.findViewById(R.id.newsTextProgressBar);

                        /*holder.contentTxt.setVisibility(View.INVISIBLE);
                        holder.textIndicator.setVisibility(View.VISIBLE);
                        holder.textTitleTxt.setVisibility(View.INVISIBLE);*/


                        holder.contentTxt.setVisibility(View.VISIBLE);
                        holder.textIndicator.setVisibility(View.INVISIBLE);
                        holder.textTitleTxt.setVisibility(View.VISIBLE);
                        holder.textTitleTxt.setText(getItem(pos).getTitle());
                        holder.contentTxt.setText(getItem(pos).getContent());
                        break;
                }
                convertView.setTag(holder);
            }
            else{
                holder = (ViewHolder)convertView.getTag();

            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return row;


    }

}

Any suggestions?

Also, is there a better way to do it other than parsing XML and showing the content as a list view?

Edit: The code now works thanks to @Jens and @matiash Code:

public class NewsAdapter extends ArrayAdapter<NewsXMLData> {

    ImageLoader imageLoader;
    DisplayImageOptions options;

    private static final int TYPE_ITEM = 0;
    private static final int TYPE_SEPARATOR = 1;
    private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;

    private LayoutInflater mInflater;

    public NewsAdapter(Context ctx, int textViewResourceId, List<NewsXMLData> sites) {
        super(ctx, textViewResourceId, sites);




        //Setup the ImageLoader, we'll use this to display our images
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(ctx).build();
        imageLoader = ImageLoader.getInstance();
        imageLoader.init(config);

        //Setup options for ImageLoader so it will handle caching for us.
        options = new DisplayImageOptions.Builder()
                .cacheInMemory()
                .cacheOnDisc()
                .build();


    }
    @Override
    public int getItemViewType(int position) {

       if(getItem(position).getType().equals("image")) {

            return TYPE_ITEM;

       }

       else{

            return TYPE_SEPARATOR;
       }
    }

    @Override
    public int getViewTypeCount() {
        return TYPE_MAX_COUNT;
    }
    public static class ViewHolder {
        public ImageView iconImg = null;
        public TextView contentTxt = null;
        public TextView imageTitleTxt = null ;
        public ProgressBar imageIndicator = null ;
        public TextView textTitleTxt = null ;
        public ProgressBar textIndicator = null;
    }




    String flag;
    //@Override
    public View getView(int pos, View convertView, ViewGroup parent){
        ViewHolder holder =null;
        int type = getItemViewType(pos);
        //Log.i("APP", "getView " + pos + " " + convertView + " type = " + type);
        View row = convertView;

        mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        try {

            if (null == row) {
                //No recycled View, we have to inflate one.
                holder = new ViewHolder();
                switch (type) {
                    case TYPE_ITEM:
                        row = (RelativeLayout) mInflater.inflate(R.layout.row_news, null);


                        break;
                    case TYPE_SEPARATOR:
                        row = (RelativeLayout) mInflater.inflate(R.layout.row_news_text, null);

                        break;
                }
                //Log.i("APP","holder" + holder);
            }
                if(type==TYPE_ITEM){
                holder = new ViewHolder();
                holder.iconImg = (ImageView) row.findViewById(R.id.newsImageView);
                holder.imageTitleTxt = (TextView) row.findViewById(R.id.newsTitleText);
                holder.imageIndicator = (ProgressBar) row.findViewById(R.id.newsProgressBar);
                holder.iconImg.setVisibility(View.INVISIBLE);
                holder.imageIndicator.setVisibility(View.VISIBLE);
                holder.imageTitleTxt.setVisibility(View.INVISIBLE);
                //Setup a listener we can use to swtich from the loading indicator to the Image once it's ready
                ImageLoadingListener listener = new ImageLoadingListener() {


                    @Override
                    public void onLoadingStarted(String arg0, View arg1) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public void onLoadingCancelled(String arg0, View arg1) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) {

                    }

                    @Override
                    public void onLoadingFailed(String arg0, View arg1, FailReason arg2) {
                        // TODO Auto-generated method stub
                    }

                };
                holder.iconImg.setVisibility(View.VISIBLE);
                holder.imageIndicator.setVisibility(View.INVISIBLE);
                holder.imageTitleTxt.setVisibility(View.VISIBLE);
                //Load the image and use our options so caching is handled.
                imageLoader.displayImage(getItem(pos).getImgUrl(), holder.iconImg, options, listener);
                //Set the relavent text in our TextViews
                holder.imageTitleTxt.setText(getItem(pos).getTitle());
            }
            else if(type==TYPE_SEPARATOR){
                holder = new ViewHolder();
                holder.contentTxt = (TextView) row.findViewById(R.id.newsTextContentText);
                holder.textTitleTxt = (TextView) row.findViewById(R.id.newsTextTitleText);
                holder.textIndicator = (ProgressBar) row.findViewById(R.id.newsTextProgressBar);

                        /*holder.contentTxt.setVisibility(View.INVISIBLE);
                        holder.textIndicator.setVisibility(View.VISIBLE);
                        holder.textTitleTxt.setVisibility(View.INVISIBLE);*/


                holder.contentTxt.setVisibility(View.VISIBLE);
                holder.textIndicator.setVisibility(View.INVISIBLE);
                holder.textTitleTxt.setVisibility(View.VISIBLE);
                holder.textTitleTxt.setText(getItem(pos).getTitle());
                holder.contentTxt.setText(getItem(pos).getContent());
            }
        }
        catch(Exception e){
            e.printStackTrace();

        }
        return row;


    }

}
Maedr3
  • 3
  • 4
  • 2
    Is it string comparing `if(type=="image")` correctly? – Braj Jun 05 '14 at 18:54
  • Add a stacktrace please. In which line you get the NPE – Jens Jun 05 '14 at 18:58
  • @Braj Yes sir it is correct. – Maedr3 Jun 05 '14 at 19:27
  • @Jens How can I do that? – Maedr3 Jun 05 '14 at 19:31
  • @Jens I surrounded the whole function in a try block and now when I scroll up the list view some "image" layouts are getting swapped with "text" layouts. Still getting the same error in logcat. – Maedr3 Jun 05 '14 at 19:38
  • @user3712483 please post the logcat entry with the whole stacktrace. So we can help you. – Jens Jun 06 '14 at 04:40
  • @Jens I changed the code a bit as per matiash's comment. Here is the logcat - http://pastebin.com/PYgXF6ie now it is showing all the layouts properly but gives errors when the activity is launched (see logcat). – Maedr3 Jun 06 '14 at 08:32
  • You get the NPE in `com.justduthings.companion.NewsAdapter.getView(NewsAdapter.java:172)` Which line is it? – Jens Jun 06 '14 at 08:36
  • @Jens `convertView.setTag(holder);` this is line 172 currently. – Maedr3 Jun 06 '14 at 09:15
  • @user3712483 Looks like holder is null. Can you check this using the debugger? – Jens Jun 06 '14 at 09:20
  • @Jens Thanks a lot! It works now. I removed `convertView.setTag(holder);` and it works properly, without any errors now. Thanks a lot! – Maedr3 Jun 06 '14 at 09:40
  • Actually convertView is null here. you should be putting like `row.setTag(holder)`. On first run convertView will be null. – Dinesh Balu Jun 06 '14 at 09:49

2 Answers2

0

First of all, if (type=="image") or flag != type is not the correct way to compare Strings in Java. See How do I compare strings in Java?. This means that your code won't do what you expect, using the incorrect ifs all the way down

Secondly, for ListViews such as these, with "mixed" item views, there is a much more elegant (and built-in) solution. By implementing getViewTypeCount() (returning 2) and getItemViewType() (returning the type of each item) the framework can keep different recycling lists for the different view types.

This means that you can trust that when you get passed a non-null convertView, it will be one you inflated for the same item type (and you can dispense with the flag!=type check entirely).

Community
  • 1
  • 1
matiash
  • 54,791
  • 16
  • 125
  • 154
  • I edited the code (please see OP). I am still getting the error when I start the activity(Although the list is getting populated properly). After scrolling up and down a few times there are is no error. Logcat - http://pastebin.com/PYgXF6ie – Maedr3 Jun 06 '14 at 08:32
0

Holder is null. Can you check this using the debugger. Remove the line 172 in com.justduthings.companion.NewsAdapter.

Jens
  • 67,715
  • 15
  • 98
  • 113
  • Thanks for helping me out. One more question, I want to update "news" dynamically is there a better way to do this other than parsing XML and showing the content as a list view? – Maedr3 Jun 06 '14 at 09:46
  • Actually convertView is null here. you should be putting like `row.setTag(holder)`. On first run convertView will be null. – Dinesh Balu Jun 06 '14 at 09:52
  • @DineshBalu Why is setTag required? It is working fine without it. Please tell what is its function. – Maedr3 Jun 06 '14 at 09:57
  • Now your are not using the ViewHolder that you were using before. Why were you having a ViewHolder object?. The purpose of ViewHolder is that you don't have to do things like `findViewById` everytime the view is drawn. Now you are just creating a ViewHolder instance and assigning view references to it unnecessarily . You can create ViewHolder instance once , set it as tag for the row view and use it later to update the child views. – Dinesh Balu Jun 06 '14 at 10:12
  • @DineshBalu Is my way of doing it wrong? So, if I use setTag then I can put all the `findViewById` statements in `if (row==null)` block? – Maedr3 Jun 06 '14 at 10:19
  • You are not doing entirely wrong , just not the recommended best way.Yes you can. Otherwise how are you gonna update row on scrolling now !!! – Dinesh Balu Jun 06 '14 at 10:53