Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how does the ReadableMap interface in React-native convert JS to JAVA?

I'm trying to understand how to properly pass options from the js side of react-native to the java side.

The react-native bridge uses ReadableMap to convert but as a Java noob I'm failing to understand how this works.

More specifically I don't understand:

  • how the actual conversion works?
  • how to tell what type/format the downstream Java code wants?
  • how to properly use ReadableMap to do this?

Generally I would like to know how this works but I'll give the specific example I'm looking at to give some context.


A react-native package exposes a datetime picker.

The JS side has a showTimePicker method:

showTimePicker(date, callback) {
    date = date || new Date();
    console.log(this.props);
    debugger
    var options = {
        ...this.props,
        hour:date.getHours(),
        minute:date.getMinutes()
    };
    RCTDateTimePicker.showTimePicker(options, function (hour, minute) {
        date.setHours(hour);
        date.setMinutes(minute);
        callback(date);
    });
}

RCTDateTimePicker.showTimePicker is bridged to a Java method on the native side:

@ReactMethod
public void showTimePicker(ReadableMap options, Callback callback) {
    DialogFragment timePicker = new TimePicker(options, callback);
    timePicker.show(activity.getFragmentManager(), "timePicker");
}

which calls

public TimePicker(ReadableMap options, Callback callback) {
    final Calendar c = Calendar.getInstance();
    this.callback = callback;
    hour = options.hasKey("hour") ? options.getInt("hour") : c.get(Calendar.HOUR_OF_DAY);
    minute = options.hasKey("minute") ? options.getInt("minute") : c.get(Calendar.MINUTE);
}

which creates and instance of an Android TimePicker. My goal is to change the style of the Timepicker from watch to spinner.

There is a settable XML attribute android:timePickerMode="spinner" but I don't think I can pass an XML attribute through react-native can I?

I also found a suggestion in comments to pass defStyleAttr to do this, but I don't understand how.

like image 829
funkyeah Avatar asked Jul 21 '16 07:07

funkyeah


1 Answers

First, see the list of Argument Types from the React Native document for Android Native Modules.

Argument Types

The following argument types are supported for methods annotated with @ReactMethod and they directly map to their JavaScript equivalents

  • Boolean -> Bool
  • Integer -> Number
  • Double -> Number
  • Float -> Number
  • String -> String
  • Callback -> function
  • ReadableMap -> Object
  • ReadableArray -> Array

So, you can pass the extra field for timePickerMode as a String by updating the options that the JS side passes to include it.

var options = {
    ...this.props,
    hour:date.getHours(),
    minute:date.getMinutes(),
    timePickerMode:"spinner"
};

And then get that value from the ReadableMap in your custom TimePicker constructor.

String timePickerMode = options.hasKey("timePickerMode") ?
        options.getString("timePickerMode") : defaultTimePickerMode;

Now you have the value you wish to set. Unfortunately it does not appear that timePickerMode can be set programmatically. This SO question asks how to do it and @alanv (whose profile indicates they are a Software Engineer at Google) indicates that it is not possible at runtime.

like image 60
mpkuth Avatar answered Sep 19 '22 19:09

mpkuth