简体   繁体   中英

ListView with customAdapter not updated when notifyDataSetChanged is called?

I have a Listview with two adapters. They receive an Array with some data and when scrolled to bottom of the listview more data is loaded into the Array and here the listview should add the new data.

Question: How can I make the listview reflect the new data and why isn't it updated when I call adAdapter.notifyDataSetChanged(); ?

Fragments inner class where I download data & update UI in onPostExecute:

@Override
    protected void onPostExecute(String result) {

        super.onPostExecute(result);

        numberofpagesshown = numberofpagesshown + 1;

        if(numberofpagesshown == 1 ) {

            list = (ListView) getActivity().findViewById(R.id.search_listview_movie);

            adapter = new SearchListViewAdapter(getActivity(), mylist);

            adAdapter = new BannerAdListView2(getActivity(), adapter);

           // list.setAdapter(adapter); this works when adapter.notifyDataSetChanged(); also is in the else statement but here I don't use the BannerAdListView2 adapter which i want to?

list.setAdapter(adAdapter);

            bar.setVisibility(View.GONE);
        }
        else {

          //  adapter.notifyDataSetChanged();   // Here the listview should get refresh with the new data

              adAdapter.notifyDataSetChanged();

            bar.setVisibility(View.GONE);

        }


        // Attach the listener to the AdapterView onCreate
        list.setOnScrollListener(new EndlessScrollListener() {
            @Override
            public void onLoadMore(int page, int totalItemsCount) {
                // Triggered only when new data needs to be appended to the list
                // Append new items to AdapterView
                if(pageNumberInt < totalPagesInt){

                   ++incre;
                   new DownloadJSON().execute();
                }

            }
        });


    }

Here is my SearchListViewAdapter:

public class SearchListViewAdapter extends BaseAdapter{

Context context;
ArrayList<HashMap<String, String>> data;
HashMap<String, String> mylist = new HashMap<>();


static String url;
static String title;

public SearchListViewAdapter(Context a, ArrayList<HashMap<String, String>> d) {
    context = a;
    data = d;
}

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

public HashMap<String, String> getItem(int position) {
    return data.get(position);
}

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

public View getView(final int position, View convertView, ViewGroup parent) {

    // Avoid unneccessary calls to findViewById() on each row
    final ViewHolder holder;

    /*
     * If convertView is not null, reuse it directly, no inflation
     * Only inflate a new View when the convertView is null.
     */

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.search_list_item, parent, false);

            holder = new ViewHolder();

            holder.poster = (ImageView) convertView.findViewById(R.id.list_image);

            holder.textForTitle = (TextView) convertView.findViewById(R.id.search_title);

            holder.textForTitle.setTag(position);

            convertView.setTag(holder);
        }
        else{

            // Get the ViewHolder back to get fast access to the TextView
            // and the ImageView.
            holder = (ViewHolder) convertView.getTag();
            holder.textForTitle.setTag(data.get(position));
        }



        mylist = data.get(position);


        final String mediaType = mylist.get("media_type");

        if (mediaType.equals("movie")) {

            String posterPath = mylist.get("poster_path");
            url = "http://image.tmdb.org/t/p/w185" + posterPath;
            title = mylist.get("title");
        } else if (mediaType.equals("tv")) {

            String posterPath = mylist.get("poster_path");
            url = "http://image.tmdb.org/t/p/w185" + posterPath;
            title = mylist.get("original_name");
        } else {

            String posterPath = mylist.get("profile_path");
            url = "http://image.tmdb.org/t/p/w185" + posterPath;
            title = mylist.get("name");

        }


        // set image url correctly
        // sizes for image 45, 92, 154, 185, 300, 500


        // load image url into poster
        Picasso.with(context).load(url).into(holder.poster);

        // set title to textview

        holder.textForTitle.setText(title);





    return convertView;


}



class ViewHolder {
    ImageView poster;
    TextView textForTitle;
}

 }

And my BannerAdListView2 adapter:

public class BannerAdListView2 extends BaseAdapter
     {

Activity activity;
Context context;
BaseAdapter delegate;
int k = 7;
int baseItems;
int noAds;



// Constructor takes in a BaseAdapter
public BannerAdListView2(Activity activity, BaseAdapter delegate ) {

    this.activity = activity;
    this.delegate = delegate;

    baseItems = delegate.getCount();
    noAds  = baseItems / k;
    LayoutInflater mLayoutInflater = (LayoutInflater) this.activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

}


         @Override
         public int getCount() {
             // Total count includes list items and ads.
             return baseItems + noAds;
         }

         @Override
         public Object getItem(int position) {
             // Return null if an item is an ad.  Otherwise return the delegate item.
             if (isItemAnAd(position)) {
                 return null;
             }
             return delegate.getItem(getOffsetPosition(position));
         }

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

         @Override
         public int getViewTypeCount() {
             return delegate.getViewTypeCount() + noAds;
         }

         @Override
         public int getItemViewType(int position) {
             if (isItemAnAd(position)) {
                 return delegate.getViewTypeCount();
             } else {
                 return delegate.getItemViewType(getOffsetPosition(position));
             }
         }

         @Override
         public boolean areAllItemsEnabled() {
             return false;
         }

         @Override
         public boolean isEnabled(int position) {
             return (!isItemAnAd(position)) && delegate.isEnabled(getOffsetPosition(position));
         }

         private boolean isItemAnAd(int position) {


             if (position < k) return false;
             // Calculate current offset caused by ads already embedded

             if (position==k){
                 return true;
             }
             else {
                 return isItemAnAd(position-k);
             }


         }

         // Get the position that is offset by the insertion of the ads
         private int getOffsetPosition(int position) {
             int currentNoAds = position / k;
             return position - currentNoAds;

         }



         @Override
         public View getView(int position, View convertView, ViewGroup parent) {

             // Display every n list items
             if (isItemAnAd(position)) {
                 if (convertView instanceof AdView) {
                     // Don’t instantiate new AdView, reuse old one
                     return convertView;
                 } else {
                     // Create a new AdView
                     AdView adView = new AdView(activity);
                     adView.setAdSize(AdSize.BANNER);
                     String bannerId = "My unit id";
                     adView.setAdUnitId(bannerId);

                     // Disable focus for sub-views of the AdView to avoid problems with
                     // trackpad navigation of the list.
                     for (int i = 0; i < adView.getChildCount(); i++)
                     {
                         adView.getChildAt(i).setFocusable(false);
                     }
                     adView.setFocusable(false);

                     // Convert the default layout parameters so that they play nice with
                     // ListView.

                     float density = activity.getResources().getDisplayMetrics().density;
                     int height = Math.round(AdSize.BANNER.getHeight() * density);
                     AbsListView.LayoutParams params = new AbsListView.LayoutParams(
                             AbsListView.LayoutParams.MATCH_PARENT,
                             height);
                     adView.setLayoutParams(params);
                     AdRequest bannerIntermediateReq = new AdRequest.Builder()
                             .addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
                             .addTestDevice("d9e108ab") //means that a test ad is shown on my phone
                             .build();

                     adView.loadAd(bannerIntermediateReq);

                     return adView;
                 }
             } else {

                 // Offload displaying other items to the delegate
                 return delegate.getView(getOffsetPosition(position) ,
                         convertView, parent);

             }
         }
     }

Edit: Changed the constructor of BannerAdListView2

 // Constructor takes in a BaseAdapter
public BannerAdListView2(Activity activity, final BaseAdapter delegate ) {

    this.activity = activity;
    this.delegate = delegate;
    delegate.registerDataSetObserver(new DataSetObserver() {
        public void onChanged() {
            baseItems = delegate.getCount();
            noAds = baseItems / k;
        }

        public void onInvalidated() {
            notifyDataSetInvalidated();
        }
    });
    baseItems = delegate.getCount();
    noAds  = baseItems / k;
    LayoutInflater mLayoutInflater = (LayoutInflater) this.activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

}

And in fragment

@Override
    protected void onPostExecute(String result) {

        super.onPostExecute(result);

        numberofpagesshown = numberofpagesshown + 1;

        if(numberofpagesshown == 1 ) {

            list = (ListView) getActivity().findViewById(R.id.search_listview_movie);

            adapter = new SearchListViewAdapter(getActivity(), mylist);

            adAdapter = new BannerAdListView2(getActivity(), adapter);

            list.setAdapter(adAdapter);

            bar.setVisibility(View.GONE);
        }
        else {

            adapter.notifyDataSetChanged();   

            bar.setVisibility(View.GONE);

        }

     }

Try this solution ... DecorerAdapter:

public static abstract class DecorerAdapter extends BaseAdapter {

            public int DECORER_ITEM_TYPE;
            private final BaseAdapter mInnerAdapter;
            private final int mRepeatAfterEvery;
            private int mCount;

            public DecorerAdapter(BaseAdapter innerAdapter, int repeatAfterEvery) {
                mInnerAdapter = innerAdapter;
                mRepeatAfterEvery = repeatAfterEvery;
                mInnerAdapter.registerDataSetObserver(new DataSetObserver() {
                    @Override
                    public void onChanged() {
                        notifyDataSetChanged();
                    }

                    @Override
                    public void onInvalidated() {
                        notifyDataSetInvalidated();
                    }
                });
                setupAdapter();
            }

            @Override
            public void notifyDataSetChanged() {
                setupAdapter();
                super.notifyDataSetChanged();
            }

            private void setupAdapter(){
                mCount = mInnerAdapter.getCount();
                mCount += (mCount  + mRepeatAfterEvery - 2) / (mRepeatAfterEvery - 1);
                DECORER_ITEM_TYPE = mInnerAdapter.getViewTypeCount();
            }

            @Override
            public int getCount() {
                return mCount;
            }

            @Override
            public Object getItem(int position) {
                if(position % mRepeatAfterEvery == 0)
                    return null;
                return mInnerAdapter.getItem(calculateInnerPosition(position));
            }

            private int calculateInnerPosition(int position) {
                return position - (position  + mRepeatAfterEvery - 1) / mRepeatAfterEvery;
            }

            @Override
            public long getItemId(int position) {
                if(position % mRepeatAfterEvery == 0)
                    return -1;
                return mInnerAdapter.getItemId(calculateInnerPosition(position));
            }

            @Override
            public int getItemViewType(int position) {
                if(position % mRepeatAfterEvery == 0)
                    return DECORER_ITEM_TYPE;
                return mInnerAdapter.getItemViewType(calculateInnerPosition(position));
            }

            @Override
            public boolean hasStableIds() {
                return mInnerAdapter.hasStableIds();
            }

            @Override
            public int getViewTypeCount() {
                return mInnerAdapter.getViewTypeCount() + 1;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                if(position % mRepeatAfterEvery == 0)
                    return getDecorerView((position  + mRepeatAfterEvery - 1) / mRepeatAfterEvery, convertView, parent);
                return mInnerAdapter.getView(calculateInnerPosition( position), convertView, parent);
            }

            public abstract View getDecorerView(int position, View convertView, ViewGroup parent);
        }

code with usage:

package pl.selvin.decoreradapter;

import android.database.DataSetObserver;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class MainActivity extends AppCompatActivity {

    /*** paste the DecorerAdapter class here ***/

    public static class MyListFragment extends ListFragment{
        final ArrayList<String> strings = new ArrayList<>();
        private BaseAdapter innerAdapter;

        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            menu.add("Add rnd(10) more");

            super.onCreateOptionsMenu(menu, inflater);
        }

        final Random rnd = new Random();
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            final String[] toAdd = new String[rnd.nextInt(10)];
            int start = strings.size();
            for(int i = 0; i < toAdd.length; i++)
                toAdd[i] = (start + i) + "";
            Collections.addAll(strings, toAdd);
            Toast.makeText(getActivity(), "Added " + toAdd.length + " count: " + strings.size(), Toast.LENGTH_SHORT).show();
            innerAdapter.notifyDataSetChanged();
            return true;
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setHasOptionsMenu(true);
            for(int i = 0; i < 4; i++) {
                strings.add(i + "");
            }
            innerAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, strings);
            setListAdapter(new DecorerAdapter(innerAdapter, 5) {
                @Override
                public View getDecorerView(int position, View convertView, ViewGroup parent) {
                    if(convertView == null) {
                        convertView = new TextView(getActivity());
                        convertView.setBackgroundColor(Color.RED);
                    }
                    ((TextView)convertView).setText("AdView: " + position);
                    return convertView;
                }
            });
        }

        @Override
        public void onListItemClick(ListView l, View v, int position, long id) {
            String item = (String)l.getItemAtPosition(position);
            Toast.makeText(getActivity(), "Item click: " + (item == null ? "ADVIEW" : item), Toast.LENGTH_LONG).show();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction().replace(android.R.id.content, new MyListFragment(), "LIST").commit();
        }
    }
}

It repeats decorer view at every element passed to the constructor ...

all you need to do is implement getDecorerView in the similar way as getView in normal adapter

看起来如何?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM