React Native中Android InMobi Banner基于SimpleViewManager不显示求助
我在开发React Native的Android原生UI组件以集成InMobi Banner时遇到问题:用继承SimpleViewManager的类创建UI模块,组件无法在屏幕上显示;但用Fragment实现时能正常运行。根据InMobi文档,Banner只能在UI线程显示,我尝试了Handler和runOnUiThread(通过React bridge)但无效。
我不想用Fragment方案,因为需要将Banner集成到现有布局中。以下是我的实现代码:
InMobiBannerManager类(继承SimpleViewManager)
public class InMobiBannerManager extends SimpleViewManager<InMobiBannerClass> { public static final String REACT_CLASS = "InMobibanner"; ReactApplicationContext reactContext; public InMobiBannerManager(ReactApplicationContext reactContext) { this.reactContext = reactContext; } @Override public String getName() { return REACT_CLASS; } @Override protected InMobiBannerClass createViewInstance(ThemedReactContext reactContext) { return new InMobiBannerClass(reactContext); } }
InMobiBannerClass类(继承RelativeLayout)
public class InMobiBannerClass extends RelativeLayout { Context context; InMobiBanner bannerAd; private static final String TAG = "InMobiBannerClass"; BannerAdEventListener bannerAdEventListener = new BannerAdEventListener() { @Override public void onAdFetchFailed(@NonNull InMobiBanner inMobiBanner, @NonNull InMobiAdRequestStatus inMobiAdRequestStatus) { super.onAdFetchFailed(inMobiBanner, inMobiAdRequestStatus); Log.d(TAG, "INMOBIBANNNERonAdFetchFailed: "+inMobiAdRequestStatus.getMessage()); } @Override public void onAdDisplayed(@NonNull InMobiBanner inMobiBanner) { super.onAdDisplayed(inMobiBanner); Log.d(TAG, "INMOBIBANNNERonAdDisplayed: "); } @Override public void onAdDismissed(@NonNull InMobiBanner inMobiBanner) { super.onAdDismissed(inMobiBanner); Log.d(TAG, "INMOBIBANNNERonAdDismissed: "); } @Override public void onUserLeftApplication(@NonNull InMobiBanner inMobiBanner) { super.onUserLeftApplication(inMobiBanner); } @Override public void onRewardsUnlocked(@NonNull InMobiBanner inMobiBanner, Map<Object, Object> map) { super.onRewardsUnlocked(inMobiBanner, map); } @Override public void onAdFetchSuccessful(@NonNull InMobiBanner inMobiBanner, @NonNull AdMetaInfo adMetaInfo) { super.onAdFetchSuccessful(inMobiBanner, adMetaInfo); Log.d(TAG, "onAdFetchSuccessful: "); } @Override public void onAdLoadSucceeded(@NonNull InMobiBanner inMobiBanner, @NonNull AdMetaInfo adMetaInfo) { super.onAdLoadSucceeded(inMobiBanner, adMetaInfo); Log.d(TAG, "INMOBIBANNNERonAdLoadSucceeded: "); } @Override public void onAdLoadFailed(@NonNull InMobiBanner inMobiBanner, @NonNull InMobiAdRequestStatus inMobiAdRequestStatus) { super.onAdLoadFailed(inMobiBanner, inMobiAdRequestStatus); Log.d(TAG, "INMOBIBANNNERonAdLoadFailed: "+inMobiAdRequestStatus.getMessage()); } @Override public void onAdClicked(@NonNull InMobiBanner inMobiBanner, Map<Object, Object> map) { super.onAdClicked(inMobiBanner, map); } @Override public void onRequestPayloadCreated(byte[] bytes) { super.onRequestPayloadCreated(bytes); } @Override public void onRequestPayloadCreationFailed(@NonNull InMobiAdRequestStatus inMobiAdRequestStatus) { super.onRequestPayloadCreationFailed(inMobiAdRequestStatus); } @Override public void onAdImpression(@NonNull InMobiBanner inMobiBanner) { super.onAdImpression(inMobiBanner); } }; @SuppressLint("MissingInflatedId") public InMobiBannerClass(Context context) { super(context); this.context = context; LayoutInflater inflater = LayoutInflater.from(context); View inflatedView = inflater.inflate(R.layout.activity_main3, null); RelativeLayout adContainer = (RelativeLayout) inflatedView.findViewById(R.id.ad_container); bannerAd = new InMobiBanner(context, 1683264304035L); RelativeLayout.LayoutParams bannerLp = new RelativeLayout.LayoutParams(dpToPx(350), dpToPx(200)); adContainer.addView(bannerAd, bannerLp); bannerAd.setListener(bannerAdEventListener); // 原代码此处有语法错误,且createViewInstance本身就在UI线程,无需额外延迟 new Handler(Looper.getMainLooper()).post(() -> { bannerAd.setEnableAutoRefresh(true); bannerAd.load(); }); // 给inflatedView设置LayoutParams,确保它能填满当前RelativeLayout addView(inflatedView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); } private int dpToPx(int dp) { return (int) (dp * Resources.getSystem().getDisplayMetrics().density); } public void onReceiveNativeEvent() { WritableMap event = Arguments.createMap(); event.putString("message", "MyMessage"); ReactContext reactContext = (ReactContext)getContext(); reactContext .getJSModule(RCTEventEmitter.class) .receiveEvent(getId(), "topChange", event); } }
React Native侧调用代码
const InMobibanner = requireNativeComponent('InMobibanner'); // 使用时必须设置宽高,否则原生组件可能不显示 function App() { return ( <View style={{flex: 1}}> {/* 给Banner组件设置明确的宽高 */} <InMobibanner style={{width: 350, height: 200}} /> </View> ); }
解决方案分析
UI线程问题:
SimpleViewManager的createViewInstance方法本身就在UI线程执行,不需要额外用runOnUiThread延迟加载,原代码中的延迟反而可能导致初始化时机异常,且存在语法错误(多了闭合括号)。直接用Handler(Looper.getMainLooper())确保在主线程执行即可,甚至可以直接调用bannerAd.load()。布局参数问题:
- 将
inflatedView添加到当前RelativeLayout时,必须设置LayoutParams为MATCH_PARENT,否则视图会没有尺寸而不显示。 - React Native侧使用原生组件时,必须给组件设置明确的宽高样式,RN不会自动给原生组件分配尺寸。
- 将
注册Native组件:确保在自定义的
ReactPackage中注册InMobiBannerManager,否则RN无法识别该原生组件:
public class CustomPackage implements ReactPackage { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { List<ViewManager> modules = new ArrayList<>(); modules.add(new InMobiBannerManager(reactContext)); return modules; } }
- 检查布局文件
activity_main3:确保ad_container这个RelativeLayout设置了合适的宽高(比如match_parent),否则Banner添加进去后也无法显示。
内容的提问来源于stack exchange,提问作者Tanveerbyn
相关产品推荐
相关产品推荐

