mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-02-14 22:36:21 +08:00
Release React Native for Android
This is an early release and there are several things that are known not to work if you're porting your iOS app to Android. See the Known Issues guide on the website. We will work with the community to reach platform parity with iOS.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.queue;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import android.os.Looper;
|
||||
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
|
||||
/**
|
||||
* Specifies which {@link MessageQueueThread}s must be used to run the various contexts of
|
||||
* execution within catalyst (Main UI thread, native modules, and JS). Some of these queues *may* be
|
||||
* the same but should be coded against as if they are different.
|
||||
*
|
||||
* UI Queue Thread: The standard Android main UI thread and Looper. Not configurable.
|
||||
* Native Modules Queue Thread: The thread and Looper that native modules are invoked on.
|
||||
* JS Queue Thread: The thread and Looper that JS is executed on.
|
||||
*/
|
||||
public class CatalystQueueConfiguration {
|
||||
|
||||
private final MessageQueueThread mUIQueueThread;
|
||||
private final MessageQueueThread mNativeModulesQueueThread;
|
||||
private final MessageQueueThread mJSQueueThread;
|
||||
|
||||
private CatalystQueueConfiguration(
|
||||
MessageQueueThread uiQueueThread,
|
||||
MessageQueueThread nativeModulesQueueThread,
|
||||
MessageQueueThread jsQueueThread) {
|
||||
mUIQueueThread = uiQueueThread;
|
||||
mNativeModulesQueueThread = nativeModulesQueueThread;
|
||||
mJSQueueThread = jsQueueThread;
|
||||
}
|
||||
|
||||
public MessageQueueThread getUIQueueThread() {
|
||||
return mUIQueueThread;
|
||||
}
|
||||
|
||||
public MessageQueueThread getNativeModulesQueueThread() {
|
||||
return mNativeModulesQueueThread;
|
||||
}
|
||||
|
||||
public MessageQueueThread getJSQueueThread() {
|
||||
return mJSQueueThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called when the corresponding {@link com.facebook.react.bridge.CatalystInstance}
|
||||
* is destroyed so that we shut down the proper queue threads.
|
||||
*/
|
||||
public void destroy() {
|
||||
if (mNativeModulesQueueThread.getLooper() != Looper.getMainLooper()) {
|
||||
mNativeModulesQueueThread.quitSynchronous();
|
||||
}
|
||||
if (mJSQueueThread.getLooper() != Looper.getMainLooper()) {
|
||||
mJSQueueThread.quitSynchronous();
|
||||
}
|
||||
}
|
||||
|
||||
public static CatalystQueueConfiguration create(
|
||||
CatalystQueueConfigurationSpec spec,
|
||||
QueueThreadExceptionHandler exceptionHandler) {
|
||||
Map<MessageQueueThreadSpec, MessageQueueThread> specsToThreads = MapBuilder.newHashMap();
|
||||
|
||||
MessageQueueThreadSpec uiThreadSpec = MessageQueueThreadSpec.mainThreadSpec();
|
||||
MessageQueueThread uiThread = MessageQueueThread.create( uiThreadSpec, exceptionHandler);
|
||||
specsToThreads.put(uiThreadSpec, uiThread);
|
||||
|
||||
MessageQueueThread jsThread = specsToThreads.get(spec.getJSQueueThreadSpec());
|
||||
if (jsThread == null) {
|
||||
jsThread = MessageQueueThread.create(spec.getJSQueueThreadSpec(), exceptionHandler);
|
||||
}
|
||||
|
||||
MessageQueueThread nativeModulesThread =
|
||||
specsToThreads.get(spec.getNativeModulesQueueThreadSpec());
|
||||
if (nativeModulesThread == null) {
|
||||
nativeModulesThread =
|
||||
MessageQueueThread.create(spec.getNativeModulesQueueThreadSpec(), exceptionHandler);
|
||||
}
|
||||
|
||||
return new CatalystQueueConfiguration(uiThread, nativeModulesThread, jsThread);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.queue;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
|
||||
/**
|
||||
* Spec for creating a CatalystQueueConfiguration. This exists so that CatalystInstance is able to
|
||||
* set Exception handlers on the MessageQueueThreads it uses and it would not be super clean if the
|
||||
* threads were configured, then passed to CatalystInstance where they are configured more. These
|
||||
* specs allows the Threads to be created fully configured.
|
||||
*/
|
||||
public class CatalystQueueConfigurationSpec {
|
||||
|
||||
private final MessageQueueThreadSpec mNativeModulesQueueThreadSpec;
|
||||
private final MessageQueueThreadSpec mJSQueueThreadSpec;
|
||||
|
||||
private CatalystQueueConfigurationSpec(
|
||||
MessageQueueThreadSpec nativeModulesQueueThreadSpec,
|
||||
MessageQueueThreadSpec jsQueueThreadSpec) {
|
||||
mNativeModulesQueueThreadSpec = nativeModulesQueueThreadSpec;
|
||||
mJSQueueThreadSpec = jsQueueThreadSpec;
|
||||
}
|
||||
|
||||
public MessageQueueThreadSpec getNativeModulesQueueThreadSpec() {
|
||||
return mNativeModulesQueueThreadSpec;
|
||||
}
|
||||
|
||||
public MessageQueueThreadSpec getJSQueueThreadSpec() {
|
||||
return mJSQueueThreadSpec;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static CatalystQueueConfigurationSpec createDefault() {
|
||||
return builder()
|
||||
.setJSQueueThreadSpec(MessageQueueThreadSpec.newBackgroundThreadSpec("js"))
|
||||
.setNativeModulesQueueThreadSpec(
|
||||
MessageQueueThreadSpec.newBackgroundThreadSpec("native_modules"))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private @Nullable MessageQueueThreadSpec mNativeModulesQueueSpec;
|
||||
private @Nullable MessageQueueThreadSpec mJSQueueSpec;
|
||||
|
||||
public Builder setNativeModulesQueueThreadSpec(MessageQueueThreadSpec spec) {
|
||||
Assertions.assertCondition(
|
||||
mNativeModulesQueueSpec == null,
|
||||
"Setting native modules queue spec multiple times!");
|
||||
mNativeModulesQueueSpec = spec;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJSQueueThreadSpec(MessageQueueThreadSpec spec) {
|
||||
Assertions.assertCondition(mJSQueueSpec == null, "Setting JS queue multiple times!");
|
||||
mJSQueueSpec = spec;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CatalystQueueConfigurationSpec build() {
|
||||
return new CatalystQueueConfigurationSpec(
|
||||
Assertions.assertNotNull(mNativeModulesQueueSpec),
|
||||
Assertions.assertNotNull(mJSQueueSpec));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.queue;
|
||||
|
||||
import android.os.Looper;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.bridge.AssertionException;
|
||||
import com.facebook.react.bridge.SoftAssertions;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.futures.SimpleSettableFuture;
|
||||
|
||||
/**
|
||||
* Encapsulates a Thread that has a {@link Looper} running on it that can accept Runnables.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class MessageQueueThread {
|
||||
|
||||
private final String mName;
|
||||
private final Looper mLooper;
|
||||
private final MessageQueueThreadHandler mHandler;
|
||||
private final String mAssertionErrorMessage;
|
||||
private volatile boolean mIsFinished = false;
|
||||
|
||||
private MessageQueueThread(
|
||||
String name,
|
||||
Looper looper,
|
||||
QueueThreadExceptionHandler exceptionHandler) {
|
||||
mName = name;
|
||||
mLooper = looper;
|
||||
mHandler = new MessageQueueThreadHandler(looper, exceptionHandler);
|
||||
mAssertionErrorMessage = "Expected to be called from the '" + getName() + "' thread!";
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given Runnable on this Thread. It will be submitted to the end of the event queue even
|
||||
* if it is being submitted from the same queue Thread.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public void runOnQueue(Runnable runnable) {
|
||||
if (mIsFinished) {
|
||||
FLog.w(
|
||||
ReactConstants.TAG,
|
||||
"Tried to enqueue runnable on already finished thread: '" + getName() +
|
||||
"... dropping Runnable.");
|
||||
}
|
||||
mHandler.post(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the current Thread is also the Thread associated with this MessageQueueThread.
|
||||
*/
|
||||
public boolean isOnThread() {
|
||||
return mLooper.getThread() == Thread.currentThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts {@link #isOnThread()}, throwing a {@link AssertionException} (NOT an
|
||||
* {@link AssertionError}) if the assertion fails.
|
||||
*/
|
||||
public void assertIsOnThread() {
|
||||
SoftAssertions.assertCondition(isOnThread(), mAssertionErrorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quits this queue's Looper. If that Looper was running on a different Thread than the current
|
||||
* Thread, also waits for the last message being processed to finish and the Thread to die.
|
||||
*/
|
||||
public void quitSynchronous() {
|
||||
mIsFinished = true;
|
||||
mLooper.quit();
|
||||
if (mLooper.getThread() != Thread.currentThread()) {
|
||||
try {
|
||||
mLooper.getThread().join();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Got interrupted waiting to join thread " + mName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Looper getLooper() {
|
||||
return mLooper;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public static MessageQueueThread create(
|
||||
MessageQueueThreadSpec spec,
|
||||
QueueThreadExceptionHandler exceptionHandler) {
|
||||
switch (spec.getThreadType()) {
|
||||
case MAIN_UI:
|
||||
return createForMainThread(spec.getName(), exceptionHandler);
|
||||
case NEW_BACKGROUND:
|
||||
return startNewBackgroundThread(spec.getName(), exceptionHandler);
|
||||
default:
|
||||
throw new RuntimeException("Unknown thread type: " + spec.getThreadType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a MessageQueueThread corresponding to Android's main UI thread.
|
||||
*/
|
||||
private static MessageQueueThread createForMainThread(
|
||||
String name,
|
||||
QueueThreadExceptionHandler exceptionHandler) {
|
||||
Looper mainLooper = Looper.getMainLooper();
|
||||
return new MessageQueueThread(name, mainLooper, exceptionHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and starts a new MessageQueueThread encapsulating a new Thread with a new Looper
|
||||
* running on it. Give it a name for easier debugging. When this method exits, the new
|
||||
* MessageQueueThread is ready to receive events.
|
||||
*/
|
||||
private static MessageQueueThread startNewBackgroundThread(
|
||||
String name,
|
||||
QueueThreadExceptionHandler exceptionHandler) {
|
||||
final SimpleSettableFuture<Looper> simpleSettableFuture = new SimpleSettableFuture<>();
|
||||
Thread bgThread = new Thread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
|
||||
simpleSettableFuture.set(Looper.myLooper());
|
||||
|
||||
Looper.loop();
|
||||
}
|
||||
}, "mqt_" + name);
|
||||
bgThread.start();
|
||||
|
||||
return new MessageQueueThread(name, simpleSettableFuture.get(5000), exceptionHandler);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.queue;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
/**
|
||||
* Handler that can catch and dispatch Exceptions to an Exception handler.
|
||||
*/
|
||||
public class MessageQueueThreadHandler extends Handler {
|
||||
|
||||
private final QueueThreadExceptionHandler mExceptionHandler;
|
||||
|
||||
public MessageQueueThreadHandler(Looper looper, QueueThreadExceptionHandler exceptionHandler) {
|
||||
super(looper);
|
||||
mExceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchMessage(Message msg) {
|
||||
try {
|
||||
super.dispatchMessage(msg);
|
||||
} catch (Exception e) {
|
||||
mExceptionHandler.handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.queue;
|
||||
|
||||
/**
|
||||
* Spec for creating a MessageQueueThread.
|
||||
*/
|
||||
public class MessageQueueThreadSpec {
|
||||
|
||||
private static final MessageQueueThreadSpec MAIN_UI_SPEC =
|
||||
new MessageQueueThreadSpec(ThreadType.MAIN_UI, "main_ui");
|
||||
|
||||
protected static enum ThreadType {
|
||||
MAIN_UI,
|
||||
NEW_BACKGROUND,
|
||||
}
|
||||
|
||||
public static MessageQueueThreadSpec newBackgroundThreadSpec(String name) {
|
||||
return new MessageQueueThreadSpec(ThreadType.NEW_BACKGROUND, name);
|
||||
}
|
||||
|
||||
public static MessageQueueThreadSpec mainThreadSpec() {
|
||||
return MAIN_UI_SPEC;
|
||||
}
|
||||
|
||||
private final ThreadType mThreadType;
|
||||
private final String mName;
|
||||
|
||||
private MessageQueueThreadSpec(ThreadType threadType, String name) {
|
||||
mThreadType = threadType;
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public ThreadType getThreadType() {
|
||||
return mThreadType;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.queue;
|
||||
|
||||
import com.facebook.jni.Countable;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
||||
/**
|
||||
* A Runnable that has a native run implementation.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class NativeRunnable extends Countable implements Runnable {
|
||||
|
||||
/**
|
||||
* Should only be instantiated via native (JNI) code.
|
||||
*/
|
||||
@DoNotStrip
|
||||
private NativeRunnable() {
|
||||
}
|
||||
|
||||
public native void run();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.queue;
|
||||
|
||||
/**
|
||||
* Interface for a class that knows how to handle an Exception thrown while executing a Runnable
|
||||
* submitted via {@link MessageQueueThread#runOnQueue}.
|
||||
*/
|
||||
public interface QueueThreadExceptionHandler {
|
||||
|
||||
void handleException(Exception e);
|
||||
}
|
||||
Reference in New Issue
Block a user