2 votes

React Native ReactContext cycle de vie bloqué sur BEFORE_CREATE

Je suis en train d'essayer d'exécuter un service en arrière-plan dans React-Native. D'après ce que j'ai entendu, je dois l'écrire en Java native et le connecter au code react-native. Lorsque j'essaie d'émettre un événement, j'obtiens une erreur:

Essai d'accéder à un module JS avant que l'instance React ne soit entièrement configurée. Les appels à ne doivent se produire qu'une fois que initialize() a été appelé sur votre module natif.

J'ai donc ajouté une vérification pour voir si le module est en cours d'exécution:

if (reactContext.getLifecycleState() == LifecycleState.RESUMED)

Mais cela renvoie toujours faux. Le cycle de vie est bloqué sur BEFORE_CREATE. Comment devrais-je émettre mon événement.

Service:

public class TestService extends Service {

double distance = 0.0;
ReactContext reactContext;

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    reactContext = new ReactContext(getApplicationContext());
    new Timer().scheduleAtFixedRate(new TimerTask(){
        @Override
        public void run(){
            WritableMap params = Arguments.createMap();
            distance+= 0.7;
            Log.d("LOG", "Trying to send distance: "+distance+" on lifecycle: "+reactContext.getLifecycleState());
            params.putDouble("distance", distance);
            sendEvent(reactContext, "updateDistance", params);
        }
    },0,1000);
    return START_STICKY;
}

private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
    if (reactContext.getLifecycleState() == LifecycleState.RESUMED) {
        reactContext.getJSModule(DeviceEventManagerModule
                .RCTDeviceEventEmitter.class)
                .emit(eventName, params);
        Log.d("LOG", "Sent distance: "+distance);
    }
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}
}

Module:

public class ServiceModule extends ReactContextBaseJavaModule {
ReactContext reactContext;

public ServiceModule(ReactApplicationContext reactContext) {
    super(reactContext);
    this.reactContext = reactContext;
    this.initialize();
}

@ReactMethod
public void startTrackingService() {
    Intent intent = new Intent(reactContext, TestService.class);
    reactContext.startService(intent);
}

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

Package:

public class ServicePackage implements ReactPackage {
@Override
public List createNativeModules(ReactApplicationContext reactContext) {
    List modules = new ArrayList<>();
    modules.add(new ServiceModule(reactContext));
    return modules;
}

@Override
public List> createJSModules() {
    return Collections.emptyList();
}

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

MainApplication:

@Override
protected List getPackages() {
  return Arrays.asList(
      new MainReactPackage(),
      new ReactNativePushNotificationPackage(),
      new ServicePackage()
  );
}

3voto

Haruspik Points 161

J'ai résolu le problème :) Dans le service que je créais, je créais un nouveau contexte à partir du contexte de base qui n'est PAS le même objet. La solution de contournement a été de diffuser les données depuis le service et ensuite de les envoyer à javascript.

Module de Service :

public class ServiceModule extends ReactContextBaseJavaModule {
public static String UPDATE = "updateDistance";
public static String DISTANCE = "distance";

private IntentFilter intentFilter;
private BroadcastReceiver receiver;

public ServiceModule(ReactApplicationContext reactContext) {
    super(reactContext);
    initializeBroadcastReceiver();
}

@ReactMethod
public void startTrackingService() {
    Intent intent = new Intent(getReactApplicationContext(), TestService.class);
    getReactApplicationContext().startService(intent);
}

@ReactMethod
public void stopTrackingService() {
    Intent intent = new Intent(getReactApplicationContext(), TestService.class);
    getReactApplicationContext().stopService(intent);
}

private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
    if (reactContext.hasActiveCatalystInstance()) {
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName, params);
    }
}

private void initializeBroadcastReceiver() {
    intentFilter = new IntentFilter();
    intentFilter.addAction(UPDATE);
    receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            WritableMap params = Arguments.createMap();
            params.putDouble(DISTANCE, intent.getDoubleExtra(DISTANCE, 0));
            sendEvent(getReactApplicationContext(), UPDATE, params);
        }
    };
    getReactApplicationContext().registerReceiver(receiver, intentFilter);
}

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

TestService :

public class TestService extends Service {

double distance = 0.0;

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    new Timer().scheduleAtFixedRate(new TimerTask(){
        @Override
        public void run(){
            Intent broadcastIntent = new Intent();
            broadcastIntent.setAction(ServiceModule.UPDATE);
            broadcastIntent.putExtra(ServiceModule.DISTANCE, distance);
            sendBroadcast(broadcastIntent);
            distance+= 0.7;
        }
    },0,1000);
    return START_STICKY;
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X