6

I have listview with cursoradapter. Now i want to implement native express ads in listview.

I have seen the implementation of Native ads with simple baseAdapter,in that generally we are using List<Object> for passing data to adapter and check type of item inside getView() method to add ads.

 @Override
public View getView(int position, View convertView, ViewGroup parent)
        throws IllegalArgumentException {
    Object item = getItem(position);

    if (item instanceof Listing) {
        // Listing items already have all the data required, so they just need to be displayed.
                  return listingLayout;
    } else if (item instanceof AdPlacement) {
        return ((AdPlacement) item).getView(convertView, parent);
    } else {
        // Any unknown items will cause exceptions, though this shouldn't ever happen.
        throw new IllegalArgumentException(
                String.format("Adapter can't handle getView() for list item of type %s",
                        item.getClass().getName()));
    }


}

How to check this condition in cursoradapter as cursoradapter only have method newItem() with cursor details

 @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View v = LayoutInflater.from(context).inflate(R.layout.list_item_station, parent, false);
        ViewHolder holder = new ViewHolder();

        v.setTag(holder);
        return v;
    }

How to add native ads after every 10 items in cursoradapter

Bellow is the current code i am using to add data in the list.

public class StationsCursorAdapter extends CursorAdapter{


    public StationsCursorAdapter(Context context) {
        super(context, null, true);
            }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View v = LayoutInflater.from(context).inflate(R.layout.list_item_station, parent, false);
        ViewHolder holder = new ViewHolder();

        v.setTag(holder);
        return v;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ViewHolder holder = (ViewHolder) view.getTag();
        holder.titleTextView.setText(cursor.getString(cursor.getColumnIndex(Station.NAME)));
    }

    private static final class ViewHolder {
               TextView titleTextView;
           }

}

3 Answers3

1

Implementation View Item type a little another. You should define different types of layout, and inflating. Take a look RecyclerView Item Type.

After you create correct View Inflating, you can check type in OnBind method, and implement another behavior for each View.

@Override
public void bindView(View view, Context context, Cursor cursor) {
    ViewHolder holder = (ViewHolder) view.getTag();
    if (holder instance of Dog) {
         // Handle one case
    } else {
         // Handle other case
    }
}
CL.
  • 158,085
  • 15
  • 181
  • 214
GensaGames
  • 4,757
  • 1
  • 17
  • 43
  • But how can i set viewType when we are using curson adapter? – Om Infowave Developers Jun 12 '17 at 11:50
  • @OmInfowaveDevelopers Basically, you create several ViewHolder. Each for your implementation. ViewHolderDog, ViewHolderCat. In `NewView` you will fetch some info about type from Cursor, and then return special ViewHolder Type. Then in `OnBind`, you will receive ViewHolder, and you will check what is the type. – GensaGames Jun 12 '17 at 12:09
  • 1
    ,But issue is CursorAdpater it directly pass the cursor to adapter,suppose there is 22 items in local database then cursor size is 22 then adapter size is also 22 ,now i want add ads after every 10 item so adapter size must me 24. How to add this two extra item in cursor adapter as we are not able to modify the Cursor value – Om Infowave Developers Jun 12 '17 at 12:15
  • @OmInfowaveDevelopers Oh, I suppose it will be some workaround with `getHeaderView` and `getHeaderId` with https://github.com/emilsjolander/StickyListHeaders. – GensaGames Jun 12 '17 at 12:40
  • @OmInfowaveDevelopers I still thinking, about it, but so far, even Custom Items in Cursor will be bad ideas. Event better jsut implement your own loading with simple RecyclerAdapter. And without this vehicle. – GensaGames Jun 12 '17 at 12:41
  • how github.com/emilsjolander/StickyListHeaders. is useful? – Om Infowave Developers Jun 12 '17 at 12:44
  • @OmInfowaveDevelopers You can implement their ListView item in XML. And then implement interface with Headers in your CursorAdapter. – GensaGames Jun 12 '17 at 12:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/146473/discussion-between-om-infowave-developers-and-gensagames). – Om Infowave Developers Jun 13 '17 at 03:24
1

create file list_item_native_ad.xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="132dp">

    <com.google.android.gms.ads.NativeExpressAdView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/nativeAd"
        ads:adSize="FULL_WIDTHx132"
        ads:adUnitId="@string/native_ad_unit_id"/>
</LinearLayout>

Create NativeAdViewHelperinside your adapter.

public class NativeAdViewHolder extends RecyclerView.ViewHolder {

        private final NativeExpressAdView mNativeAd;

        public NativeAdViewHolder(View itemView) {
            super(itemView);
            mNativeAd = (NativeExpressAdView) itemView.findViewById(R.id.nativeAd);
            mNativeAd.setAdListener(new AdListener() {
                @Override
                public void onAdLoaded() {
                    super.onAdLoaded();
                    if (mItemClickListener != null) {
                        Log.i(TAG, "onAdLoaded");
                    }
                }

                @Override
                public void onAdClosed() {
                    super.onAdClosed();
                    if (mItemClickListener != null) {
                        Log.i(TAG, "onAdClosed");
                    }
                }

                @Override
                public void onAdFailedToLoad(int errorCode) {
                    super.onAdFailedToLoad(errorCode);
                    if (mItemClickListener != null) {
                        Log.i(TAG, "onAdFailedToLoad");
                    }
                }

                @Override
                public void onAdLeftApplication() {
                    super.onAdLeftApplication();
                    if (mItemClickListener != null) {
                        Log.i(TAG, "onAdLeftApplication");
                    }
                }

                @Override
                public void onAdOpened() {
                    super.onAdOpened();
                    if (mItemClickListener != null) {
                        Log.i(TAG, "onAdOpened");
                    }
                }
            });
            AdRequest adRequest = new AdRequest.Builder()
                    .addTestDevice(MainActivity.TEST_DEVICE_ID)
                    .build();
            //You can add the following code if you are testing in an emulator
            /*AdRequest adRequest = new AdRequest.Builder()
                .addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
                .build();*/
            mNativeAd.loadAd(adRequest);
        }
    }

Override method getItemViewType() inside your adapter

@Override
    public int getItemViewType(int position) {
        if (position>1 && position % 3 == 0) {//in your case replace % 3 with % 10.
            return NATIVE_AD_VIEW_TYPE;
        }
        return DEFAULT_VIEW_TYPE;
    }

Override method getViewTypeCount()

@Override
public int getViewTypeCount() {
            return 2;
        }

inside your newView() method

@Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view;
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        switch (viewType) {
            default:
                view = layoutInflater
                        .inflate(R.id.content, parent, false);
                return new ViewHolder(view);
            case NATIVE_AD_VIEW_TYPE:
                view = layoutInflater.inflate(R.layout.list_item_native_ad, parent, false);
                return new NativeAdViewHolder(view);
        }
    }

inside your bindView() method

@Override
    public void bindView(View view, Context context, Cursor cursor) {
        if (!(holder instanceof ViewHolder)) {
            return;
        }
        holder.titleTextView.setText(cursor.getString(cursor.getColumnIndex(Station.NAME)));
    }

Hope it will help you!

N.Droid
  • 1,982
  • 15
  • 28
  • thank you for reply.Issue is that suppose there are 15 items in cursor then it call newView() method for 15 times only how to call this method one extra time for return view of ads from newView() method. – Om Infowave Developers Jun 17 '17 at 03:41
  • @OmInfowaveDevelopers can you please accept the answer if it worked for you – N.Droid Jun 19 '17 at 08:39
  • there is no method getItemCount() that's why we are not able to modify the size of list.size of list is define from the cursor size – Om Infowave Developers Jun 20 '17 at 07:11
1

I ll suggest you not to use cursor adapter for this case, as it will be inefficient, rather you should fetch data from Database to a list, and use CustomAdapter extending BaseAdapter to bind views accordingly.

And if you have to use cursor adapter only, then you need to modify your cursor data to have ads item at every 10th position. You could alter your cursor like :

    public Cursor getModifiedCursorWithAds(Cursor cursor) {
        int size = cursor.getCount();
        MatrixCursor matrixCursor = new MatrixCursor(cursor.getColumnNames());
        int totalAds = size / 10;
        int negativeIds = -1;
        cursor.moveToFirst();
        //assuming only two columns in cursor
        for (int i = 0; i < (size + totalAds); i++) {
            if (i % 10 == 0 && i != 0) {
                matrixCursor.addRow(new String[]{"" + negativeIds--, "Ads data"}); //add dummy data for displaying ads(on the basis of negative ids, ad will be displayed
            } else {
                matrixCursor.addRow(new String[]{cursor.getString(0), cursor.getString(1)}); //add data from actual cursor, if you have more than 2 data modify this statement
                cursor.moveToNext();
            }
        }
        cursor.close();
        return matrixCursor;
    }

Modify you newView to return different view for ads and other items and bind accordinly in bindView callback.

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view;
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        int viewType = cursor.getInt(0);
        if (viewType >= 0) {
            view = layoutInflater
                    .inflate(R.id.list_item_content, parent, false);
            ViewHolder holder = new ViewHolder();
            view.setTag(holder);
        } else {
            view = layoutInflater.inflate(R.layout.list_item_native_ad, parent, false);
            AdViewHolder holder = new AdViewHolder();

            view.setTag(holder);
        }
        return view;
    }

I have not tested above code, so it may need some changes to make it work.

abhishesh
  • 2,976
  • 15
  • 19
  • thank you for reply logically it look right! what about performance of application as i have approx 1000 items in list? – Om Infowave Developers Jun 19 '17 at 03:47
  • Not very efficient, as you have to traverse the whole cursor data once. Time complexity of getModifiedCursorWithAds is O(n) where n is size of cursor data. – abhishesh Jun 19 '17 at 06:07