ReactNative与Android原生交互

ReactNative调用原生

通过原生向ReactNative中注入方法来实现。

第一步:自定义Module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class ToastModule extends ReactContextBaseJavaModule {
private static final String DURATION_SHORT_KEY = "SHORT";
private static final String DURATION_LONG_KEY = "LONG";

public ToastModule(ReactApplicationContext reactContext) {
super(reactContext);
}

@Override
public String getName() {
return "Toast";
}

@ReactMethod
public void show(final String message) {
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getReactApplicationContext(), message, Toast.SHORT).show();
}
});
}

@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
return constants;
}
}

@ReactMethod注解的方法才会被注入到RN中,getConstants用于向RN注入常量。

被@ReactMethod注解方法支持的参数类型
1
2
3
4
5
6
7
8
Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array

第二步:自定义Package

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ToastPackage implements ReactPackage {

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ToastModule(reactContext));
return modules;
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

第三步:注入到ReactNative

ReactNative集成原生则是在对应的MainApplication中通过getPackages方法注入。

1
2
3
4
5
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new ToastPackage());
}

若是原生集成ReactNative则是在构建ReactInstanceManager时通过ReactInstanceManager.BuilderaddPackage注入。

1
2
3
4
5
6
7
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.addPackage(new MainReactPackage())
.addPackage(new ToastPackage())
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();

第四步:在RN中调用

1
2
3
4
5
import {NativeModules} from 'react-native';

const Toast = NativeModules.Toast;

Toast.show("Toast", Toast.SHORT);

原生回调ReactNative

Callbacks

原生Module也支持Callback参数类型,用于返回结果到Js。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class LoginModule extends ReactContextBaseJavaModule{
···
@ReactMethod
public void login(String acount,String pwd,
Callback error,
Callback success){
if (login(acount,pwd)){
success.invoke("1");
}else{
error.invoke("0");
}
}
}

Js

1
2
3
4
5
Login.login("123","456",(msg) => {
console.log(msg);
},(msg) => {
console.log(msg);
});

参考链接

native-modules-android

React Native 原生模块和 JS 模块交互

ReactNative实现js和原生交互

Kotlin与Java通信

简介

Kotlin 是一个用于现代多平台应用的静态编程语言,由JetBrains公司开发。
Kotlin 在设计时就考虑了 Java 互操作性,因此 Kotlin 完全兼容 Java 代码;
但是在使用过程中还是有可能会出现一些小的问题。

Java调用Kotlin方法传入空对象

如果Kotlin文件声明的方法的参数列表为非空类型,在纯 Kotlin 代码的调用,编译器会帮你完成空检测。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Hello.kt
class Foo {
companion object {
fun bar(name: String) {
print(name)
}
}
}

//Hello1.kt
fun main(args: Array<String>) {
Foo.bar(null) //编译不通过
}

但是当 Java 调用 Kotlin 时则不一样,编译器无法帮你识别 Java 传递的参数是否是非空类型。

1
2
3
4
//Hello2.java
public static void main(String[] args) {
Foo.Companion.bar(null);
}

以上代码在编译时不会出错,但运行时则会报如下错误。

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Foo$Companion.bar, parameter name

Kotlin 在声明供 Java 调用的方法时参数列表应该声明为可空类型。

1
2
3
4
// Hello.kt
fun bar(name: String?) {
print(name)
}

kotlin空安全

简介

此文档记做Kotlin开发过程中遇到的问题以及总结

空安全

可空对象

Kotlin与Java不同,对象分为可空和不可空,可空在类型声明后加 ?

var b : String?

若类型为不可空,此时赋空编译器则会报错。

var b : String = "1"
b = null  // 编译不通过

安全的类型转换

Java在类型转换时,如果类型不匹配则会出现类型强转异常ClassCastException导致Crash;而Kotlin则可以采取安全的类型转换。

// 若a的类型不为Int则返回null,不会导致crash
val aInt: Int? = a as? Int 

安全的调用

在使用可能为空的对象时,Java中若不进行空判断则非常容易产生空指针异常,所以经常会出现下面的代码。

if (不为空) { } else { }

而Kotlin中可以采用安全的调用方式。

// 如果 b 非空,就返回 b.length;否则返回 null
val bLength: Int? = b?.length 

若想对非空值执行某个操作,安全调用操作符可以与 let 一起使用。

bLength?.let{
    // 具体逻辑
}
// 只有bLength不为空时才会执行lambda表达式

Elvis操作符

当我们有一个可空的引用 b 时,我们可以说 如果 b 非空,我使用它;否则使用某个非空的值 x

val bLength: Int = if (b != null) b.length else -1

除了采用if的方式还可以使用elvis操作符?:,与Java中的三目表达式类似:

// 如果 ?: 左侧表达式非空,elvis 操作符就调用其左侧表达式,否则调用右侧表达式。
val bLength = b?.length ?: -1

!! 操作符

若想抛出空指针异常NPE

// 若b为空则抛出空指针异常
val bLength = b!!.length

Git小结

简介

Git作为开源的分布式版本控制系统,很多开源项目都使用Git用作版本控制。

安装

Google、百度,不予赘述。

命令补全

Git默认是无法自动补全命令,需要添加自动补全脚本。
下载自动补全脚本,放在用户主目录下,并将下面一行添加至 .bashrc 文件中。

1
source ~/.git-completion.bash

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
git init // 初始化仓库
git clone [url] // 克隆现有仓库
git add -u // 将所有已跟踪的文件的改动添加至暂存区
git add -A // 将所有操作添加至暂存区
git add . // 同上
git commit <-m 添加提交说明> <-s 对本次提交签名> // 提交
git reset --soft HEAD~ // 将版本库重置为HEAD指针指向的提交的父提交,暂存区与工作区不变
git reset --mixed HEAD~ // 将版本库与暂存区重置为HEAD指针指向的提交的父提交,工作区不变
git reset HEAD~ // 缺省行为,同上
git reset --hard HEAD~ // 将版本库与暂存区和工作区重置为HEAD指针指向的提交的父提交
git checkout -- <file> // 放弃已修改的内容
git checkout <branchName> // 切换分支
git checkout -b <branchName> // 创建分支并切换
git remote // 列出所有远程主机
git remote -v // 查看远程主机的网址
git remote show <主机名> // 查看远程主机的详细信息
git remote add <主机名> <Url> // 添加远程主机
git remote rm <主机名> // 删除远程主机
git remote rename <原主机名> <新主机名> // 远程主机改名
git fetch <远程主机名> // 将远程主机的更新全部取回本地
git fetch <远程主机名> <分支名> // 获取远程主机特定分支的更新
git pull <远程主机名> <远程分支名>:<本地分支名> // 获取远程分支的更新并与本地分支合并
git pull <远程主机名> <远程分支名> // 获取远程分支更新并与当前分支合并
git push <远程主机名> <本地分支名>:<远程分支名> // 将本地分支推送至远程分支
git push <远程主机名> <本地分支名> // 将本地分支推送至存在“追踪关系”的远程分支,若远程分支不存在则会被新建
git push origin :<远程分支名> // 删除指定远程分支
git push origin --delete <远程分支名> // 同上
git log <-p 查看提交的内容差异> <-n 显示最近n次提交>
git log -U1 --word-diff // 获取单词层面的对比
git log --stat // 显示简要的增改行数统计
git diff <filename> // 工作区vs暂存区
git diff <branch> <filename> // 与另一个分支比较
git diff --cached <filename> // 暂存区vs仓库
git diff --cached <commit> <filename> // 暂存区vs指导提交
git diff git diff <commit> <filename> // 工作目录vs仓库
git diff <commit> <commit> // 两次提交对比
HEAD 最近一次 commit
HEAD^ 上次提交
HEAD~100 上100次提交

参考

Git远程操作详解
Git-远程分支,远程跟踪分支,跟踪分支的区别
代码回滚:Reset、Checkout、Revert 的选择
常用 Git 命令清单