为你设计这个设备固件升级界面,包含圆形进度条和倒计时功能:
package com.tplink.deco.activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.tplink.apps.architecture.BaseMvvmActivity;
import com.tplink.deco.databinding.ActivityDeviceListBinding;
import com.tplink.deco.model.DeviceListResponse;
import com.tplink.deco.viewmodel.DeviceListViewModel;
import java.util.ArrayList;
import java.util.List;
public class DeviceListActivity extends BaseMvvmActivity<ActivityDeviceListBinding> {
private DeviceListViewModel deviceListViewModel;
private DeviceListAdapter deviceListAdapter;
private String userToken;
@Nullable
@Override
protected ActivityDeviceListBinding bindContentView(@Nullable Bundle bundle) {
ActivityDeviceListBinding mBinding = ActivityDeviceListBinding.inflate(getLayoutInflater());
return mBinding;
}
@Override
protected void subscribeViewModel(@Nullable Bundle bundle) {
// 获取从登录页面传递过来的token
userToken = getIntent().getStringExtra("user_token");
// 初始化 ViewModel
deviceListViewModel = new ViewModelProvider(this).get(DeviceListViewModel.class);
setupViews();
observeViewModel();
// 自动加载设备列表
if (userToken != null) {
deviceListViewModel.refreshDeviceList(userToken);
}
}
/**
* 设置UI组件
*/
private void setupViews() {
// 设置RecyclerView
viewBinding.recyclerViewDevices.setLayoutManager(new LinearLayoutManager(this));
deviceListAdapter = new DeviceListAdapter();
viewBinding.recyclerViewDevices.setAdapter(deviceListAdapter);
// 设置刷新按钮(可选)
viewBinding.btnRefresh.setOnClickListener(v -> {
if (userToken != null) {
deviceListViewModel.refreshDeviceList(userToken);
}
});
// 设置返回按钮
viewBinding.toolbar.setOnClickListener(v -> {
finish();
});
}
/**
* 观察 ViewModel 中的 LiveData
*/
private void observeViewModel() {
// 观察设备列表
deviceListViewModel.deviceList.observe(this, deviceList -> {
if (deviceList != null) {
deviceListAdapter.updateDeviceList(deviceList);
// 更新空状态显示
if (deviceList.isEmpty()) {
viewBinding.textViewEmptyState.setVisibility(View.VISIBLE);
viewBinding.recyclerViewDevices.setVisibility(View.GONE);
} else {
viewBinding.textViewEmptyState.setVisibility(View.GONE);
viewBinding.recyclerViewDevices.setVisibility(View.VISIBLE);
}
}
});
// 观察设备总数
deviceListViewModel.totalDeviceCount.observe(this, totalCount -> {
if (totalCount != null) {
viewBinding.textViewDeviceCount.setText("共 " + totalCount + " 个设备");
}
});
}
/**
* 设备列表适配器
*/
private static class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.DeviceViewHolder> {
private List<DeviceListResponse.Device> deviceList = new ArrayList<>();
public void updateDeviceList(List<DeviceListResponse.Device> newDeviceList) {
this.deviceList.clear();
if (newDeviceList != null) {
this.deviceList.addAll(newDeviceList);
}
notifyDataSetChanged();
}
@NonNull
@Override
public DeviceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(android.R.layout.simple_list_item_2, parent, false);
return new DeviceViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull DeviceViewHolder holder, int position) {
DeviceListResponse.Device device = deviceList.get(position);
holder.bind(device);
}
@Override
public int getItemCount() {
return deviceList.size();
}
/**
* 设备项ViewHolder
*/
static class DeviceViewHolder extends RecyclerView.ViewHolder {
private TextView textViewDeviceName;
private TextView textViewDeviceInfo;
public DeviceViewHolder(@NonNull View itemView) {
super(itemView);
textViewDeviceName = itemView.findViewById(android.R.id.text1);
textViewDeviceInfo = itemView.findViewById(android.R.id.text2);
}
public void bind(DeviceListResponse.Device device) {
// 显示设备名称(优先显示解码后的alias,如果为空则显示deviceName)
String decodedAlias = device.getDecodedAlias();
String displayName = decodedAlias != null && !decodedAlias.isEmpty()
? decodedAlias : device.getDeviceName();
textViewDeviceName.setText(displayName);
// 显示设备信息(型号 + MAC地址 + 状态)
String deviceInfo = String.format("%s | MAC: %s | 状态: %s",
device.getDeviceModel(),
device.getDeviceMac(),
device.getStatus() == 1 ? "在线" : "离线");
textViewDeviceInfo.setText(deviceInfo);
// 设置点击事件(可选)
itemView.setOnClickListener(v -> {
// 这里可以添加设备详情页面跳转
// Intent intent = new Intent(v.getContext(), DeviceDetailActivity.class);
// intent.putExtra("device_id", device.getDeviceId());
// v.getContext().startActivity(intent);
});
}
}
}
}
package com.tplink.deco.viewmodel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.tplink.deco.client.ApiClient;
import com.tplink.deco.dao.DeviceListApiService;
import com.tplink.deco.model.DeviceListRequest;
import com.tplink.deco.model.DeviceListResponse;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class DeviceListViewModel extends ViewModel {
private DeviceListApiService deviceListApiService;
private Call<DeviceListResponse> deviceListCall;
// LiveData for device list
private MutableLiveData<List<DeviceListResponse.Device>> _deviceList = new MutableLiveData<>(new ArrayList<>());
private MutableLiveData<Integer> _totalDeviceCount = new MutableLiveData<>(0);
// Public LiveData (read-only)
public LiveData<List<DeviceListResponse.Device>> deviceList = _deviceList;
public LiveData<Integer> totalDeviceCount = _totalDeviceCount;
public DeviceListViewModel() {
deviceListApiService = ApiClient.getDeviceListService();
}
/**
* 获取设备列表
* @param token 登录API返回的token
* @param index 分页索引,从0开始
* @param limit 每页数量,默认20
*/
public void getDeviceList(String token, int index, int limit) {
// 创建请求参数
DeviceListRequest request = new DeviceListRequest();
// 设置分页参数
request.getParams().setIndex(index);
request.getParams().setLimit(limit);
// 发起网络请求
deviceListCall = deviceListApiService.getDeviceList(
"TP-Link_Tapo_Android",
"2.2.15",
"wifi",
"40-3F-8C-3B-B7-B9",
"Android%208.1.0",
"zh_CN_%23Hans",
token,
request
);
deviceListCall.enqueue(new Callback<DeviceListResponse>() {
@Override
public void onResponse(Call<DeviceListResponse> call, Response<DeviceListResponse> response) {
handleDeviceListResponse(response);
}
@Override
public void onFailure(Call<DeviceListResponse> call, Throwable t) {
// 可以在这里处理网络失败,但用户要求不要error message
// 保持当前设备列表不变
}
});
}
/**
* 处理设备列表响应
*/
private void handleDeviceListResponse(Response<DeviceListResponse> response) {
if (response.isSuccessful() && response.body() != null) {
DeviceListResponse deviceResponse = response.body();
if (deviceResponse.getError_code() == 0 && deviceResponse.getResult() != null) {
DeviceListResponse.DeviceListResult result = deviceResponse.getResult();
// 更新设备列表
List<DeviceListResponse.Device> devices = result.getDeviceList();
if (devices != null) {
_deviceList.setValue(devices);
_totalDeviceCount.setValue(result.getTotalNum());
}
}
}
}
/**
* 刷新设备列表(重新从第一页开始)
*/
public void refreshDeviceList(String token) {
getDeviceList(token, 0, 20);
}
/**
* 加载更多设备(分页加载)
*/
public void loadMoreDevices(String token, int currentSize) {
int nextIndex = currentSize;
getDeviceList(token, nextIndex, 20);
}
/**
* 追加设备到现有列表(用于分页加载)
*/
private void appendDevices(List<DeviceListResponse.Device> newDevices) {
List<DeviceListResponse.Device> currentList = _deviceList.getValue();
if (currentList != null && newDevices != null) {
List<DeviceListResponse.Device> updatedList = new ArrayList<>(currentList);
updatedList.addAll(newDevices);
_deviceList.setValue(updatedList);
}
}
@Override
protected void onCleared() {
super.onCleared();
// 取消未完成的网络请求
if (deviceListCall != null && !deviceListCall.isCanceled()) {
deviceListCall.cancel();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 工具栏 -->
<LinearLayout
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?attr/colorPrimary"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="设备列表"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold" />
<Button
android:id="@+id/btn_refresh"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="?attr/selectableItemBackground"
android:text="刷新"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<!-- 设备数量显示 -->
<TextView
android:id="@+id/text_view_device_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="共 0 个设备"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary" />
<!-- 设备列表 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view_devices"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="8dp" />
<!-- 空状态提示 -->
<TextView
android:id="@+id/text_view_empty_state"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="暂无设备\n请确保您的设备已正确配置"
android:textColor="?android:attr/textColorSecondary"
android:textSize="16sp"
android:visibility="gone" />
</LinearLayout>
package com.tplink.deco.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CircularProgressView extends View {
private Paint backgroundPaint;
private Paint progressPaint;
private RectF oval;
private float progress = 0f; // 0-100
private int strokeWidth = 20;
// 颜色定义
private static final int BACKGROUND_COLOR = 0xFFE8E8E8; // 灰色背景
private static final int PROGRESS_COLOR = 0xFF00BCD4; // 蓝色进度
public CircularProgressView(Context context) {
super(context);
init();
}
public CircularProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// 背景圆环画笔
backgroundPaint = new Paint();
backgroundPaint.setAntiAlias(true);
backgroundPaint.setStyle(Paint.Style.STROKE);
backgroundPaint.setStrokeWidth(strokeWidth);
backgroundPaint.setColor(BACKGROUND_COLOR);
backgroundPaint.setStrokeCap(Paint.Cap.ROUND);
// 进度圆环画笔
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeWidth(strokeWidth);
progressPaint.setColor(PROGRESS_COLOR);
progressPaint.setStrokeCap(Paint.Cap.ROUND);
oval = new RectF();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int radius = Math.min(centerX, centerY) - strokeWidth / 2;
// 设置绘制区域
oval.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
// 绘制背景圆环
canvas.drawCircle(centerX, centerY, radius, backgroundPaint);
// 绘制进度圆环
float sweepAngle = (progress / 100f) * 360f;
canvas.drawArc(oval, -90, sweepAngle, false, progressPaint);
}
/**
* 设置进度 0-100
*/
public void setProgress(float progress) {
this.progress = Math.max(0, Math.min(100, progress));
invalidate();
}
public float getProgress() {
return progress;
}
}
// 2. 固件升级Activity
package com.tplink.deco.activity;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.tplink.deco.R;
import com.tplink.deco.widget.CircularProgressView;
public class FirmwareUpgradeActivity extends AppCompatActivity {
private CircularProgressView progressView;
private TextView remainingTimeText;
private TextView statusText;
private CountDownTimer countDownTimer;
private ValueAnimator progressAnimator;
// 默认升级时间(秒)
private static final int UPGRADE_DURATION = 150; // 2分30秒
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_firmware_upgrade);
initViews();
setupToolbar();
startUpgrade();
}
private void initViews() {
progressView = findViewById(R.id.progressView);
remainingTimeText = findViewById(R.id.remainingTimeText);
statusText = findViewById(R.id.statusText);
}
private void setupToolbar() {
// 设置返回按钮(可选)
findViewById(R.id.backButton).setOnClickListener(v -> {
// 升级过程中不允许返回,可以显示警告
Toast.makeText(this, "固件升级进行中,请勿中断", Toast.LENGTH_SHORT).show();
});
}
private void startUpgrade() {
statusText.setText("Installing new firmware...");
// 启动倒计时
startCountdown();
// 启动进度动画
startProgressAnimation();
}
private void startCountdown() {
countDownTimer = new CountDownTimer(UPGRADE_DURATION * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
long seconds = millisUntilFinished / 1000;
long minutes = seconds / 60;
seconds = seconds % 60;
String timeText = String.format("%02d:%02d", minutes, seconds);
remainingTimeText.setText(timeText);
}
@Override
public void onFinish() {
remainingTimeText.setText("00:00");
onUpgradeComplete();
}
};
countDownTimer.start();
}
private void startProgressAnimation() {
progressAnimator = ValueAnimator.ofFloat(0f, 100f);
progressAnimator.setDuration(UPGRADE_DURATION * 1000);
progressAnimator.addUpdateListener(animation -> {
float progress = (Float) animation.getAnimatedValue();
progressView.setProgress(progress);
});
progressAnimator.start();
}
private void onUpgradeComplete() {
statusText.setText("Firmware upgrade completed!");
// 延迟2秒后关闭页面
remainingTimeText.postDelayed(() -> {
Toast.makeText(this, "升级完成", Toast.LENGTH_SHORT).show();
finish();
}, 2000);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 清理资源
if (countDownTimer != null) {
countDownTimer.cancel();
}
if (progressAnimator != null) {
progressAnimator.cancel();
}
}
@Override
public void onBackPressed() {
// 升级过程中禁用返回键
Toast.makeText(this, "固件升级进行中,请勿中断", Toast.LENGTH_SHORT).show();
}
}
// 3. 布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/white">
<!-- 顶部工具栏 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<ImageView
android:id="@+id/backButton"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerVertical="true"
android:src="@drawable/ic_menu"
android:background="?attr/selectableItemBackgroundBorderless" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="TP WIFI"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@android:color/black" />
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_add"
android:background="?attr/selectableItemBackgroundBorderless" />
</RelativeLayout>
<!-- 分割线 -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#EEEEEE" />
<!-- 内容区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:padding="24dp">
<!-- 说明文字 -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="The new firmware will be downloaded by your Deco system, not this app. No mobile data or storage on this device is required."
android:textSize="16sp"
android:textColor="#666666"
android:lineSpacing="4dp" />
<!-- 占位空间 -->
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<!-- 圆形进度条区域 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<!-- 圆形进度条 -->
<com.tplink.deco.widget.CircularProgressView
android:id="@+id/progressView"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true" />
<!-- 中间文字 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Remaining Time"
android:textSize="14sp"
android:textColor="#999999" />
<TextView
android:id="@+id/remainingTimeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:02:32"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="@android:color/black"
android:layout_marginTop="4dp" />
</LinearLayout>
</RelativeLayout>
<!-- 占位空间 -->
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<!-- 状态文字 -->
<TextView
android:id="@+id/statusText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Installing new firmware..."
android:textSize="16sp"
android:textColor="#666666" />
<!-- 底部占位 -->
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.5" />
</LinearLayout>
</LinearLayout>
// 4. 启动升级界面的方法 // 在你的设备列表或设备详情页面中添加:
public void startFirmwareUpgrade() {
Intent intent = new Intent(this, FirmwareUpgradeActivity.class);
startActivity(intent);
}
// 5. 需要的图标资源 // 在 app/src/main/res/drawable/ 目录下创建:
// ic_menu.xml (汉堡菜单图标)
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M3,6h18v2H3V6zM3,11h18v2H3V11zM3,16h18v2H3V16z" />
</vector>
// ic_add.xml (加号图标)
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>
// 6. 使用说明和特性 /* ✨ 主要特性:
- 圆形进度条从0%到100%平滑填充
- 倒计时从设定时间倒数到00:00
- 进度条和倒计时同步进行
- 升级完成后自动关闭页面
- 升级过程中禁用返回键
🎨 视觉效果:
- 蓝色进度条(#00BCD4)逐渐填充灰色背景圆环
- 圆角笔触,看起来更现代
- 中心显示剩余时间,格式MM:SS
- 底部显示当前状态文字
🔧 自定义选项:
- 修改UPGRADE_DURATION调整升级时长
- 修改PROGRESS_COLOR和BACKGROUND_COLOR调整颜色
- 修改strokeWidth调整圆环粗细
📱 启动方式: 在设备列表点击升级按钮时调用startFirmwareUpgrade()方法 */# 🎯 设计完成!
我为你设计了一个完整的固件升级界面,完美还原了截图中的效果:
✨ 主要特性
🔄 圆形进度条
- 自定义View - 平滑的圆环进度动画
- 颜色渐变 - 蓝色进度逐渐填充灰色背景
- 同步更新 - 进度和倒计时完美同步
⏱️ 倒计时功能
- 实时更新 - 每秒更新显示
MM:SS格式 - 默认2分30秒 - 可以通过
UPGRADE_DURATION调整 - 倒计时结束 - 自动显示完成状态
🎨 界面设计
- 完全还原截图 - 包括顶部工具栏、说明文字、进度区域
- 现代化UI - 圆角笔触、合适的间距和颜色
- 状态提示 - 底部动态显示当前状态
🛡️ 用户体验
- 防中断 - 升级过程中禁用返回键
- 自动完成 - 升级结束后自动关闭页面
- 友好提示 - 用户尝试返回时显示警告
🚀 使用方法
// 在设备列表或详情页面启动升级
public void onUpgradeButtonClick() {
Intent intent = new Intent(this, FirmwareUpgradeActivity.class);
startActivity(intent);
}
🎛️ 自定义选项
- 升级时长: 修改
UPGRADE_DURATION常量 - 进度颜色: 修改
PROGRESS_COLOR和BACKGROUND_COLOR - 圆环粗细: 调整
strokeWidth参数
package com.tplink.deco.model;
import java.util.Arrays;
import java.util.List;
public class DeviceListRequest {
private String method;
private DeviceListParams params;
public DeviceListRequest() {
this.method = "getDeviceListByPage";
this.params = new DeviceListParams();
}
public static class DeviceListParams {
private List<String> deviceTypeList;
private int index;
private int limit;
public DeviceListParams() {
this.deviceTypeList = Arrays.asList("SMART.TAPOPLUG");
this.index = 0;
this.limit = 20;
}
// getters and setters
public List<String> getDeviceTypeList() { return deviceTypeList; }
public void setDeviceTypeList(List<String> deviceTypeList) { this.deviceTypeList = deviceTypeList; }
public int getIndex() { return index; }
public void setIndex(int index) { this.index = index; }
public int getLimit() { return limit; }
public void setLimit(int limit) { this.limit = limit; }
}
// getters and setters
public String getMethod() { return method; }
public void setMethod(String method) { this.method = method; }
public DeviceListParams getParams() { return params; }
public void setParams(DeviceListParams params) { this.params = params; }}
// 2. 设备响应实体
package com.tplink.deco.model;
import java.util.List;
public class DeviceListResponse {
private int error_code;
private DeviceListResult result;
public static class DeviceListResult {
private int totalNum;
private List<Device> deviceList;
private int currentIndex;
// getters and setters
public int getTotalNum() { return totalNum; }
public void setTotalNum(int totalNum) { this.totalNum = totalNum; }
public List<Device> getDeviceList() { return deviceList; }
public void setDeviceList(List<Device> deviceList) { this.deviceList = deviceList; }
public int getCurrentIndex() { return currentIndex; }
public void setCurrentIndex(int currentIndex) { this.currentIndex = currentIndex; }
}
public static class Device {
private String deviceType;
private int role;
private String deviceId;
private String deviceName;
private String alias;
private String deviceMac;
private String deviceModel;
private int status;
// 解码别名
public String getDecodedAlias() {
try {
if (alias != null) {
return new String(android.util.Base64.decode(alias, android.util.Base64.DEFAULT));
}
} catch (Exception e) {}
return alias;
}
// getters and setters
public String getDeviceType() { return deviceType; }
public void setDeviceType(String deviceType) { this.deviceType = deviceType; }
public int getRole() { return role; }
public void setRole(int role) { this.role = role; }
public String getDeviceId() { return deviceId; }
public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
public String getDeviceName() { return deviceName; }
public void setDeviceName(String deviceName) { this.deviceName = deviceName; }
public String getAlias() { return alias; }
public void setAlias(String alias) { this.alias = alias; }
public String getDeviceMac() { return deviceMac; }
public void setDeviceMac(String deviceMac) { this.deviceMac = deviceMac; }
public String getDeviceModel() { return deviceModel; }
public void setDeviceModel(String deviceModel) { this.deviceModel = deviceModel; }
public int getStatus() { return status; }
public void setStatus(int status) { this.status = status; }
}
// getters and setters
public int getError_code() { return error_code; }
public void setError_code(int error_code) { this.error_code = error_code; }
public DeviceListResult getResult() { return result; }
public void setResult(DeviceListResult result) { this.result = result; }
}
// 3. 设备API接口
package com.tplink.deco.dao;
import com.tplink.deco.model.DeviceListRequest;
import com.tplink.deco.model.DeviceListResponse;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface DeviceApiService {
@POST("/")
Call<DeviceListResponse> getDeviceList(
@Query("appName") String appName,
@Query("appVer") String appVer,
@Query("netType") String netType,
@Query("termID") String termID,
@Query("ospf") String ospf,
@Query("locale") String locale,
@Query("token") String token,
@Body DeviceListRequest request
);
}
// 4. 在ApiClient中新增方法(不动原有代码) // 在你的ApiClient类中添加这个方法:
public static DeviceApiService getDeviceService() {
// 设备API不需要SignatureInterceptor,单独创建
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.sslSocketFactory(createSSLSocketFactory(), createTrustManager())
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(DeviceApiService.class);
}
// 5. HomePageActivity关键代码
package com.tplink.deco.activity;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.tplink.deco.client.ApiClient;
import com.tplink.deco.dao.DeviceApiService;
import com.tplink.deco.model.DeviceListRequest;
import com.tplink.deco.model.DeviceListResponse;
import com.tplink.deco.adapter.DeviceAdapter;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import java.util.ArrayList;
public class HomePageActivity extends AppCompatActivity {
private DeviceApiService deviceApiService;
private RecyclerView recyclerView;
private DeviceAdapter adapter;
private String userToken;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_homepage);
// 获取登录传递的token
userToken = getIntent().getStringExtra("user_token");
// 初始化
deviceApiService = ApiClient.getDeviceService();
recyclerView = findViewById(R.id.recyclerView);
adapter = new DeviceAdapter(new ArrayList<>());
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
// 按钮点击事件
findViewById(R.id.btn_network).setOnClickListener(v -> loadDevices());
}
private void loadDevices() {
DeviceListRequest request = new DeviceListRequest();
Call<DeviceListResponse> call = deviceApiService.getDeviceList(
"TP-Link_Tapo_Android",
"2.2.15",
"wifi",
"40-3F-8C-3B-B7-B9", // 固定的termID
"Android 8.1.0",
"zh_CN_#Hans",
userToken,
request
);
call.enqueue(new Callback<DeviceListResponse>() {
@Override
public void onResponse(Call<DeviceListResponse> call, Response<DeviceListResponse> response) {
if (response.isSuccessful() && response.body() != null) {
DeviceListResponse deviceResponse = response.body();
if (deviceResponse.getError_code() == 0 && deviceResponse.getResult() != null) {
adapter.updateDevices(deviceResponse.getResult().getDeviceList());
} else {
Toast.makeText(HomePageActivity.this, "获取设备失败", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onFailure(Call<DeviceListResponse> call, Throwable t) {
Toast.makeText(HomePageActivity.this, "网络错误", Toast.LENGTH_SHORT).show();
}
});
}
}
// 6. 简单的设备适配器
package com.tplink.deco.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.tplink.deco.R;
import com.tplink.deco.model.DeviceListResponse;
import java.util.List;
public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder> {
private List<DeviceListResponse.Device> devices;
public DeviceAdapter(List<DeviceListResponse.Device> devices) {
this.devices = devices;
}
public void updateDevices(List<DeviceListResponse.Device> newDevices) {
this.devices = newDevices;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_device, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
DeviceListResponse.Device device = devices.get(position);
holder.deviceName.setText(device.getDeviceName());
holder.deviceAlias.setText(device.getDecodedAlias());
}
@Override
public int getItemCount() {
return devices.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView deviceName, deviceAlias;
ViewHolder(View itemView) {
super(itemView);
deviceName = itemView.findViewById(R.id.deviceName);
deviceAlias = itemView.findViewById(R.id.deviceAlias);
}
}
}
// 7. 布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/btn_network"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="获取设备" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp" />
</LinearLayout>
// item_device.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:id="@+id/deviceName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/deviceAlias"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_marginTop="4dp" />
</LinearLayout>