接入文档 --> 穿山甲 – 模板渲染信息流(RecyclerView)
因为自渲染信息流广告: 已回收,不再提供创建
因此使用模板渲染信息流广告, 官方接入文档中模板信息流广告使用ListView,本文采用RecyclerView
XinXiLiu.java
public class XinXiLiu extends AppCompatActivity {
private RecyclerView mRecyclerview;
private TTAdNative mTTAdNative;
private List<TTNativeExpressAd> mData;
Context mContext;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xin_xi_liu);
initAD();
initView();
}
private void initAD() {
//step1:初始化sdk
TTAdManagerHolder.init(this);
TTAdManager ttAdManager = TTAdManagerHolder.get();
//step2:创建TTAdNative对象,用于调用广告请求接口
mTTAdNative = ttAdManager.createAdNative(this);
//step3:(可选,强烈建议在合适的时机调用):申请部分权限,如read_phone_state,防止获取不了imei时候,下载类广告没有填充的问题。
TTAdManagerHolder.get().requestPermissionIfNecessary(this);
//
mData = new ArrayList<>();
for (int i = 0; i < 10; i++) {
mData.add(null);
}
}
private void initView() {
mContext = this;
mRecyclerview = (RecyclerView) findViewById(R.id.recyclerview);
mRecyclerview.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
myAdapter = new MyAdapter(mContext, mData);
mRecyclerview.setAdapter(myAdapter);
loadListAd();
}
private void loadListAd() {
float expressViewWidth = 350;
float expressViewHeight = 350;
try {
expressViewHeight = Float.parseFloat("0");
} catch (Exception e) {
expressViewHeight = 0; //高度设置为0,则高度会自适应
}
//step4:创建feed广告请求类型参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setCodeId("945***750")//自己的广告id
.setExpressViewAcceptedSize(expressViewWidth, expressViewHeight) //期望模板广告view的size,单位dp
.setAdCount(3) //请求广告数量为1到3条
.build();
//step5:请求广告,调用feed广告异步请求接口,加载到广告后,拿到广告素材自定义渲染
mTTAdNative.loadNativeExpressAd(adSlot, new TTAdNative.NativeExpressAdListener() {
@Override
public void onError(int code, String message) {
if (mRecyclerview != null) {
}
}
@Override
public void onNativeExpressAdLoad(List<TTNativeExpressAd> ads) {
if (mRecyclerview != null) {
}
if (ads == null || ads.isEmpty()) {
return;
}
bindAdListener(ads);
}
});
}
private void bindAdListener(final List<TTNativeExpressAd> ads) {
// final int count = mData.size();
int i = 1;
for (TTNativeExpressAd ad : ads) {
final TTNativeExpressAd adTmp = ad;
//设置广告位置
mData.set(i, adTmp);
i += 3;
myAdapter.notifyDataSetChanged();
adTmp.setExpressInteractionListener(new TTNativeExpressAd.ExpressAdInteractionListener() {
@Override
public void onAdClicked(View view, int type) {
TToast.show(XinXiLiu.this, "广告被点击");
}
@Override
public void onAdShow(View view, int type) {
TToast.show(XinXiLiu.this, "广告展示");
}
@Override
public void onRenderFail(View view, String msg, int code) {
TToast.show(XinXiLiu.this, msg + " code:" + code);
}
@Override
public void onRenderSuccess(View view, float width, float height) {
//返回view的宽高 单位 dp
TToast.show(XinXiLiu.this, "渲染成功");
}
});
ad.render();
}
}
}
activity_xin_xi_liu.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"
tools:context=".xinxiliu.XinXiLiu">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.8" />
</androidx.constraintlayout.widget.ConstraintLayout>
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int ITEM_VIEW_TYPE_NORMAL = 0;
private static final int ITEM_VIEW_TYPE_GROUP_PIC_AD = 1;
private static final int ITEM_VIEW_TYPE_SMALL_PIC_AD = 2;
private static final int ITEM_VIEW_TYPE_LARGE_PIC_AD = 3;
private static final int ITEM_VIEW_TYPE_VIDEO = 4;
private static final int ITEM_VIEW_TYPE_VERTICAL_IMG = 5;//竖版图片
private static final int ITEM_VIEW_TYPE_VIDEO_VERTICAL = 6;//竖版视频
private Map<AdViewHolder, TTAppDownloadListener> mTTAppDownloadListenerMap = new WeakHashMap<>();
Context mContext;
private List<TTNativeExpressAd> mData;
public MyAdapter(Context context, List<TTNativeExpressAd> mData) {
this.mContext = context;
this.mData = mData;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case ITEM_VIEW_TYPE_SMALL_PIC_AD:
case ITEM_VIEW_TYPE_LARGE_PIC_AD:
case ITEM_VIEW_TYPE_GROUP_PIC_AD:
case ITEM_VIEW_TYPE_VERTICAL_IMG:
case ITEM_VIEW_TYPE_VIDEO:
case ITEM_VIEW_TYPE_VIDEO_VERTICAL:
return new AdViewHolder(layoutInflater.inflate(R.layout.listitem_ad_native_express, parent, false));
default:
return new MyViewHolder(layoutInflater.inflate(R.layout.item, parent, false));
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(holder instanceof AdViewHolder){
try{
AdViewHolder adViewHolder = (AdViewHolder) holder;
bindData(adViewHolder, mData.get(position));
if (adViewHolder.videoView != null) {
View video = mData.get(position).getExpressAdView();
if (video != null) {
adViewHolder.videoView.removeAllViews();
if (video.getParent() == null) {
adViewHolder.videoView.addView(video);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}else if(holder instanceof MyViewHolder){
MyViewHolder myViewHolder = (MyViewHolder) holder;
myViewHolder.textView.setText("=======> " + position);
}
}
public TTNativeExpressAd getItemAd(int i) {
return mData.get(i);
}
@Override
public int getItemCount() {
return mData.size();
}
@Override
public int getItemViewType(int position) {
TTNativeExpressAd ad = getItemAd(position);
if (ad == null) {
return ITEM_VIEW_TYPE_NORMAL;
} else if (ad.getImageMode() == TTAdConstant.IMAGE_MODE_SMALL_IMG) {
return ITEM_VIEW_TYPE_SMALL_PIC_AD;
} else if (ad.getImageMode() == TTAdConstant.IMAGE_MODE_LARGE_IMG) {
return ITEM_VIEW_TYPE_LARGE_PIC_AD;
} else if (ad.getImageMode() == TTAdConstant.IMAGE_MODE_GROUP_IMG) {
return ITEM_VIEW_TYPE_GROUP_PIC_AD;
} else if (ad.getImageMode() == TTAdConstant.IMAGE_MODE_VIDEO) {
return ITEM_VIEW_TYPE_VIDEO;
} else if (ad.getImageMode() == TTAdConstant.IMAGE_MODE_VERTICAL_IMG) {
return ITEM_VIEW_TYPE_VERTICAL_IMG;
} else if (ad.getImageMode() == TTAdConstant.IMAGE_MODE_VIDEO_VERTICAL) {
return ITEM_VIEW_TYPE_VIDEO_VERTICAL;
} else {
TToast.show(mContext, "图片展示样式错误");
return ITEM_VIEW_TYPE_NORMAL;
}
}
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
}
}
static class AdViewHolder extends RecyclerView.ViewHolder {
FrameLayout videoView;
public AdViewHolder(@NonNull View itemView) {
super(itemView);
videoView = itemView.findViewById(R.id.iv_listitem_express);
}
}
private void bindData(final AdViewHolder adViewHolder, TTNativeExpressAd ad) {
//设置dislike弹窗
bindDislike(ad, false);
switch (ad.getInteractionType()) {
case TTAdConstant.INTERACTION_TYPE_DOWNLOAD:
bindDownloadListener(adViewHolder, ad);
break;
}
}
/**
* 设置广告的不喜欢,注意:强烈建议设置该逻辑,如果不设置dislike处理逻辑,则模板广告中的 dislike区域不响应dislike事件。
*
* @param ad
* @param customStyle 是否自定义样式,true:样式自定义
*/
private void bindDislike(final TTNativeExpressAd ad, boolean customStyle) {
if (customStyle) {
//使用自定义样式
DislikeInfo dislikeInfo = ad.getDislikeInfo();
if (dislikeInfo == null || dislikeInfo.getFilterWords() == null || dislikeInfo.getFilterWords().isEmpty()) {
return;
}
final DislikeDialog dislikeDialog = new DislikeDialog(mContext, dislikeInfo);
dislikeDialog.setOnDislikeItemClick(new DislikeDialog.OnDislikeItemClick() {
@Override
public void onItemClick(FilterWord filterWord) {
//屏蔽广告
TToast.show(mContext, "点击 " + filterWord.getName());
//用户选择不喜欢原因后,移除广告展示
mData.remove(ad);
notifyDataSetChanged();
}
});
dislikeDialog.setOnPersonalizationPromptClick(new DislikeDialog.OnPersonalizationPromptClick() {
@Override
public void onClick(PersonalizationPrompt personalizationPrompt) {
TToast.show(mContext, "点击了为什么看到此广告");
}
});
ad.setDislikeDialog(dislikeDialog);
return;
}
//使用默认模板中默认dislike弹出样式
ad.setDislikeCallback((Activity) mContext, new TTAdDislike.DislikeInteractionCallback() {
@Override
public void onShow() {
}
@Override
public void onSelected(int position, String value) {
TToast.show(mContext, "点击 " + value);
//用户选择不喜欢原因后,移除广告展示
mData.remove(ad);
notifyDataSetChanged();
}
@Override
public void onCancel() {
TToast.show(mContext, "点击取消 ");
}
@Override
public void onRefuse() {
}
});
}
private void bindDownloadListener(final AdViewHolder adViewHolder, TTNativeExpressAd ad) {
TTAppDownloadListener downloadListener = new TTAppDownloadListener() {
private boolean mHasShowDownloadActive = false;
@Override
public void onIdle() {
if (!isValid()) {
return;
}
TToast.show(mContext, "点击广告开始下载");
}
@SuppressLint("SetTextI18n")
@Override
public void onDownloadActive(long totalBytes, long currBytes, String fileName, String appName) {
if (!isValid()) {
return;
}
if (!mHasShowDownloadActive) {
mHasShowDownloadActive = true;
TToast.show(mContext, appName + " 下载中,点击暂停", Toast.LENGTH_LONG);
}
}
@SuppressLint("SetTextI18n")
@Override
public void onDownloadPaused(long totalBytes, long currBytes, String fileName, String appName) {
if (!isValid()) {
return;
}
TToast.show(mContext, appName + " 下载暂停", Toast.LENGTH_LONG);
}
@Override
public void onDownloadFailed(long totalBytes, long currBytes, String fileName, String appName) {
if (!isValid()) {
return;
}
TToast.show(mContext, appName + " 下载失败,重新下载", Toast.LENGTH_LONG);
}
@Override
public void onInstalled(String fileName, String appName) {
if (!isValid()) {
return;
}
TToast.show(mContext, appName + " 安装完成,点击打开", Toast.LENGTH_LONG);
}
@Override
public void onDownloadFinished(long totalBytes, String fileName, String appName) {
if (!isValid()) {
return;
}
TToast.show(mContext, appName + " 下载成功,点击安装", Toast.LENGTH_LONG);
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isValid() {
return mTTAppDownloadListenerMap.get(adViewHolder) == this;
}
};
//一个ViewHolder对应一个downloadListener, isValid判断当前ViewHolder绑定的listener是不是自己
ad.setDownloadListener(downloadListener); // 注册下载监听器
mTTAppDownloadListenerMap.put(adViewHolder, downloadListener);
}
}
listitem_ad_native_express.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="HardcodedText">
<FrameLayout
android:id="@+id/iv_listitem_express"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.2" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.8" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="TextView"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>