1

我使用 Ably API 作为在两个 Android 设备(手机)之间进行通信的一种方式。第一个是“”,它向第二个(“从”)发送请求。“ Slave ”的主要部分是后台服务,等待主人的命令。一旦来自服务器的请求到达,服务器获取其地理位置并将其发送回服务器。问题是,当机处于打盹模式时,Ably 不起作用(' onMessage ' 方法不起作用),直到我唤醒手机。同时, “即使手机处于“睡眠状态”,它也能正常工作。有什么办法可以解决这个问题吗?这是我的服务代码。

package ru.volganap.nikolay.kids_monitor_ably;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.LocationManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.telephony.SmsManager;
import android.util.Log;
import android.app.Service;
import android.os.IBinder;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import androidx.core.app.NotificationCompat;

import io.ably.lib.realtime.AblyRealtime;
import io.ably.lib.realtime.Channel;
import io.ably.lib.realtime.CompletionListener;
import io.ably.lib.types.AblyException;
import io.ably.lib.types.ErrorInfo;
import io.ably.lib.types.Message;

public class KidService extends Service implements KM_Constants {*emphasized text*
    private SharedPreferences sharedPrefs;
    BroadcastReceiver mainBroadcastReceiver;
    private String parent_sender;
    FindGeoPos fg;
    private NotificationManager notificationManager;

private static final int NOTIFY_ID = 101;
private static final String NOTIFY_CHANNEL_ID = "CHANNEL_ID";
public static final int DEFAULT_NOTIFICATION_ID = 101;
private Channel channel;

public void onCreate() {
    super.onCreate();
    Log.d(LOG_TAG, "Service: onCreate");
    //EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
    sharedPrefs = getSharedPreferences(PREF_ACTIVITY, MODE_PRIVATE);
    notificationManager = (NotificationManager) this.getSystemService(this.NOTIFICATION_SERVICE);
    try {   //Init ABLY
        AblyRealtime ablyRealtime = new AblyRealtime(ABLY_API_KEY);
        channel = ablyRealtime.channels.get(ABLY_ROOM);
        channel.subscribe(PARENT_PHONE, new Channel.MessageListener() {
            @Override
            public void onMessage(Message messages) {
                Log.d(LOG_TAG, "Service - Ably message received: " + messages.data);
                if (messages.name.equals(PARENT_PHONE) && messages.data.equals(getResources().getString(R.string.parent_sms))) {
                    getPosition();
                }
            }
        });
    } catch (AblyException e) {
        e.printStackTrace();
    }
}

@SuppressLint("MissingPermission")
public int onStartCommand(Intent intent, int flags, int startId) {
    if (startId > 1) {
        stopSelf(startId);
    }
    Log.d(LOG_TAG, "Service: onStartCommand, starId = " + startId + ", flags = " + flags);
    //Send Foreground Notification
    sendNotification("KMService","");

    if (!EventBus.getDefault().hasSubscriberForEvent(KidService.class)) {
        EventBus.getDefault().register(this);
    }
    //Init SMS Receiver
    IntentFilter filter = new IntentFilter();
    filter.addAction(ACTION_FROM_BR);
    mainBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null) {
                parent_sender = intent.getStringExtra("sender");
                Log.d(LOG_TAG, "Service: Get back with Sender-parent");
                getPosition();
            }
        }
    };
    registerReceiver(mainBroadcastReceiver, filter);
    return START_STICKY;
}

public void sendNotification(String Title,String Text) {

    Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
    //notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
    notificationIntent.setAction(Intent.ACTION_MAIN);
    PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), NOTIFY_CHANNEL_ID)
                    .setOngoing(true)
                    .setSmallIcon(R.drawable.ic_stat_name)
                    .setWhen(System.currentTimeMillis())
                    .setContentIntent(contentIntent)
                    .setContentTitle(Title)
                    .setContentText(Text);
                    //.setPriority(PRIORITY_HIGH);

    createChannelIfNeeded(notificationManager);
    Notification notification = builder.build();
    //notificationManager.notify(NOTIFY_ID, notification);
    startForeground(NOTIFY_ID, notification);
}

public static void createChannelIfNeeded(NotificationManager manager) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFY_CHANNEL_ID, NOTIFY_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
        manager.createNotificationChannel(notificationChannel);
    }
}

// Find the location
protected void getPosition () {
    if (isLocationEnabled()) {
        Log.d(LOG_TAG, "Service: new FindGeoPos call");

        Handler handler = new Handler(Looper.getMainLooper());
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                fg = new FindGeoPos(getBaseContext());
            }
        };
        handler.post(myRunnable);
    } else {
        Toast.makeText(getApplicationContext(), "Service: Please turn on your location", Toast.LENGTH_LONG).show();
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        startActivity(intent);
        Log.d(LOG_TAG, "Service: Please turn on your location");
    }
}

private boolean isLocationEnabled() {
    LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}

@Subscribe//(threadMode = ThreadMode.MAIN)
public void onEvent(EventBus_Kid event){
    Log.d(LOG_TAG, "Service: EventBus is worked, position is:  " + event.location_message);
    fg = null;
    parent_sender = sharedPrefs.getString(PARENT_PHONE, "" );

    try { // ABLY PUBLISH a message
        channel.publish(KID_PHONE,  event.location_message, new CompletionListener() {
            @Override
            public void onSuccess() {
                Log.d(LOG_TAG,"Service - onSuccess - Message sent");
            }

            @Override
            public void onError(ErrorInfo reason) {
                Log.d(LOG_TAG,"Service - onError - Message not sent, error occurred: " + reason.message);
                sendSMSMessage (parent_sender, event.location_message);
            }
        });
    } catch (AblyException e) {
        Log.d(LOG_TAG,"Service - AblyException - Message not sent: " + e.toString());
        sendSMSMessage (parent_sender, event.location_message);
    }
    //OkHttp is starting
    String user = KID_PHONE;
    OkHttpRequest serverReguest = new OkHttpRequest();
    serverReguest.serverGetback(user, event.location_message);
}

protected void sendSMSMessage (String phoneNo, String message) {
    try {
        SmsManager smsManager = SmsManager.getDefault();
        smsManager.sendTextMessage(phoneNo, null, message, null, null);
        Toast.makeText(getApplicationContext(), "SMS sent.", Toast.LENGTH_LONG).show();
        Log.d(LOG_TAG, "Service: SMS sent to number: " + phoneNo + " with message: " + message);
    } catch (Exception e) {
        Toast.makeText(getApplicationContext(),"SMS faild, please try again later", Toast.LENGTH_LONG).show();
        e.printStackTrace();
        Log.d(LOG_TAG, "Service: SMS failed. SMS Exception: " + e.toString());
    }
}

public void onDestroy() {
    super.onDestroy();
    Log.d(LOG_TAG, "Service: onDestroy");
    unregisterReceiver(mainBroadcastReceiver);
    EventBus.getDefault().unregister(this);
    channel.unsubscribe();
    notificationManager.cancel(DEFAULT_NOTIFICATION_ID);
    stopSelf();
}

@Override
public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    return null;
    //throw new UnsupportedOperationException("Service: Not yet implemented");
}

}

4

1 回答 1

0

精通工程师在这里。这里的问题主要与应用程序不在前台时 android 处理服务的方式有关。使用 Ably 会有所帮助,但我们无法阻止操作系统暂停该线程:D。

设备处理短信的方式不同,系统不受用户空间控制。无论如何都会收到它们,然后您的应用程序可以处理它们。

这篇文章中,有一个关于后台线程/任务中的 websockets 的答案。它或多或少是正确的方法。有一些关于如何在颤振中在 android 上执行此操作的示例: https ://medium.com/stuart-engineering/keep-flutter-running-background-on-android-6ffc85be0234

于 2021-03-26T08:31:11.023 回答