官网的例子以ReactNative项目来说明,没有关于ReactNative嵌入到android是如何调用android原生组件的例子,没办法只能参考ReactNative源代码来自己调用。本文以调用android组件ExpandableListView为例。
1、创建调用原生组件模块ReactExpandableListViewManager。

package com.example.test.widget.reactnative.expandableListView;import android.app.Activity;import android.content.Context;import android.content.SharedPreferences;import android.graphics.Color;import android.widget.ExpandableListView;import com.example.test.adapter.ExpandableListAdapter;import com.example.test.bean.AppUpdate;import com.facebook.react.module.annotations.ReactModule;import com.facebook.react.uimanager.SimpleViewManager;import com.facebook.react.uimanager.ThemedReactContext;import com.facebook.react.uimanager.annotations.ReactProp;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.List;import java.util.Set;import rx.Observable;import rx.Observer;import rx.Subscriber;import rx.android.schedulers.AndroidSchedulers;import rx.schedulers.Schedulers;/** * Created by Springever on 2017/5/18. */@ReactModule(name = ReactExpandableListViewManager.REACT_CLASS)public class ReactExpandableListViewManager extends SimpleViewManager implements ExpandableListAdapter.Callback {    public static final String REACT_CLASS = "RCTExpandableListView";//和ReactNative的js组件名字一致    private ExpandableListView expandableListView;    private ExpandableListAdapter mUpdateAdapter;    private Activity activity;    private static final String NAME_ENTITIES = "entities";    private static String PREF_IGNORE = "ignore";    private static final String JSON_UPAPPITEMS = "upappitems";    private static final String JSON_IGNOREAPPITEMS = "ignoreappitems";    public List mUpdates = new ArrayList();    public List mIgnores = new ArrayList();    public ReactExpandableListViewManager(){    }    @Override    public String getName() {        return REACT_CLASS;    }    @Override    protected ExpandableListView createViewInstance(ThemedReactContext reactContext) {        expandableListView =new ExpandableListView(reactContext);        mUpdateAdapter = new ExpandableListAdapter(reactContext);        mUpdateAdapter.registerCallback(this);//注册回调函数        expandableListView.setAdapter(mUpdateAdapter);        expandableListView.setCacheColorHint(Color.TRANSPARENT);//点击时候不会变黑        expandableListView.setGroupIndicator(null);//去掉左边图标        expandableListView.expandGroup(ExpandableListAdapter.GROUP_UPDATE);//触发展开        expandableListView.expandGroup(ExpandableListAdapter.GROUP_IGNORE);//触发展开        activity = reactContext.getCurrentActivity();        showData();        return expandableListView;    }    @ReactProp(name = "layoutWidth")    public void setLayoutWidth(ExpandableListView view, int layoutWidth) {    }    @ReactProp(name = "layoutHeight")    public void setLayoutHeight(ExpandableListView view, int layoutHeight) {    }    public void showData() {        final Thread t = Thread.currentThread();        Observable.create(new Observable.OnSubscribe() {            @Override            public void call(Subscriber<? super JSONObject> subscriber) {                byte[] bytes = readFromAsset(activity, "preload/update.json");                JSONObject jsonObj = null;                if (bytes != null) {                    try {                        jsonObj = new JSONObject(new String(bytes));                    } catch (JSONException e) {                        e.printStackTrace();                    }                }                subscriber.onNext(jsonObj);                subscriber.onCompleted();            }        })                .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程                .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程                .subscribe(new Observer() {                    @Override                    public void onNext(JSONObject jsonObj) {                        JSONObject entities = jsonObj.optJSONObject(NAME_ENTITIES);                        if (entities != null) {                            try {                                readFromJSON(entities);                                //上次忽略更新的应用                                SharedPreferences pref = activity.getSharedPreferences(PREF_IGNORE, 0);                                Set ignoreSet = pref.getAll().keySet();                                List update = new ArrayList();                                List ignore = new ArrayList();                                if (mUpdates != null) {                                    for (AppUpdate au : mUpdates) {                                        //比较本地应用                                        //int status = getXXX(au.mPackageName, au.mVersionCode, au.mVersion);                                        //if (status != STATUS_INSTALLED_OLD_VERSION)                                        //    continue;                                        if (ignoreSet.contains(au.mPackageName)) {                                            ignore.add(au);                                        } else {                                            update.add(au);                                        }                                    }                                }                                mUpdateAdapter.setData(update, ignore);                            } catch (JSONException e) {                                e.printStackTrace();                            }                        }                    }                    @Override                    public void onCompleted() {                    }                    @Override                    public void onError(Throwable e) {                    }                });        /*        JSONObject jsonObj = null;        try {            byte[] bytes = readFromAsset(this, "preload/update.json");            if (bytes != null) {                jsonObj = new JSONObject(new String(bytes));            } else {            }            JSONObject entities = jsonObj.optJSONObject(NAME_ENTITIES);            if (entities != null) {                readFromJSON(entities);                //上次忽略更新的应用                SharedPreferences pref = getSharedPreferences(PREF_IGNORE, 0);                Set ignoreSet = pref.getAll().keySet();                List update = new ArrayList();                List ignore = new ArrayList();                if (mUpdates != null) {                    for (AppUpdate au : mUpdates) {                        //比较本地应用                        //int status = getXXX(au.mPackageName, au.mVersionCode, au.mVersion);                        //if (status != STATUS_INSTALLED_OLD_VERSION)                        //    continue;                        if (ignoreSet.contains(au.mPackageName)) {                            ignore.add(au);                        } else {                            update.add(au);                        }                    }                }                mUpdateAdapter.setData(update, ignore);            }        } catch (Exception e) {        }        */    }    public static byte[] readFromAsset(Context context, String fileName) {        byte[] ret = null;        InputStream instream = null;        try {            instream = context.getAssets().open(fileName);            byte[] buffer = new byte[8192];            ByteArrayOutputStream baos = new ByteArrayOutputStream();            int len = -1;            while ((len = instream.read(buffer)) >= 0)                baos.write(buffer, 0, len);            baos.flush();            ret = baos.toByteArray();            baos.close();        } catch (IOException e) {        } finally {            try {                if (instream != null)                    instream.close();            } catch (IOException e) {            }        }        return ret;    }    public void readFromJSON(JSONObject jsonObj) throws JSONException {        mUpdates.clear();        Object upAppItemObj = jsonObj.opt(JSON_UPAPPITEMS);        if (upAppItemObj != null) {            // 兼容两种更新接口数据            if (upAppItemObj instanceof JSONArray) {                parseUpdateArrayData(mUpdates, (JSONArray) upAppItemObj);            } else if (upAppItemObj instanceof JSONObject) {                int objCount = ((JSONObject) upAppItemObj).length();                parseUpdateObjData(mUpdates, (JSONObject) upAppItemObj, objCount);            } else {                // Can't resolve upappitems, do nothing.            }        }        mIgnores.clear();        Object ignoreAppItemObj = jsonObj.opt(JSON_IGNOREAPPITEMS);        if (ignoreAppItemObj != null) {            if (ignoreAppItemObj instanceof JSONArray) {                parseUpdateArrayData(mIgnores, (JSONArray) ignoreAppItemObj);            } else if (ignoreAppItemObj instanceof JSONObject) {                int objCount = ((JSONObject) ignoreAppItemObj).length();                parseUpdateObjData(mIgnores, (JSONObject) ignoreAppItemObj, objCount);            } else {                // Can't resolve ignoreappitems, do nothing.            }        }    }    private void parseUpdateObjData(List outList, JSONObject jsonObj, int objCount) {        int length = objCount;        if (jsonObj == null || objCount <= 0)            return;        for (int pos = 0; pos < length; ++pos) {            JSONObject updateObj = jsonObj.optJSONObject(String.valueOf(pos));            if (updateObj == null)                continue;            try {                AppUpdate update = new AppUpdate();                update.readFromJSON(updateObj);                outList.add(update);            } catch (JSONException e) {                continue;            }        }    }    private void parseUpdateArrayData(List outList, JSONArray jsonObj) {        JSONArray updateArray = jsonObj;        int length = 0;        if (updateArray != null && (length = updateArray.length()) > 0) {            for (int pos = 0; pos < length; ++pos) {                JSONObject updateObj = updateArray.optJSONObject(pos);                if (updateObj == null)                    continue;                try {                    AppUpdate update = new AppUpdate();                    update.readFromJSON(updateObj);                    outList.add(update);                } catch (JSONException e) {                    continue;                }            }        }    }    public JSONObject generateJSONObject() throws JSONException {        JSONObject ret = new JSONObject();        JSONArray array = new JSONArray();        for (AppUpdate update : mUpdates) {            if (update == null)                continue;            JSONObject updateObj = update.generateJSONObject();            array.put(updateObj);        }        ret.put(JSON_UPAPPITEMS, array);        array = new JSONArray();        for (AppUpdate update : mIgnores) {            if (update == null)                continue;            JSONObject updateObj = update.generateJSONObject();            array.put(updateObj);        }        ret.put(JSON_IGNOREAPPITEMS, array);        return ret;    }    @Override    public void onUpdate(ExpandableListAdapter.UpdateInfoHolder updateInfo) {    }    @Override    public void onIgnore(AppUpdate item) {    }    @Override    public void onRemoveIgnore(AppUpdate item) {    }}

核心东西是继承SimpleViewManager,实现protected ExpandableListView createViewInstance(ThemedReactContext reactContext)与getName(),这两个方法会自动调用。
REACT_CLASS可以说是组件对外发布的名称(ReactNative的js通过这个名字可以找到这个组件)。

    @ReactProp(name = "layoutWidth")    public void setLayoutWidth(ExpandableListView view, int layoutWidth) {    }
这个方法是ReactNative的js会传递layoutWidth属性过来(而且是数字类型),这是固定写法。

2、将ViewManager类注册到ReactPackage

package com.example.test.widget.reactnative.expandableListView;import com.facebook.react.ReactPackage;import com.facebook.react.bridge.JavaScriptModule;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.uimanager.ViewManager;import java.util.Arrays;import java.util.Collections;import java.util.List;/** * Created by Springever on 2017/5/18. */public class ExpandableReactPackage implements ReactPackage {    @Override    public List createNativeModules(ReactApplicationContext reactContext) {        return Collections.emptyList();    }    @Override    public List> createJSModules() {        return Collections.emptyList();    }    @Override    public List createViewManagers(ReactApplicationContext reactContext) {        return Arrays.asList(                new ReactExpandableListViewManager()        );    }}

3、将ReactPackage添加到application中(在ReactNative的启动Activity中添加)

addPackage(new ExpandableReactPackage())

package com.example.test.activity;import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Build;import android.os.Bundle;import android.provider.Settings;import android.view.KeyEvent;import com.example.test.BuildConfig;import com.example.test.widget.reactnative.expandableListView.ExpandableReactPackage;import com.facebook.react.ReactInstanceManager;import com.facebook.react.ReactRootView;import com.facebook.react.common.LifecycleState;import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;import com.facebook.react.shell.MainReactPackage;/** * Created by Springever on 2017/5/2. */public class ReactNativeActivity extends Activity implements DefaultHardwareBackBtnHandler {    private ReactRootView mReactRootView;    private ReactInstanceManager mReactInstanceManager;    private final static int OVERLAY_PERMISSION_REQ_CODE=1;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {            if (!Settings.canDrawOverlays(this)) {                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,                        Uri.parse("package:" + getPackageName()));                startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);            }        }        mReactRootView = new ReactRootView(this);        mReactInstanceManager = ReactInstanceManager.builder()                .setApplication(getApplication())                .setBundleAssetName("index.android.bundle")                .setJSMainModuleName("index.android")                .addPackage(new MainReactPackage())                .addPackage(new ExpandableReactPackage())                .setUseDeveloperSupport(BuildConfig.DEBUG)                .setInitialLifecycleState(LifecycleState.RESUMED)                .build();        // 注意这里的HelloWorld必须对应“index.android.js”中的        // “AppRegistry.registerComponent()”的第一个参数        mReactRootView.startReactApplication(mReactInstanceManager, "ReactNativeActivity", null);        setContentView(mReactRootView);    }    @Override    public void invokeDefaultOnBackPressed() {        super.onBackPressed();    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {                if (!Settings.canDrawOverlays(this)) {                    // SYSTEM_ALERT_WINDOW permission not granted...                }            }        }    }    @Override    public void onBackPressed() {        if (mReactInstanceManager != null) {            mReactInstanceManager.onBackPressed();        } else {            super.onBackPressed();        }    }    @Override    public boolean onKeyUp(int keyCode, KeyEvent event) {        if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {            mReactInstanceManager.showDevOptionsDialog();            return true;        }        return super.onKeyUp(keyCode, event);    }    @Override    protected void onPause() {        super.onPause();        if (mReactInstanceManager != null) {            mReactInstanceManager.onHostPause(this);        }    }    @Override    protected void onResume() {        super.onResume();        if (mReactInstanceManager != null) {            mReactInstanceManager.onHostResume(this, this);        }    }    @Override    protected void onDestroy() {        super.onDestroy();        if (mReactInstanceManager != null) {            mReactInstanceManager.onHostDestroy();        }    }}

4、编写ReactNative的ExpandableListView.js

RCTExpandableListView与ViewManager类中的REACT_CLASS一致

'use strict';import { PropTypes } from 'react';import { requireNativeComponent, View } from 'react-native';var iFace = {  name: 'ExpandableTextView',  /*  propTypes: {    src: PropTypes.string,    borderRadius: PropTypes.number,    resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),    ...View.propTypes // 包含默认的View的属性  },  */  propTypes: {    layoutWidth:  PropTypes.number,    layoutHeight: PropTypes.number,    ...View.propTypes  },};module.exports = requireNativeComponent('RCTExpandableListView', iFace);

5、ReactNative的index.anroid.js调用组件

Dimensions获得屏幕大小

var ExpandableListView = require('./android/lib/ExpandableListView');
const {width, height} = Dimensions.get('window');class SubScreen extends React.Component {  static navigationOptions = {    tabBarLabel: 'SubScreen',    tabBarIcon: ({ tintColor }) => (          ),  };  render() {    height=height-300;    return (                    Alert测试                        ExpandableListView测试                        );  }}

最后由于ReactNative的自定义的顶层容器改写了requestLayout(),导致重写等不能上传到顶层容器RootViewImpl,这样的后果是导致类似ListView的setData、notifyDataSetChanged方法失效,解决办法是在自定组件中重写requestLayout方法,先调用父类requestLayout,而后手动触发measure计算方法、layout布局方法。代码如下:

public class ReactExpandableListView extends ExpandableListView {    public ReactExpandableListView(Context context) {        super(context);    }    public ReactExpandableListView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public ReactExpandableListView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public ReactExpandableListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    private final Runnable measureAndLayout = new Runnable() {        @Override        public void run() {            measure(                    MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),                    MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));            layout(getLeft(), getTop(), getRight(), getBottom());        }    };    @Override    public void requestLayout() {        super.requestLayout();        // The spinner relies on a measure + layout pass happening after it calls requestLayout().        // Without this, the widget never actually changes the selection and doesn't call the        // appropriate listeners. Since we override onLayout in our ViewGroups, a layout pass never        // happens after a call to requestLayout, so we simulate one here.        post(measureAndLayout);    }}
这样,我们需要用ReactExpandableListView替代ExpandableListView。

最后ReactNative的js如何调用原生模块(比如某个方法),可以参考官网http://reactnative.cn/docs/0.44/native-modules-android.html#content ,这次官网写的是对的。

具体代码可以参考git:https://github.com/Springever/Test



更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. Android(安卓)AsyncTask
  5. Android(安卓)content provider基础与使用
  6. Android下Activity全屏显示实现方法
  7. Android获取mac地址方法,6.0以上也可用
  8. 利用HTML5开发Android
  9. android MultiDex multiDex原理(一)

随机推荐

  1. Android之应用资源的调用
  2. 新手学习linux需了解的内容
  3. 不仅是微软和诺基亚,谁都无法 fork Androi
  4. Android对Linux内核的增强:Low Memory Kil
  5. Android(安卓)应用程序
  6. Android的memory maps
  7. Android 开发视频推荐
  8. Android软件开发之盘点所有Dialog对话框
  9. android:绘图 (android.graphics包)
  10. android 跨应用程序广播发送接受