This is mi first post so I will try to show my problem in a clear way and I'm not an android developer with a basic kownledge of java.
I'm trying to run a socket IO client in my react-native app, as I inquire in order to achieve this I use Headless JS task to have this socket running in the background and even when the app is close, the user recieves a notification.
I have all the flow working well, but the only problem is that when I execute Background.stopService()
, the websocket do not disconect but the persistance notification disappear.
index.js (where I register the task)
const MyHeadlessTask = async () => {
const email = await AsyncStorage.getItem('email');
if (!!email) {
try {
let socket = SocketIOClient('url', {
transports: ['websocket'],
query: `email=${email}`
});
etc...
} catch (ex) {
console.log('[MyHeadlessTask() ex] ', ex)
}
}
};
AppRegistry.registerHeadlessTask('Background', () => MyHeadlessTask);
BackgroundEventService.java
public class BackgroundEventService extends HeadlessJsTaskService {
@Nullable
protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
WritableMap data = extras != null ? Arguments.fromBundle(extras) : Arguments.createMap();
return new HeadlessJsTaskConfig(
"Background",
data,
5000,
true
);
}
}
BackgroundModule.java
public class BackgroundModule extends ReactContextBaseJavaModule {
public static final String REACT_CLASS = "Background";
private static ReactApplicationContext reactContext;
public BackgroundModule(@Nonnull ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Nonnull
@Override
public String getName() {
return REACT_CLASS;
}
@ReactMethod
public void startService() {
this.reactContext.startService(new Intent(this.reactContext, BackgroundService.class));
}
@ReactMethod
public void stopService() {
this.reactContext.stopService(new Intent(this.reactContext, BackgroundService.class));
}
}
BackgroundPackage.java
public class BackgroundPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(
new BackgroundModule(reactContext)
);
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
MainApplication.java (add package)
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new BackgroundPackage());
return packages;
}
and this are the two ways that I writed BackgroundService.javafirst one
public class BackgroundService extends Service {
private static final int SERVICE_NOTIFICATION_ID = 12345;
private static final String CHANNEL_ID = "BACKGROUND";
private Handler handler = new Handler();
private Runnable runnableCode = new Runnable() {
@Override
public void run() {
Context context = getApplicationContext();
Intent myIntent = new Intent(context, BackgroundEventService.class);
context.startService(myIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
//handler.postDelayed(this, 2000);
}
};
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "BACKGROUND", importance);
channel.setDescription("CHANEL DESCRIPTION");
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
this.handler.removeCallbacks(this.runnableCode);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.handler.post(this.runnableCode);
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Safe Home")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(contentIntent)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setVisibility(Notification.VISIBILITY_SECRET)
.build();
startForeground(SERVICE_NOTIFICATION_ID, notification);
return START_STICKY;
}
}
second one
public class BackgroundService extends Service {
private static final int SERVICE_NOTIFICATION_ID = 12345;
private static final String CHANNEL_ID = "BACKGROUND";
private volatile boolean running = true;
private Thread thread;
private Runnable runnableCode = new Runnable() {
@Override
public void run() {
if (running) {
Context context = getApplicationContext();
Intent myIntent = new Intent(context, BackgroundEventService.class);
context.startService(myIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
} else {
Context context = getApplicationContext();
Intent myIntent = new Intent(context, BackgroundEventService.class);
context.stopService(myIntent);
}
}
};
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "BACKGROUND", importance);
channel.setDescription("CHANEL DESCRIPTION");
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
running = false;
this.thread.interrupt();
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.thread = new Thread(this.runnableCode);
this.thread.start();
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Safe Home")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(contentIntent)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setVisibility(Notification.VISIBILITY_SECRET)
.build();
startForeground(SERVICE_NOTIFICATION_ID, notification);
return START_STICKY;
}
}
This problem is giving me a headache, and I can't find a solution, I repeat everthing works well but it seems that the BackgroundEventService don't stop and the sockets still running, I try too many ways to stop the thread but nothing works for me.
Maybe i'm using wrongs concepts or the is an error in my code...