android - 带有 React Native 和 Headless JS 的 Socket IO,无法杀死它
问题描述
这是我的第一篇文章,所以我将尝试以清晰的方式展示我的问题,而且我不是具有基本 java 知识的 android 开发人员。
我正在尝试在我的 react-native 应用程序中运行套接字 IO 客户端,因为我询问为了实现这一点,我使用 Headless JS 任务让这个套接字在后台运行,即使应用程序关闭,用户也会收到一个通知。
我的所有流程都运行良好,但唯一的问题是当我执行时Background.stopService()
,websocket 不会断开连接,但持久性通知会消失。
index.js(我注册任务的地方)
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);
背景事件服务.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
);
}
}
背景模块.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));
}
}
背景包.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(添加包)
@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;
}
这是我第一个编写BackgroundService.java的两种方式
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;
}
}
第二个
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;
}
}
这个问题让我头疼,我找不到解决方案,我重复一切都很好但似乎BackgroundEventService没有停止并且套接字仍在运行,我尝试了太多方法来停止线程但没有任何效果为了我。也许我使用了错误的概念,或者是我的代码中的错误......
解决方案
我能够通过全局分配它来关闭套接字。在你的无头任务中:
const headlessTask = async () => {
global.socket = SocketIOClient('url', {
transports: ['websocket'],
query: `email=${email}`
});
// Rest...
}
然后,在调用时,stopService
我们只需像这样关闭它:
const stopService = () => {
global.socket.close();
Background.stopService();
}
推荐阅读
- java - Tomcat 与 Java 11 部署问题
- python - 修改现有代码以从 API 获取搜索结果
- java - JUnit 使用 Mockito 测试异步方法
- java - 自动数据绑定
- android - 在 Android 上使用带有 USB 电缆的 ADB 时,运行 shell 时的权限是什么?
- laravel - 如何收听 Laravel 中的所有更新?
- google-cloud-platform - GCP 计算 - RDP 替代方案?
- terraform - 在 terraform 中重命名时,有什么方法可以自动将对象从旧存储桶转移到新存储桶?
- loops - 空白、Null 或空字段的访问检查
- x86 - Phoenix BIOS 跳过 MBR 代码,ACTUAL BIOS 标准是什么?