海外购物网站大全,济南市商务局官方网站,怎样登入网站后台,做网站3个月前言
之前我们在使 RESTful 访问服务端时#xff0c;一般都是客户端请求服务端应答的方式#xff0c;这种通讯方式#xff0c;对于需要持续获取数据的情形都是采用轮询的方式#xff0c;但是这种方式对两边的性能消耗很大#xff0c;特别是服务端的压力很大。现在当我们使…前言
之前我们在使 RESTful 访问服务端时一般都是客户端请求服务端应答的方式这种通讯方式对于需要持续获取数据的情形都是采用轮询的方式但是这种方式对两边的性能消耗很大特别是服务端的压力很大。现在当我们使用WebSocket时这类问题迎刃而解了。服务端可以根据需要向客户端实时推送消息。 WebSocket的协议很简单客户端的onMessage事件可以很方便的接收消息。我们可以收到后传递给前端的Activity处理更新UI.
现代手机为了省电屏幕在很短的时候就关闭了但有时候我们不希望屏幕一灭应用也跟着睡着了手机息屏后我们仍然希望用户能通过语音给用户传递信息。就像你切换屏幕了高德能继续给你语音导航一样。这种情况单独使用Activity是无能为力的Android系统设计为只要屏幕一灭任何Activity的UI活动都会睡眠。不过息屏后后台的WebSocket客户端是能够继续接受消息的但是没办法传到前端的活动了。这时候我们需要引入Android的Service来处理。 在讲解正文之前我们先回顾一下WebSocket的基本使用。
WebSocket与回调接口
在之前的文章中我们介绍了WebSocket的基本使用。就是利用OkHttp3的WebSocket相关功能搭建自己的调用程序框架。这里为了适应Service的使用我们对WebSocket程序稍微加以改造一下。 首先我们将静态方法改造为实例方法并使用单例模式。 其次我们引入一个回调接口这个很关键。 WebSocketListenerCallback
public interface WebSocketListenerCallback {void onDataReceived(String action, String data);void onFailure(String text);
}它包含2个方法 onDataReceived 处理收到消息后怎么办 onFailure 处理通讯失败
我们的WebSocket程序设计为可以设定多个Callback, 在onMessage 收到消息后逐个执行每个Callback的onDataReceived方法。整个WebSocket程序的代码如下。使用前需要引入Okhttp3库。
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;import com.bob.app.C;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;public class WSClient {private static WSClient instance;private WebSocket socket;private final ListWebSocketListenerCallback callbacks new ArrayList();private final OkHttpClient client;private WSClient() {OkHttpClient.Builder cb new OkHttpClient.Builder();cb.readTimeout(C.SOCKET_TIMEOUT, TimeUnit.SECONDS);cb.connectTimeout(C.SOCKET_TIMEOUT, TimeUnit.SECONDS);cb.writeTimeout(C.SOCKET_TIMEOUT, TimeUnit.SECONDS);client cb.build();}public static synchronized WSClient getInstance() {if (instance null) {instance new WSClient();}return instance;}public synchronized void init() {Request request new Request.Builder().url(C.serverUrl).build();WSListener listener new WSListener();socket client.newWebSocket(request, listener);}public void addCallback(WebSocketListenerCallback callback) {if (!callbacks.contains(callback)) {callbacks.add(callback);}}public void removeCallback(WebSocketListenerCallback callback) {callbacks.remove(callback);}public synchronized void send(String action, Object data) {long txNo System.currentTimeMillis();String message action $$ txNo $$ U.toJSONString(data);if (socket ! null) {socket.send(message);}}public void disconnect(int code, String reason) {if (socket ! null) {socket.close(code, reason);socket null;}}private class WSListener extends WebSocketListener {Overridepublic void onMessage(NonNull WebSocket webSocket, NonNull String text) {for (WebSocketListenerCallback callback : callbacks) {String[] str text.split(\$\$);String action str[0];//操作指令String message str.length 2 ? str[2] : ;//信息正文callback.onDataReceived(action, message);}}Overridepublic void onFailure(NonNull WebSocket webSocket, NonNull Throwable t, Nullable Response response) {for (WebSocketListenerCallback callback : callbacks) {callback.onFailure(Error: t.getMessage());//错误信息传出去}}}
}C是一个常数类,里面有些常数比如SOCKET_TIMEOUT 5;
Service接收推送消息
关于Service的基本使用网上有很多资料。我们这里通过实际的场景应用来消化理解。
我们现在的应用场景就是收到后台消息后通过Service传递给前端应用然后语音播报。 首先自己的Service继承基类并且需要实现回调方法WebSocketListenerCallback 在初始化WebSocket的时候我们就把Callback传进去。并初始化。
整个Service的完整代码如下:
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;import com.bob.app.common.WSClient;
import com.bob.app.common.WebSocketListenerCallback;public class ActiveDataService extends Service implements WebSocketListenerCallback {Overridepublic void onCreate() {super.onCreate();WSClient wsClient WSClient.getInstance();//获取实例wsClient.addCallback(this);//传入CallbackwsClient.init();//执行初始化}public void onDataReceived(String action, String str) {if (A.ACTIVE_DATA.equals(action)) {//如果指令是推送新消息Intent intent new Intent(BC.BROADCAST_ACTIVE_DATA);//收到最新实时消息intent.putExtra(data, str);LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}}public void onFailure(String str) {Intent intent new Intent(BC.BROADCAST_SERVER_OFFLINE);//服务端访问异常LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}Overridepublic int onStartCommand(Intent intent, int flags, int startId) {startForeground(1, createNotification());return START_STICKY;}private Notification createNotification() {NotificationChannel channel new NotificationChannel(channel, Service, NotificationManager.IMPORTANCE_LOW);NotificationManager manager getSystemService(NotificationManager.class);if (manager ! null) {manager.createNotificationChannel(channel);}NotificationCompat.Builder builder new NotificationCompat.Builder(this, channel).setContentTitle(getString(R.string.app_name)).setContentText(getString(R.string.fetching_data)).setSmallIcon(android.R.drawable.ic_notification_overlay).setAutoCancel(true).setOngoing(false).setPriority(NotificationCompat.PRIORITY_DEFAULT); // Make sure the priority is LOWreturn builder.build();}NullableOverridepublic IBinder onBind(Intent intent) {return null;}Overridepublic void onDestroy() {super.onDestroy();}
}其中BC.BROADCAST_ACTIVE_DATA和BC.BROADCAST_SERVER_OFFLINE是2个常数字符串可以自己取名字。
在Android里面由于Activity和Service的生命周期并不相同Service息屏后还能活动因此Service并不能直接引用Activity也不能直接与Activity交互只能通过广播间接交互。意思就是Service发送广播Activity可以订阅后处理。上面的代码展示了怎样发送广播。
createNotification是一个常规方法创建一个通知信息栏。这个会让用户知道一个后台服务在干嘛。有的手机会显示比如华为等有的手机也默认不显示比如Oppo等
Activity接收Service广播信息
Service发送的广播Activity可以通过订阅的方式来使用。
具体的订阅方法如下 private final BroadcastReceiver receiver1 new BroadcastReceiver() {Overridepublic void onReceive(Context context, Intent intent) {String data intent.getStringExtra(data);finishGetActiveData(data);//接收到最新数据传递到处理方法}};private final BroadcastReceiver receiver2 new BroadcastReceiver() {Overridepublic void onReceive(Context context, Intent intent) {showLogin();//接收到网络异常退回到登录界面}};先声明BroadcastReceiver, receiver的目的就是声明收到数据后怎么办。在onReceive方法里接收数据然后传递到实现方法里面。这里我们声明了2个receiver一个是收到正常的最新信息后怎么办。另一个是收到网络错误信息后怎么办。
然后在onCreate方法里注册receiver
Intent serviceIntent new Intent(this, ActiveDataService.class);
ContextCompat.startForegroundService(this, serviceIntent);
LocalBroadcastManager.getInstance(this).registerReceiver(receiver1, new IntentFilter(BC.BROADCAST_ACTIVE_DATA));
LocalBroadcastManager.getInstance(this).registerReceiver(receiver2, new IntentFilter(BC.BROADCAST_SERVER_OFFLINE));注意其中的 IntentFilter的用法一般一个receiver只过滤接收一种消息。
这样我们就完成把消息传送给Activity这个数据链路了。
然后我们可以在finishGetActiveData方法里面干该干的事情了比如调用TTS语音播报啥的。
看到这里有的小伙伴可能会问这个Callback我能不能在Activity里将WebSocket初始化然后传入Callback呢答案是可以的可以将Activity实现WebSocketListenerCallback后传入WebSocket,也是一样的效果还更简单不用广播。不过前面我们讲过这种直接使用Activity初始化WebSocket的程序只能在亮屏时功能正常息屏了程序就跟着睡眠了。
另外需要强调的一点时要实现息屏后服务正常需要手机在设置里关闭省电功能并且允许应用后台活动。否则写了也白搭。只有用户才有最终决定权。
总结
要想息屏后部分手机功能正常接收后台推送消息并传递给Activity处理需要做如下处理
- WebSocket引入回调接口并在onMesssge中调用。
- 创建一个Service实现回调接口在回调方法中发送广播
- Activity中声明接收广播的receiver并实现处理receiver收到的的数据。