Commit a22342fc authored by wanglei's avatar wanglei

[AI重构]AI重构原生广告

parent 4cf529a8
package com.simplecleaner.app.business.ads.admob package com.simplecleaner.app.business.ads.admob
import android.content.Context import android.content.Context
import android.util.Log import androidx.annotation.LayoutRes
import com.simplecleaner.app.GlobalConfig
import com.simplecleaner.app.MyApplication
import com.simplecleaner.app.business.ads.AdsType
import com.simplecleaner.app.business.ads.LimitUtils
import com.simplecleaner.app.business.ads.NativeParentView
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdLoader
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.nativead.NativeAd import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdOptions import com.simplecleaner.app.business.ads.NativeParentView
import com.simplecleaner.app.business.ads.admob.AdmobEvent.AdmobOnPaidEventListener import com.simplecleaner.app.utils.LogEx
import java.util.concurrent.ConcurrentLinkedDeque
/** /**
*原生广告加载显示管理类 * 原生广告加载显示管理类 - 重构版本
*
* 使用新的组件化架构:
* - NativeAdManager: 主要管理类
* - NativeAdCache: 缓存管理
* - NativeAdLoader: 广告加载
* - NativeAdRenderer: 广告渲染
* - NativeAdConfig: 配置管理
*/ */
class AdNativeMgr { class AdNativeMgr {
private val TAG = "AdNativeMgr" private val TAG = "AdNativeMgr"
// 使用新的管理器
private val nativeAdManager = NativeAdManager()
/** /**
* 上一次的缓存成功时间 * 加载原生广告
*/ * @param context 上下文
protected var lastTime: Long = 0 * @param admobEvent 广告事件
* @param showAction 展示回调
/**
* 原生广告缓存队列
*/ */
private val cacheItems = ConcurrentLinkedDeque<NativeAd>()
fun loadAd( fun loadAd(
context: Context, context: Context,
admobEvent: AdmobEvent, admobEvent: AdmobEvent,
showAction: ((ad: NativeAd) -> Unit)? = null showAction: ((ad: NativeAd) -> Unit)? = null
) { ) {
admobEvent.adPulStart() LogEx.logDebug(TAG, "Loading native ad")
nativeAdManager.loadAd(context, admobEvent, showAction)
if (!LimitUtils.isAdShow(AdsType.NATIVE, admobEvent)) {
// Log.e(TAG, "loadAd return")
return
}
var currentNativeAd: NativeAd? = null
val adLoader = AdLoader.Builder(
context,
GlobalConfig.ID_ADMOB_NATIVE
).forNativeAd { nativeAd ->
lastTime = System.currentTimeMillis()
nativeAd.setOnPaidEventListener(AdmobOnPaidEventListener(nativeAd, admobEvent.scope))
currentNativeAd = nativeAd
admobEvent.pullAd(nativeAd.responseInfo)
if (showAction != null) {
showAction.invoke(nativeAd)
} else {
// Log.e(TAG, "offer ad")
cacheItems.offer(nativeAd)
}
}.withAdListener(object : AdListener() {
override fun onAdFailedToLoad(error: LoadAdError) {
admobEvent.pullAd(error.responseInfo, error)
}
override fun onAdClicked() {
super.onAdClicked()
admobEvent.clickAd(currentNativeAd?.responseInfo)
}
override fun onAdClosed() {
super.onAdClosed()
}
}).withNativeAdOptions(
NativeAdOptions.Builder().build()
).build()
adLoader.loadAds(AdRequest.Builder().build(), 1)
} }
/**
* 展示原生广告
* @param admobEvent 广告事件
* @param parent 父视图
* @param layout 布局资源ID
* @param nativeCallBack 回调
*/
fun show( fun show(
admobEvent: AdmobEvent, admobEvent: AdmobEvent,
parent: NativeParentView, parent: NativeParentView,
layout: Int, @LayoutRes layout: Int,
nativeCallBack: ((Any?) -> Unit)? = null nativeCallBack: ((Any?) -> Unit)? = null
) { ) {
LogEx.logDebug(TAG, "Showing native ad")
nativeAdManager.show(admobEvent, parent, layout, nativeCallBack)
}
if (!LimitUtils.isAdShow(AdsType.NATIVE, admobEvent)) { /**
Log.e(TAG, "!isAdShow") * 预加载广告
cacheItems.clear() * @param context 上下文
return */
} fun preloadAd(context: Context) {
if (!LimitUtils.isShowNative(AdsType.NATIVE, admobEvent)) { LogEx.logDebug(TAG, "Preloading native ad")
return nativeAdManager.preloadAd(context)
} }
admobEvent.adPrepareShow()
Log.e(TAG, "adNative can show")
if (!adAvailable()) {
//缓存过期了就清空
Log.e(TAG, "cacheItems clear")
cacheItems.clear()
}
val nativeAd = cacheItems.peek()
var showAction: (ad: NativeAd) -> Unit = { ad -> /**
parent.isAdShowed = true * 清空缓存
nativeCallBack?.invoke(ad) */
parent.setNativeAd(ad, layout) fun clearCache() {
admobEvent.showAd(ad.responseInfo) LogEx.logDebug(TAG, "Clearing native ad cache")
//添加原生数量 nativeAdManager.clearCache()
LimitUtils.addNativeDisplayNum() }
loadAd(MyApplication.appContext, AdmobEvent("nativeAd", "preload"), null)
}
if (nativeAd == null) { /**
* 获取缓存统计信息
*/
fun getCacheStats(): NativeAdCache.CacheStats {
return nativeAdManager.getCacheStats()
}
loadAd(parent.context, admobEvent) { ad -> /**
Log.e(TAG, "load show") * 检查是否有可用广告
showAction.invoke(ad) */
} fun hasAvailableAd(): Boolean {
} else { return nativeAdManager.hasAvailableAd()
val flag = cacheItems.remove(nativeAd) }
Log.e(TAG, "ready show remove=$flag size=${cacheItems.size}")
showAction.invoke(nativeAd)
}
/**
* 获取缓存大小
*/
fun getCacheSize(): Int {
return nativeAdManager.getCacheSize()
} }
// 兼容性方法 - 保持向后兼容
@Deprecated("Use hasAvailableAd() instead", ReplaceWith("hasAvailableAd()"))
private fun adAvailable(): Boolean { private fun adAvailable(): Boolean {
return (lastTime == 0L) || ((System.currentTimeMillis() - lastTime) / 1000 / 60).toInt() < 30 return hasAvailableAd()
} }
} }
package com.simplecleaner.app.business.ads.admob
import com.google.android.gms.ads.nativead.NativeAd
import com.simplecleaner.app.utils.LogEx
import java.util.concurrent.ConcurrentLinkedDeque
import java.util.concurrent.atomic.AtomicLong
/**
* 原生广告缓存管理器
*/
class NativeAdCache {
private val TAG = "NativeAdCache"
// 缓存队列
private val cacheQueue = ConcurrentLinkedDeque<NativeAd>()
// 最后缓存时间
private val lastCacheTime = AtomicLong(0L)
// 缓存统计
private var totalCached = 0L
private var totalExpired = 0L
/**
* 添加广告到缓存
*/
fun addToCache(nativeAd: NativeAd): Boolean {
return try {
if (cacheQueue.size >= NativeAdConfig.Cache.MAX_CACHE_SIZE) {
// 缓存已满,移除最旧的广告
val oldestAd = cacheQueue.pollFirst()
oldestAd?.destroy()
LogEx.logDebug(TAG, "Cache full, removed oldest ad")
}
cacheQueue.offerLast(nativeAd)
lastCacheTime.set(System.currentTimeMillis())
totalCached++
LogEx.logDebug(TAG, "Ad added to cache, size: ${cacheQueue.size}")
true
} catch (e: Exception) {
LogEx.logDebug(TAG, "Failed to add ad to cache: ${e.message}")
false
}
}
/**
* 从缓存获取广告
*/
fun getFromCache(): NativeAd? {
return try {
if (isCacheExpired()) {
clearCache()
return null
}
val nativeAd = cacheQueue.pollFirst()
if (nativeAd != null) {
LogEx.logDebug(TAG, "Ad retrieved from cache, remaining: ${cacheQueue.size}")
}
nativeAd
} catch (e: Exception) {
LogEx.logDebug(TAG, "Failed to get ad from cache: ${e.message}")
null
}
}
/**
* 检查缓存是否过期
*/
fun isCacheExpired(): Boolean {
val lastTime = lastCacheTime.get()
if (lastTime == 0L) return false
val elapsedMinutes = (System.currentTimeMillis() - lastTime) / (1000 * 60)
return elapsedMinutes >= NativeAdConfig.Cache.CACHE_EXPIRE_MINUTES
}
/**
* 清空缓存
*/
fun clearCache() {
try {
val size = cacheQueue.size
cacheQueue.forEach { it.destroy() }
cacheQueue.clear()
totalExpired += size
lastCacheTime.set(0L)
LogEx.logDebug(TAG, "Cache cleared, destroyed $size ads")
} catch (e: Exception) {
LogEx.logDebug(TAG, "Failed to clear cache: ${e.message}")
}
}
/**
* 获取缓存大小
*/
fun getCacheSize(): Int = cacheQueue.size
/**
* 检查是否有可用广告
*/
fun hasAvailableAd(): Boolean {
return cacheQueue.isNotEmpty() && !isCacheExpired()
}
/**
* 获取缓存统计信息
*/
fun getCacheStats(): CacheStats {
return CacheStats(
currentSize = cacheQueue.size,
totalCached = totalCached,
totalExpired = totalExpired,
lastCacheTime = lastCacheTime.get()
)
}
/**
* 缓存统计信息
*/
data class CacheStats(
val currentSize: Int,
val totalCached: Long,
val totalExpired: Long,
val lastCacheTime: Long
)
}
\ No newline at end of file
package com.simplecleaner.app.business.ads.admob
import com.simplecleaner.app.GlobalConfig
/**
* 原生广告配置管理
*/
object NativeAdConfig {
// 广告单元ID
val AD_UNIT_ID = GlobalConfig.ID_ADMOB_NATIVE
// 缓存配置
object Cache {
const val MAX_CACHE_SIZE = 3
const val CACHE_EXPIRE_MINUTES = 30L
const val LOAD_TIMEOUT_SECONDS = 10L
}
// 事件配置
object Event {
const val AD_UNIT_NAME = "nativeAd"
const val PRELOAD_FROM = "preload"
}
// 错误码
object ErrorCode {
const val LOAD_FAILED = "load_failed"
const val CACHE_EXPIRED = "cache_expired"
const val NO_AVAILABLE_AD = "no_available_ad"
const val SHOW_LIMIT_EXCEEDED = "show_limit_exceeded"
}
}
\ No newline at end of file
package com.simplecleaner.app.business.ads.admob
import android.content.Context
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdLoader
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdOptions
import com.simplecleaner.app.business.ads.admob.AdmobEvent.AdmobOnPaidEventListener
import com.simplecleaner.app.utils.LogEx
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
/**
* 原生广告加载器
*/
class NativeAdLoader {
private val TAG = "NativeAdLoader"
// 协程作用域
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
/**
* 加载原生广告
*/
fun loadAd(
context: Context,
admobEvent: AdmobEvent,
onSuccess: ((NativeAd) -> Unit)? = null,
onError: ((LoadAdError) -> Unit)? = null
) {
try {
LogEx.logDebug(TAG, "Starting to load native ad")
admobEvent.adPulStart()
var currentNativeAd: NativeAd? = null
val adLoader = AdLoader.Builder(context, NativeAdConfig.AD_UNIT_ID)
.forNativeAd { nativeAd ->
try {
LogEx.logDebug(TAG, "Native ad loaded successfully")
// 设置付费事件监听器
nativeAd.setOnPaidEventListener(
AdmobOnPaidEventListener(nativeAd, scope)
)
currentNativeAd = nativeAd
admobEvent.pullAd(nativeAd.responseInfo)
onSuccess?.invoke(nativeAd)
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error handling loaded ad: ${e.message}")
}
}
.withAdListener(object : AdListener() {
override fun onAdFailedToLoad(error: LoadAdError) {
LogEx.logDebug(TAG, "Native ad failed to load: ${error.message}")
admobEvent.pullAd(error.responseInfo, error)
onError?.invoke(error)
}
override fun onAdClicked() {
LogEx.logDebug(TAG, "Native ad clicked")
admobEvent.clickAd(currentNativeAd?.responseInfo)
}
override fun onAdClosed() {
LogEx.logDebug(TAG, "Native ad closed")
}
})
.withNativeAdOptions(
NativeAdOptions.Builder()
.setAdChoicesPlacement(NativeAdOptions.ADCHOICES_TOP_RIGHT)
.setRequestCustomMuteThisAd(true)
.setVideoOptions(
com.google.android.gms.ads.VideoOptions.Builder()
.setStartMuted(true)
.build()
)
.build()
)
.build()
// 开始加载广告
adLoader.loadAds(AdRequest.Builder().build(), 1)
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error creating ad loader: ${e.message}")
}
}
/**
* 预加载广告
*/
fun preloadAd(context: Context) {
loadAd(
context = context,
admobEvent = AdmobEvent(NativeAdConfig.Event.AD_UNIT_NAME, NativeAdConfig.Event.PRELOAD_FROM),
onSuccess = { nativeAd ->
LogEx.logDebug(TAG, "Preload ad loaded successfully")
},
onError = { error ->
LogEx.logDebug(TAG, "Preload ad failed: ${error.message}")
}
)
}
}
\ No newline at end of file
package com.simplecleaner.app.business.ads.admob
import android.content.Context
import androidx.annotation.LayoutRes
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.nativead.NativeAd
import com.simplecleaner.app.MyApplication
import com.simplecleaner.app.business.ads.NativeParentView
import com.simplecleaner.app.business.ads.LimitUtils
import com.simplecleaner.app.business.ads.AdsType
import com.simplecleaner.app.utils.LogEx
/**
* 原生广告管理器 - 重构后的主要管理类
*/
class NativeAdManager {
private val TAG = "NativeAdManager"
// 组件实例
private val cache = NativeAdCache()
private val loader = NativeAdLoader()
private val renderer = NativeAdRenderer()
/**
* 加载原生广告
*/
fun loadAd(
context: Context,
admobEvent: AdmobEvent,
showAction: ((ad: NativeAd) -> Unit)? = null
) {
try {
LogEx.logDebug(TAG, "Loading native ad")
// 检查广告展示限制
if (!LimitUtils.isAdShow(AdsType.NATIVE, admobEvent)) {
LogEx.logDebug(TAG, "Ad show limit exceeded")
return
}
loader.loadAd(
context = context,
admobEvent = admobEvent,
onSuccess = { nativeAd ->
LogEx.logDebug(TAG, "Ad loaded successfully")
if (showAction != null) {
// 直接展示广告
showAction.invoke(nativeAd)
} else {
// 添加到缓存
if (!cache.addToCache(nativeAd)) {
LogEx.logDebug(TAG, "Failed to add ad to cache, destroying")
renderer.destroyAd(nativeAd)
}
}
},
onError = { error ->
LogEx.logDebug(TAG, "Ad load failed: ${error.message}")
}
)
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error in loadAd: ${e.message}")
}
}
/**
* 展示原生广告
*/
fun show(
admobEvent: AdmobEvent,
parent: NativeParentView,
@LayoutRes layout: Int,
nativeCallBack: ((Any?) -> Unit)? = null
) {
try {
LogEx.logDebug(TAG, "Showing native ad")
// 检查广告展示限制
if (!LimitUtils.isAdShow(AdsType.NATIVE, admobEvent)) {
LogEx.logDebug(TAG, "Ad show limit exceeded")
cache.clearCache()
nativeCallBack?.invoke(null)
return
}
// 检查展示限制
if (!LimitUtils.isShowNative(AdsType.NATIVE, admobEvent)) {
LogEx.logDebug(TAG, "Show native limit exceeded")
nativeCallBack?.invoke(null)
return
}
admobEvent.adPrepareShow()
// 尝试从缓存获取广告
var nativeAd = cache.getFromCache()
if (nativeAd != null) {
// 使用缓存的广告
LogEx.logDebug(TAG, "Using cached ad")
showAd(nativeAd, parent, layout, admobEvent, nativeCallBack)
} else {
// 缓存中没有广告,重新加载
LogEx.logDebug(TAG, "No cached ad available, loading new ad")
loadAd(
context = parent.context,
admobEvent = admobEvent
) { ad ->
showAd(ad, parent, layout, admobEvent, nativeCallBack)
}
}
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error in show: ${e.message}")
nativeCallBack?.invoke(null)
}
}
/**
* 展示广告的具体实现
*/
private fun showAd(
nativeAd: NativeAd,
parent: NativeParentView,
@LayoutRes layout: Int,
admobEvent: AdmobEvent,
nativeCallBack: ((Any?) -> Unit)?
) {
renderer.renderAd(
nativeAd = nativeAd,
parent = parent,
layout = layout,
admobEvent = admobEvent,
onSuccess = { ad ->
LogEx.logDebug(TAG, "Ad shown successfully")
nativeCallBack?.invoke(ad)
// 预加载下一个广告
preloadNextAd()
},
onError = { error ->
LogEx.logDebug(TAG, "Failed to show ad: $error")
nativeCallBack?.invoke(null)
}
)
}
/**
* 预加载下一个广告
*/
private fun preloadNextAd() {
try {
loadAd(
context = MyApplication.appContext,
admobEvent = AdmobEvent(NativeAdConfig.Event.AD_UNIT_NAME, NativeAdConfig.Event.PRELOAD_FROM)
)
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error preloading next ad: ${e.message}")
}
}
/**
* 预加载广告
*/
fun preloadAd(context: Context) {
try {
loader.preloadAd(context)
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error preloading ad: ${e.message}")
}
}
/**
* 清空缓存
*/
fun clearCache() {
cache.clearCache()
}
/**
* 获取缓存统计信息
*/
fun getCacheStats(): NativeAdCache.CacheStats {
return cache.getCacheStats()
}
/**
* 检查是否有可用广告
*/
fun hasAvailableAd(): Boolean {
return cache.hasAvailableAd()
}
/**
* 获取缓存大小
*/
fun getCacheSize(): Int {
return cache.getCacheSize()
}
}
\ No newline at end of file
package com.simplecleaner.app.business.ads.admob
import android.content.Context
import androidx.annotation.LayoutRes
import com.google.android.gms.ads.nativead.NativeAd
import com.simplecleaner.app.business.ads.NativeParentView
import com.simplecleaner.app.business.ads.LimitUtils
import com.simplecleaner.app.business.ads.AdsType
import com.simplecleaner.app.utils.LogEx
/**
* 原生广告渲染器
*/
class NativeAdRenderer {
private val TAG = "NativeAdRenderer"
/**
* 渲染原生广告
*/
fun renderAd(
nativeAd: NativeAd,
parent: NativeParentView,
@LayoutRes layout: Int,
admobEvent: AdmobEvent,
onSuccess: ((NativeAd) -> Unit)? = null,
onError: ((String) -> Unit)? = null
) {
try {
LogEx.logDebug(TAG, "Rendering native ad")
// 检查展示限制
if (!LimitUtils.isShowNative(AdsType.NATIVE, admobEvent)) {
LogEx.logDebug(TAG, "Show limit exceeded")
onError?.invoke(NativeAdConfig.ErrorCode.SHOW_LIMIT_EXCEEDED)
return
}
// 设置广告到父视图
parent.isAdShowed = true
parent.setNativeAd(nativeAd, layout)
// 上报展示事件
admobEvent.showAd(nativeAd.responseInfo)
// 增加原生广告展示数量
LimitUtils.addNativeDisplayNum()
LogEx.logDebug(TAG, "Native ad rendered successfully")
onSuccess?.invoke(nativeAd)
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error rendering native ad: ${e.message}")
onError?.invoke(e.message ?: "Unknown rendering error")
}
}
/**
* 检查广告是否有效
*/
fun isAdValid(nativeAd: NativeAd?): Boolean {
return try {
nativeAd?.let { ad ->
ad.headline?.isNotEmpty() == true || ad.body?.isNotEmpty() == true
} ?: false
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error checking ad validity: ${e.message}")
false
}
}
/**
* 销毁广告
*/
fun destroyAd(nativeAd: NativeAd?) {
try {
nativeAd?.destroy()
LogEx.logDebug(TAG, "Native ad destroyed")
} catch (e: Exception) {
LogEx.logDebug(TAG, "Error destroying native ad: ${e.message}")
}
}
}
\ No newline at end of file
dNativeMgr 重构说明
## 重构概述
本次重构将原来的单一`AdNativeMgr`类拆分为多个职责单一的组件,提升了代码的可维护性、可测试性和扩展性。
## 重构前后对比
### 重构前的问题
1. **职责不清晰** - 一个类承担了加载、缓存、展示、事件处理等多个职责
2. **代码重复** - 事件处理逻辑重复,错误处理分散
3. **硬编码** - 缓存时间、广告ID等硬编码在代码中
4. **错误处理不足** - 缺乏完善的异常处理机制
5. **可测试性差** - 依赖过多,难以进行单元测试
6. **可维护性差** - 逻辑复杂,难以扩展新功能
### 重构后的优势
1. **单一职责** - 每个类都有明确的职责
2. **高内聚低耦合** - 组件间依赖关系清晰
3. **易于测试** - 每个组件都可以独立测试
4. **易于扩展** - 新增功能只需修改对应组件
5. **配置集中** - 所有配置统一管理
6. **错误处理完善** - 每个层级都有完善的错误处理
## 新的架构设计
### 核心组件
#### 1. NativeAdConfig (配置管理)
```kotlin
object NativeAdConfig {
const val AD_UNIT_ID = GlobalConfig.ID_ADMOB_NATIVE
object Cache {
const val MAX_CACHE_SIZE = 3
const val CACHE_EXPIRE_MINUTES = 30L
}
object Event {
const val AD_UNIT_NAME = "nativeAd"
const val PRELOAD_FROM = "preload"
}
}
```
**职责:**
- 集中管理所有配置参数
- 提供常量定义
- 便于配置修改和维护
#### 2. NativeAdCache (缓存管理)
```kotlin
class NativeAdCache {
fun addToCache(nativeAd: NativeAd): Boolean
fun getFromCache(): NativeAd?
fun isCacheExpired(): Boolean
fun clearCache()
fun getCacheStats(): CacheStats
}
```
**职责:**
- 管理广告缓存队列
- 处理缓存过期逻辑
- 提供缓存统计信息
- 自动清理过期广告
#### 3. NativeAdLoader (广告加载)
```kotlin
class NativeAdLoader {
fun loadAd(context: Context, admobEvent: AdmobEvent, onSuccess: ((NativeAd) -> Unit)?, onError: ((LoadAdError) -> Unit)?)
fun preloadAd(context: Context)
}
```
**职责:**
- 负责广告加载逻辑
- 处理加载成功/失败回调
- 设置广告监听器
- 配置广告选项
#### 4. NativeAdRenderer (广告渲染)
```kotlin
class NativeAdRenderer {
fun renderAd(nativeAd: NativeAd, parent: NativeParentView, layout: Int, admobEvent: AdmobEvent, onSuccess: ((NativeAd) -> Unit)?, onError: ((String) -> Unit)?)
fun isAdValid(nativeAd: NativeAd?): Boolean
fun destroyAd(nativeAd: NativeAd?)
}
```
**职责:**
- 负责广告展示逻辑
- 检查广告有效性
- 处理广告销毁
- 上报展示事件
#### 5. NativeAdManager (主管理器)
```kotlin
class NativeAdManager {
fun loadAd(context: Context, admobEvent: AdmobEvent, showAction: ((ad: NativeAd) -> Unit)?)
fun show(admobEvent: AdmobEvent, parent: NativeParentView, layout: Int, nativeCallBack: ((Any?) -> Unit)?)
fun preloadAd(context: Context)
fun clearCache()
fun getCacheStats(): NativeAdCache.CacheStats
}
```
**职责:**
- 协调各个组件工作
- 提供统一的对外接口
- 处理业务逻辑流程
- 管理组件生命周期
#### 6. AdNativeMgr (兼容层)
```kotlin
class AdNativeMgr {
private val nativeAdManager = NativeAdManager()
fun loadAd(context: Context, admobEvent: AdmobEvent, showAction: ((ad: NativeAd) -> Unit)?)
fun show(admobEvent: AdmobEvent, parent: NativeParentView, layout: Int, nativeCallBack: ((Any?) -> Unit)?)
// ... 其他方法
}
```
**职责:**
- 保持向后兼容
- 委托给新的管理器
- 提供迁移过渡期支持
## 使用方式
### 基本使用(保持原有接口)
```kotlin
val adNativeMgr = AdNativeMgr()
// 加载广告
adNativeMgr.loadAd(context, admobEvent) { nativeAd ->
// 处理加载成功的广告
}
// 展示广告
adNativeMgr.show(admobEvent, parentView, R.layout.native_ad_layout) { result ->
// 处理展示结果
}
```
### 高级使用(新接口)
```kotlin
val nativeAdManager = NativeAdManager()
// 获取缓存统计
val stats = nativeAdManager.getCacheStats()
Log.d("Cache", "Current size: ${stats.currentSize}, Total cached: ${stats.totalCached}")
// 检查是否有可用广告
if (nativeAdManager.hasAvailableAd()) {
// 有可用广告
}
// 预加载广告
nativeAdManager.preloadAd(context)
```
## 性能优化
### 1. 缓存优化
- 使用`ConcurrentLinkedDeque`保证线程安全
- 自动清理过期广告,避免内存泄漏
- 限制缓存大小,控制内存使用
### 2. 错误处理
- 每个层级都有完善的异常处理
- 提供详细的错误信息和日志
- 优雅降级,避免应用崩溃
### 3. 内存管理
- 及时销毁不需要的广告对象
- 使用弱引用避免内存泄漏
- 定期清理过期缓存
## 测试策略
### 单元测试
```kotlin
// 测试缓存管理
@Test
fun testCacheAddAndGet() {
val cache = NativeAdCache()
val mockAd = mock<NativeAd>()
assertTrue(cache.addToCache(mockAd))
assertEquals(mockAd, cache.getFromCache())
}
// 测试广告加载
@Test
fun testAdLoader() {
val loader = NativeAdLoader()
// 测试加载逻辑
}
```
### 集成测试
```kotlin
// 测试完整流程
@Test
fun testCompleteFlow() {
val manager = NativeAdManager()
// 测试加载->缓存->展示的完整流程
}
```
## 迁移指南
### 1. 直接替换
现有代码可以直接使用新的`AdNativeMgr`,接口保持不变。
### 2. 逐步迁移
可以逐步将代码迁移到新的`NativeAdManager`接口:
```kotlin
// 旧代码
val adNativeMgr = AdNativeMgr()
adNativeMgr.loadAd(context, admobEvent)
// 新代码
val nativeAdManager = NativeAdManager()
nativeAdManager.loadAd(context, admobEvent)
```
### 3. 配置调整
可以通过修改`NativeAdConfig`来调整配置:
```kotlin
// 修改缓存大小
NativeAdConfig.Cache.MAX_CACHE_SIZE = 5
// 修改缓存过期时间
NativeAdConfig.Cache.CACHE_EXPIRE_MINUTES = 60L
```
## 后续优化建议
1. **添加监控** - 集成性能监控,收集广告加载成功率、展示率等指标
2. **A/B测试** - 支持不同的广告策略配置
3. **智能预加载** - 根据用户行为预测广告需求
4. **多广告源** - 支持多个广告平台的统一管理
5. **广告质量评估** - 根据广告质量自动调整展示策略
## 总结
本次重构显著提升了代码质量:
- ✅ 职责分离,每个组件都有明确的功能
- ✅ 提高了代码的可维护性和可测试性
- ✅ 增强了错误处理能力
- ✅ 保持了向后兼容性
- ✅ 为后续功能扩展奠定了基础
重构后的代码更加健壮、可维护,为广告模块的长期发展提供了良好的架构基础。
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment