シーン紹介
アプリケーションがバックグラウンドからフォアグラウンドに入ると、スタートアップページにジャンプして画面上の広告を表示します。これは、比較的一般的なシナリオです。多くの場合、いくつかの制御条件を追加する必要があります。すべてのケースでスクリーン広告がスキップされるわけではなく、ユーザーエクスペリエンスが低下するため、一連のフィルター条件が発生します。
初期計画
最初は次のようでした。
- 特定のページからブロックバックする必要があるかどうかを判断します
- 判断チャネル
- インターフェイスの内容に応じて間隔時間と周波数制限を制御する
if (activity instanceof SplashActivity) {
//启动页
return;
}
if (activity instanceof LockScreenActivity) {
//锁屏
return;
}
if (activity instanceof AlcWidgetBaseConfigActivity) {
//组件设置
return;
}
if(AlcChannelUtil.isHuawei(this)){
return;
}
String data = OnlineData.getInstance().getKey(activity, "go_splash_open", "");
int status = 0;
int oneDayMaxCount = 5;
//120秒
int offsetTime = 60;
if (!TextUtils.isEmpty(data)) {
try {
JSONObject object = new JSONObject(data);
status = object.optInt("isOpen");
offsetTime = object.optInt("offsetTime");
oneDayMaxCount = object.optInt("oneDayMaxCount");
} catch (JSONException e) {
e.printStackTrace();
}
}
boolean isOpen = status == 1;
//转成毫秒
offsetTime = offsetTime * 1000;
if (isOpen) {
//如果打开
long lastSplashTime = (long) SPUtils.get(activity, "lastSplashTime", 0L);
//并且时间间隔大于设置的时间间隔
if ((System.currentTimeMillis() - lastSplashTime) > offsetTime) {
//再判断次数是否达到上限
//判断是否是今天
int todayOpenCount = 0;
if (TimeUtils.isSameDay(lastSplashTime)) {
todayOpenCount = (int) SPUtils.get(activity, "todayOpenCount", 0);
}
if (todayOpenCount < oneDayMaxCount) {
//小于这个次数,进入开屏页,保存这一次的时间,更新今天展开次数
SPUtils.put(activity, "lastSplashTime", System.currentTimeMillis());
todayOpenCount++;
SPUtils.put(activity, "todayOpenCount", todayOpenCount);
Intent goSplash = new Intent(activity, SplashActivity.class);
goSplash.putExtra("isFromOtherApp", true);
activity.startActivity(goSplash);
}
}
}
すべて一箇所で書かれているため、コードが肥大化し、スケーラビリティも劣っています。後で条件を追加または削除する場合は、ここで直接変更します。不適切な感じがするので、責任連鎖モデルを使用して変換することを考えました。
改善する
基本クラスを定義する
最初に3つの基本クラスを定義します。1つはインターセプターインターフェイス、1つはすべてのインターセプターを接続するために使用されるチェーン、もう1つはインターセプターによって処理されるオブジェクトBeanです。
public interface BaseSplashAdInterceptor {
/**
* 进行处理过滤,比如修改是否跳转广告、修改广告类型等
*
* @param adStatusBean
*/
void doProcess(SplashAdStatusBean adStatusBean);
}
チェーンクラス
public class SplashAdChain {
private List<BaseSplashAdInterceptor> mChains;
/**
* 添加拦截器
* @param interceptor
* @return
*/
public SplashAdChain addInterceptor(BaseSplashAdInterceptor interceptor) {
if (mChains == null) {
mChains = new ArrayList<>();
}
mChains.add(interceptor);
return this;
}
/**
* 处理拦截操作
* @param adStatusBean
*/
public void doProcess(SplashAdStatusBean adStatusBean) {
if (mChains != null) {
for (BaseSplashAdInterceptor interceptor : mChains) {
interceptor.doProcess(adStatusBean);
}
}
}
}
操作オブジェクトクラス:
public class SplashAdStatusBean implements Serializable {
/**
* 是否要跳转启动页广告
*/
private boolean isNeedGoSplashAd;
/**
* 广告类型
*/
private int splashAdType;
/**
* 从哪里来的
*/
private Activity currentActivity;
//...set和get方法 ,构造方法等
}
インターセプターを設定する
次に、必要な条件に従ってインターセプターをセットアップします。次に例を示します。
/**
* 过滤Activity
*
* @author moore
* @date 2019/8/5
*/
public class SplashAdActivityInterceptor implements BaseSplashAdInterceptor {
@Override
public void doProcess(SplashAdStatusBean adStatusBean) {
if (adStatusBean.isNeedGoSplashAd()) {
//如果需要跳转,再进行过滤
Activity currentActivity = adStatusBean.getCurrentActivity();
if (currentActivity == null) {
adStatusBean.setNeedGoSplashAd(false);
return;
}
if (currentActivity instanceof SplashActivity) {
//启动页
adStatusBean.setNeedGoSplashAd(false);
return;
}
if (currentActivity instanceof LockScreenActivity) {
//锁屏
adStatusBean.setNeedGoSplashAd(false);
return;
}
if (currentActivity instanceof AlcWidgetBaseConfigActivity) {
//组件设置
adStatusBean.setNeedGoSplashAd(false);
return;
}
}
}
}
他の条件は同じです。彼をインターセプターに移動して操作し、分類します。時間の制御、回数の制御、広告の種類の制御などのように。
インターセプターを使用する
これらの条件を定義した後、それを使用し、必要に応じて追加し、最後に各インターセプターによって処理されるオブジェクトを取得できます。このオブジェクトのいくつかの値に従って、次の手順に進みます。
//拦截过滤不需要跳转启动页的情况
SplashAdStatusBean statusBean = new SplashAdStatusBean(true, 5, activity);
SplashAdChain chain = new SplashAdChain()
.addInterceptor(new SplashAdActivityInterceptor())
.addInterceptor(new SplashAdChannelInterceptor())
.addInterceptor(new SplashAdTimesInterceptor());
chain.doProcess(statusBean);
//拦截后如果需要跳转,那就跳转吧~~~
if (statusBean.isNeedGoSplashAd()) {
SPUtils.put(activity, "lastSplashTime", System.currentTimeMillis());
SPUtils.put(activity, "todayOpenCount", (statusBean.getTodayOpenCount() + 1));
Intent goSplash = new Intent(activity, SplashActivity.class);
goSplash.putExtra("isFromOtherApp", true);
activity.startActivity(goSplash);
}
結論
このような分割によりクラスの数が大幅に増加しますが、これらのフィルタリングおよびインターセプト操作をより明確に確認でき、将来的にはより明確に変更を加えて、コードの結合を減らすことができます。