需求:Android做个轮播图功能,当后台上传了最新的轮播图后,Android立刻更新最新的图像信息
后台用的springboot,和Android通信用的websocket,但之前做类似的功能,比如MQ、MQTT、firebase,基本都是人家后台搭好了我直接调用就行,这次需要自己搭,做个最简单的案例
SpringBoot
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@Component
public class MyWebSocketHandler extends TextWebSocketHandler {
private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
System.out.println("新连接: " + session.getId());
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session);
System.out.println("连接关闭: " + session.getId() + ", 原因: " + status.getReason());
}
// 向所有客户端广播消息
public void broadcast(String message) {
TextMessage textMessage = new TextMessage(message);
for (WebSocketSession session : sessions) {
try {
if (session.isOpen()) {
session.sendMessage(textMessage);
}
} catch (Exception e) {
System.err.println("发送消息失败: " + e.getMessage());
}
}
}
}
import com.ruoyi.web.webSocket.MyWebSocketHandler;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@EnableScheduling
@RequestMapping("/system/message/websocket")
public class MessageController {
private final MyWebSocketHandler webSocketHandler;
public MessageController(MyWebSocketHandler webSocketHandler) {
this.webSocketHandler = webSocketHandler;
}
// 定时发送消息(每25秒)
/*@Scheduled(fixedRate = 25000)
public void sendPeriodicMessage() {
String message = "服务器消息 #" + (++messageCount) + " | " + System.currentTimeMillis();
webSocketHandler.broadcast(message);
System.out.println("已发送: " + message);
}*/
// 接收客户端消息
@MessageMapping("/send")
public void receiveMessage(String message) {
System.out.println("收到客户端消息: " + message);
}
@GetMapping("/sendMessageToAndroid")
public void sendMessageToAndroid(String message) {
System.out.println("发送主题消息给Android: " + message);
webSocketHandler.broadcast(message);
}
}
轮播图上传后,调用sendMessageToAndroid方法发消息给Android,这里没做主题消息处理,只有最简单的纯文本内容
![]()
因为用了security框架,项目中集成了Spring Security,需要在安全配置中(SecurityConfig)给WebSocket放行(通常是`/ws`)
Android(只包含接收部分)
package com.simulateclick.screen;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import com.simulateclick.utils.ApiCaller;
import com.simulateclick.utils.RouterUrlManager;
import com.simulateclick.utils.banner.CarouselAdapter;
import com.simulateclick.utils.banner.SimpleWebSocketClient;
import org.json.JSONObject;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.stream.Collectors;
public class MainActivity extends AppCompatActivity{
// 轮播图控件
private ViewPager2 viewPager;
private LinearLayout indicatorContainer;
private CarouselAdapter adapter;
// 轮播图集合
private List<String> carouselList = new ArrayList<>();
private Timer timer;
private int currentPosition = 0;
private SimpleWebSocketClient webSocketClient;
/**
* 快餐店轮播图功能
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.restaurant_banner);
// 初始化WebSocket
connectWebSocket();
// 初始化控件
viewPager = findViewById(R.id.viewPager);
indicatorContainer = findViewById(R.id.indicatorContainer);
// 初始化轮播图适配器
adapter = new CarouselAdapter(carouselList);
viewPager.setAdapter(adapter);
// 设置页面切换监听
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
currentPosition = position;
updateIndicators(position);
}
});
// 获取轮播图数据
loadCarouselData();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (timer != null) {
timer.cancel();
}
if (webSocketClient != null) {
webSocketClient.close();
}
}
private void loadCarouselData() {
// 调用 GET 接口
new ApiCaller()
.setApiPath("/system/shop/weChat/list")
.setRequestMethod("GET")
.addParam("deptId", 207)
.setOnApiResponseListener(new ApiCaller.OnApiResponseListener() {
@Override
public void onSuccess(String response) {
// 处理成功响应
System.out.println("response===>"+response);
runOnUiThread(() -> {
try {
JSONObject jsonObject = new JSONObject(response);
String carousel = jsonObject.getString("carousel");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
List<String> carouselList = Arrays.stream(carousel.split(","))
.map(String::trim)
.filter(item -> !item.isEmpty())
.map(item -> RouterUrlManager.base_url + item)
.collect(Collectors.toList());
carouselList.forEach(item->{
System.out.println("轮播图:"+item);
});
// 更新轮播图数据
updateCarousel(carouselList);
}else {
System.out.println("安卓版本过低");
}
}catch (Exception e){
e.printStackTrace();
}
});
}
@Override
public void onError(String message) {
// 处理错误
System.out.println("onError===>"+message);
// 在子线程中调用Toast,需切回主线程
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "轮播数据获取异常:" + message, Toast.LENGTH_SHORT).show();
});
}
})
.execute();
}
private void updateCarousel(List<String> imageUrls) {
carouselList.clear();
carouselList.addAll(imageUrls);
adapter.notifyDataSetChanged();
createIndicators();
startAutoScroll();
}
private void createIndicators() {
indicatorContainer.removeAllViews();
for (int i = 0; i < carouselList.size(); i++) {
ImageView indicator = new ImageView(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
12, 12);
params.setMargins(4, 0, 4, 0);
indicator.setLayoutParams(params);
indicator.setImageResource(i == 0 ?
R.drawable.indicator_active : R.drawable.indicator_inactive);
indicatorContainer.addView(indicator);
}
}
private void updateIndicators(int position) {
for (int i = 0; i < indicatorContainer.getChildCount(); i++) {
ImageView indicator = (ImageView) indicatorContainer.getChildAt(i);
indicator.setImageResource(i == position ?
R.drawable.indicator_active : R.drawable.indicator_inactive);
}
}
private void startAutoScroll() {
if (timer != null) {
timer.cancel();
}
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(() -> {
if (carouselList.size() > 1) {
currentPosition = (currentPosition + 1) % carouselList.size();
viewPager.setCurrentItem(currentPosition, true);
}
});
}
}, 3000, 3000); // 3秒切换一次
}
private void connectWebSocket() {
try {
// IP 地址
URI uri = new URI(RouterUrlManager.websocket_base_url);
webSocketClient = new SimpleWebSocketClient(uri, new SimpleWebSocketClient.WebSocketListener() {
@Override
public void onMessageReceived(String message) {
Log.d("MainActivity", "收到消息: " + message);
runOnUiThread(() -> {
// 重新加载UI界面
recreate();
});
}
@Override
public void onConnectionOpened() {
Log.d("MainActivity", "WebSocket 连接已打开");
}
@Override
public void onConnectionClosed(int code, String reason) {
Log.d("MainActivity", "连接关闭: " + reason);
}
@Override
public void onConnectionFailed(Exception ex) {
Log.e("MainActivity", "连接失败", ex);
}
});
webSocketClient.connect();
} catch (URISyntaxException e) {
Log.e("MainActivity", "URI 语法错误", e);
}
}
}
import android.util.Log;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
public class SimpleWebSocketClient extends WebSocketClient {
private final WebSocketListener listener;
public interface WebSocketListener {
void onMessageReceived(String message);
void onConnectionOpened();
void onConnectionClosed(int code, String reason);
void onConnectionFailed(Exception ex);
}
public SimpleWebSocketClient(URI serverUri, WebSocketListener listener) {
super(serverUri);
this.listener = listener;
}
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.d("WebSocket", "连接已打开");
if (listener != null) {
listener.onConnectionOpened();
}
}
@Override
public void onMessage(String message) {
Log.d("WebSocket", "收到消息: " + message);
if (listener != null) {
listener.onMessageReceived(message);
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.d("WebSocket", "连接关闭: " + reason);
if (listener != null) {
listener.onConnectionClosed(code, reason);
}
}
@Override
public void onError(Exception ex) {
Log.e("WebSocket", "错误: ", ex);
if (listener != null) {
listener.onConnectionFailed(ex);
}
}
}
本地运行测试,IP地址通过ipconfig命令获取 IPv4
String websocket_base_url = "ws://192.168.xx.xx:8083/ws";
1万+

被折叠的 条评论
为什么被折叠?



