片段内的本机 [英] React-native inside a Fragment

查看:53
本文介绍了片段内的本机的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在片段内部开始本机反应? 将react-native放入Fragment时,onCreateView函数无法从mReactRootView返回View.

How to Start react-native inside of a fragment? While putting react-native inside Fragment, onCreateView function is unable to return View from mReactRootView.

View view = inflater.inflate(mReactRootView. , container, false);

推荐答案

我已经通过反复尝试来弄清楚了这一点.我已经在互联网上看到了这个问题,并认为这是发布答案的最佳位置.这是使用最新版本的React(撰写本文时为0.29)的方法:

I've managed to figure this out with much trial and error. I've seen this question asked around the internet and thought that this was the best place to post the answer. Here is how to do with the latest version of React (0.29 as of this writing):

我们要做的第一件事是创建一个抽象的ReactFragment类,我们将在整个应用程序中使用该类:

The first thing we'll do is create an abstract ReactFragment class that we will use throughout our app:

public abstract class ReactFragment extends Fragment {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    // This method returns the name of our top-level component to show
    public abstract String getMainComponentName();

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mReactRootView = new ReactRootView(context);
        mReactInstanceManager =
                ((MyApplication) getActivity().getApplication())
                        .getReactNativeHost()
                        .getReactInstanceManager();

    }

    @Override
    public ReactRootView onCreateView(LayoutInflater inflater, ViewGroup group, Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        return mReactRootView;
    }


    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mReactRootView.startReactApplication(
                mReactInstanceManager,
                getMainComponentName(),
                null
        );
    }
}

我们现在可以创建渲染React Native组件的片段,例如:

We'll now be able to create fragments that render React Native components, e.g.:

public class HelloFragment extends ReactFragment {
    @Override
    public String getMainComponentName() { 
        return "hellocomponent"; // name of our React Native component we've registered 
    }
}

不过,还需要做更多的工作.我们的父级Activity需要将某些内容传递到ReactInstanceManager中,以使React Native生命周期正常工作.这就是我最终得到的:

A little more work is required, though. Our parent Activity needs to pass some things into the ReactInstanceManager in order for the React Native lifecycle to work properly. Here's what I ended up with:

public class FragmentActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
    /*
    * Get the ReactInstanceManager, AKA the bridge between JS and Android
    * We use a singleton here so we can reuse the instance throughout our app
    * instead of constantly re-instantiating and re-downloading the bundle
    */
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        /**
         * Get the reference to the ReactInstanceManager
         */
         mReactInstanceManager =
             ((MyApplication) getApplication()).getReactNativeHost().getReactInstanceManager();


        /*
        * We can instantiate a fragment to show for Activity programmatically,
        * or using the layout XML files.
        * This doesn't necessarily have to be a ReactFragment, any Fragment type will do.
        */

        Fragment viewFragment = new HelloFragment();
        getFragmentManager().beginTransaction().add(R.id.container, viewFragment).commit();
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }

    /*
     * Any activity that uses the ReactFragment or ReactActivty
     * Needs to call onHostPause() on the ReactInstanceManager
     */
    @Override
    protected void onPause() {
        super.onPause();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause();
        }
    }

    /*
     * Same as onPause - need to call onHostResume
     * on our ReactInstanceManager
     */
    @Override
    protected void onResume() {
        super.onResume();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostResume(this, this);
        }
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
            mReactInstanceManager.showDevOptionsDialog();
            return true;
        } 
        return super.onKeyUp(keyCode, event);
    }
}

最后,您会在整个代码中注意到对(MyApplication)的引用;这是一个全局Application对象,包含我们的ReactInstanceManager,也就是Android和React Native之间的桥梁.这是React Native项目在内部使用的模式,因此我只是复制了它.这是它的实现方式:

Finally, you'll notice the reference to (MyApplication) throughout the code; this is a global Application object to contain our ReactInstanceManager, AKA the bridge between Android and React Native. This is the pattern that the React Native projects use internally, so I simply copied it. Here's how it's implemented:

public class MyApplication extends Application implements ReactApplication {
    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return true;
        }

        @Override
        public List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage()
            );
        }
    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }
}

最棘手的事情是弄清Fragment和Activity之间的生命周期; ReactRootView需要引用Activity上下文才能实例化,因此确保getActivity()不会为null很重要.另外,最初在父Activity中注册onHostPause()onHostResume()并不直观,但是一旦ReactNativeInstanceManager被抽象为一个全局变量而不是将其保留在Activity或Fragment上,最终证明更简单.

The trickiest bit was figuring out the lifecycle between the Fragment and the Activity; the ReactRootView needs a reference to the Activity context in order to instantiate, so making sure that getActivity() would not be null was important. Also, registering the onHostPause() and onHostResume() in the parent Activity was unintuitive at first, but ultimately proved simpler once the ReactNativeInstanceManager was abstracted away into a global instead of keeping it on the Activity or Fragment.

希望这可以帮助其他人!

Hope this helps someone else out there!

这篇关于片段内的本机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆