Skip to content

Commit

Permalink
fix(Android): Switch to Java Standard concurrent API (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rapsssito committed Nov 28, 2020
1 parent 900a15c commit 373edf0
Showing 1 changed file with 50 additions and 66 deletions.
116 changes: 50 additions & 66 deletions android/src/main/java/com/tradle/react/UdpSockets.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
/**
* UdpSockets.java
* react-native-udp
*
* Created by Andy Prock on 9/24/15.
*/

package com.tradle.react;

import android.content.Context;
import android.net.wifi.WifiManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import android.util.SparseArray;
import android.os.AsyncTask;

import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.GuardedAsyncTask;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
Expand All @@ -28,57 +22,46 @@
import java.io.IOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* The NativeModule in charge of storing active {@link UdpSocketClient}s, and acting as an api layer.
*/
public final class UdpSockets extends ReactContextBaseJavaModule
implements UdpSocketClient.OnDataReceivedListener, UdpSocketClient.OnRuntimeExceptionListener {
implements UdpSocketClient.OnDataReceivedListener, UdpSocketClient.OnRuntimeExceptionListener {
private static final String TAG = "UdpSockets";
private WifiManager.MulticastLock mMulticastLock;
private static final int N_THREADS = 2;

private SparseArray<UdpSocketClient> mClients = new SparseArray<UdpSocketClient>();
private boolean mShuttingDown = false;
private WifiManager.MulticastLock mMulticastLock;
private final SparseArray<UdpSocketClient> mClients = new SparseArray<>();
private final ExecutorService executorService = Executors.newFixedThreadPool(N_THREADS);

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

@NonNull
@Override
public String getName() {
return TAG;
}

@Override
public void initialize() {
mShuttingDown = false;
}

@Override
public void onCatalystInstanceDestroy() {
mShuttingDown = true;

// serialize on the AsyncTask thread, and block
try {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
protected void doInBackgroundGuarded(Void... params) {
for (int i = 0; i < mClients.size(); i++) {
try {
mClients.valueAt(i).close();
} catch (IOException e) {
FLog.e(TAG, "exception when shutting down", e);
}
executorService.execute(new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < mClients.size(); i++) {
try {
mClients.valueAt(i).close();
} catch (IOException e) {
FLog.e(TAG, "exception when shutting down", e);
}
mClients.clear();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR).get();
} catch (InterruptedException ioe) {
FLog.e(TAG, "onCatalystInstanceDestroy", ioe);
} catch (ExecutionException ee) {
FLog.e(TAG, "onCatalystInstanceDestroy", ee);
}
mClients.clear();
}
}));
}

/**
Expand Down Expand Up @@ -123,12 +106,12 @@ public void createSocket(final Integer cId, final ReadableMap options) {
@ReactMethod
public void bind(final Integer cId, final Integer port, final @Nullable String address, final @Nullable ReadableMap options,
final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
executorService.execute(new Thread(new Runnable() {
@Override
protected void doInBackgroundGuarded(Void... params) {
public void run() {
UdpSocketClient client = findClient(cId, callback);
if (client == null) {
return;
return;
}

try {
Expand All @@ -150,31 +133,32 @@ protected void doInBackgroundGuarded(Void... params) {
callback.invoke(UdpErrorUtil.getError(null, ioe.getMessage()));
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}));
}

/**
* Joins a multi-cast group
*/
@SuppressWarnings("unused")
@ReactMethod
public void addMembership(final Integer cId, final String multicastAddress) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
executorService.execute(new Thread(new Runnable() {
@Override
protected void doInBackgroundGuarded(Void... params) {
public void run() {
UdpSocketClient client = findClient(cId, null);
if (client == null) {
return;
}

if (mMulticastLock == null) {
WifiManager wifiMgr = (WifiManager) getReactApplicationContext()
.getApplicationContext()
.getSystemService(Context.WIFI_SERVICE);
.getApplicationContext()
.getSystemService(Context.WIFI_SERVICE);
mMulticastLock = wifiMgr.createMulticastLock("react-native-udp");
mMulticastLock.setReferenceCounted(true);
}

try {
try {
mMulticastLock.acquire();
client.addMembership(multicastAddress);
} catch (IllegalStateException ise) {
Expand All @@ -197,17 +181,17 @@ protected void doInBackgroundGuarded(Void... params) {
FLog.e(TAG, "addMembership", ioe);
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}));
}

/**
* Leaves a multi-cast group
*/
@ReactMethod
public void dropMembership(final Integer cId, final String multicastAddress) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
executorService.execute(new Thread(new Runnable() {
@Override
protected void doInBackgroundGuarded(Void... params) {
public void run() {
UdpSocketClient client = findClient(cId, null);
if (client == null) {
return;
Expand All @@ -224,7 +208,7 @@ protected void doInBackgroundGuarded(Void... params) {
}
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}));
}

/**
Expand All @@ -233,9 +217,9 @@ protected void doInBackgroundGuarded(Void... params) {
@ReactMethod
public void send(final Integer cId, final String base64String,
final Integer port, final String address, final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
executorService.execute(new Thread(new Runnable() {
@Override
protected void doInBackgroundGuarded(Void... params) {
public void run() {
UdpSocketClient client = findClient(cId, callback);
if (client == null) {
return;
Expand All @@ -245,24 +229,24 @@ protected void doInBackgroundGuarded(Void... params) {
client.send(base64String, port, address, callback);
} catch (IllegalStateException ise) {
callback.invoke(UdpErrorUtil.getError(null, ise.getMessage()));
}catch (UnknownHostException uhe) {
} catch (UnknownHostException uhe) {
callback.invoke(UdpErrorUtil.getError(null, uhe.getMessage()));
} catch (IOException ioe) {
// an exception occurred
callback.invoke(UdpErrorUtil.getError(null, ioe.getMessage()));
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}));
}

/**
* Closes a specific client's socket, and removes it from the list of known clients.
*/
@ReactMethod
public void close(final Integer cId, final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
executorService.execute(new Thread(new Runnable() {
@Override
protected void doInBackgroundGuarded(Void... params) {
public void run() {
UdpSocketClient client = findClient(cId, callback);
if (client == null) {
return;
Expand All @@ -282,17 +266,17 @@ protected void doInBackgroundGuarded(Void... params) {

mClients.remove(cId);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}));
}

/**
* Sets the broadcast flag for a given client.
*/
@ReactMethod
public void setBroadcast(final Integer cId, final Boolean flag, final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
executorService.execute(new Thread(new Runnable() {
@Override
protected void doInBackgroundGuarded(Void... params) {
public void run() {
UdpSocketClient client = findClient(cId, callback);
if (client == null) {
return;
Expand All @@ -305,19 +289,19 @@ protected void doInBackgroundGuarded(Void... params) {
callback.invoke(UdpErrorUtil.getError(null, e.getMessage()));
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}));
}

/**
* Notifies the javascript layer upon data receipt.
*/
@Override
public void didReceiveData(final UdpSocketClient socket, final String data, final String host, final int port) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
executorService.execute(new Thread(new Runnable() {
@Override
protected void doInBackgroundGuarded(Void... params) {
public void run() {
int clientID = -1;
for(int i = 0; i < mClients.size(); i++) {
for (int i = 0; i < mClients.size(); i++) {
clientID = mClients.keyAt(i);
// get the object by the key.
if (socket.equals(mClients.get(clientID))) {
Expand All @@ -339,7 +323,7 @@ protected void doInBackgroundGuarded(Void... params) {
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("udp-" + clientID + "-data", eventParams);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}));
}

/**
Expand Down

0 comments on commit 373edf0

Please sign in to comment.