☰
安卓聊天机器人课设全解析:从UI布局到OkHttp网络请求避坑
2026/10/15 4:21:09 网站建设 项目流程

简介:这是一份基于Android平台的智能聊天机器人课程设计报告,面向移动应用开发课程学生,可用于课设参考、报告撰写或系统复习Android核心知识点。报告完整包含实验目的、实验内容、程序设计与说明,覆盖Android基础知识、UI界面设计、数据存储、四大组件、网络编程与高级编程技巧,重点讲解图灵机器人API Key申请、聊天界面布局创建、ChatBean消息模型、ChatAdapter数据适配器、OkHttp网络请求及JSON解析等关键环节,并逐一分析activity_main、chatting_left_item、chatting_right_item布局文件的设计思路,以及MainActivity中initView()、showData()、sendData()、getDataFromServer()、updateView()等方法的职能,配有界面运行截图和类说明,内容翔实。资源为单个doc文档,大小约1.46MB,结构清晰,可直接作为课程设计报告模板。全网已有2705人学习浏览,配合作者博客《Android Studio实现聊天机器人》可获取配套源码,帮助读者从界面到交互完整复现应用。

1. 安卓聊天机器人课设资源:先弄清楚你拿到的是报告还是源码包

拿到这份《Android实现聊天机器人》课程设计报告时,我第一反应是去核对目标:这到底是一份能复现的安卓app课设资源,还是只适合交作业的文档模板。拆完整个包之后可以确认,它是移动应用开发课程设计里非常典型的“报告+源码”组合,覆盖了UI布局、消息模型、ListView适配器、OkHttp网络请求、JSON解析、返回键处理这一整条Android开发闭环。对正在做安卓app课程设计的学生,或者想第一次接触“调用第三方开放API做聊天机器人”的入门开发者来说,这份资源的完整度比大部分零散博客教程高一个档次。但实测也发现,直接照着报告步骤做会踩到不少工程配置层面的坑,这些坑我会在后面的避坑章节逐个拆开讲。

2. 从布局到数据模型:拆开聊天界面的三层结构

2.1 聊天界面布局:activity_main 的嵌套写法与尺寸参数

报告里的聊天界面用的是纯XML手写布局,没有引入任何第三方UI库。整个布局文件的层级关系是:最外层一个垂直方向LinearLayout,里面先放一个标题TextView,再放一个占满剩余高度的RelativeLayout,这个RelativeLayout内部同时放着消息列表ListView和输入区容器。输入区又是一个小RelativeLayout,左侧EditText,右侧Button“发送”。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="机器人聊天室" android:textSize="18sp" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <ListView android:id="@+id/lv_chat" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/input_bar" android:divider="@null" android:stackFromBottom="false" /> <RelativeLayout android:id="@+id/input_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true"> <EditText android:id="@+id/et_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/btn_send" android:hint="请输入内容" /> <Button android:id="@+id/btn_send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="发送" /> </RelativeLayout> </RelativeLayout> </LinearLayout>

代码逻辑说明:ListView通过android:layout_above="@id/input_bar"把底部输入条区域预留出来,避免消息列表最后一条被输入框遮挡,这是做聊天界面时最容易忽略的一行配置。标题TextView用gravity="center"实现水平居中,外层LinearLayout用layout_weight="1"让RelativeLayout占据除标题外的全部可用高度。

参数说明集中在两个地方:ListView的layout_above绑定的是输入条RelativeLayout的id,而不是直接写alignParentBottom="true",两者的区别在于前者给消息列表留出了空间,后者会让ListView延伸到屏幕最底部,后插入的消息会被输入框盖住;EditText的layout_toLeftOf="@+id/btn_send"意味着它的右边界是发送按钮的左边界,这个约束在/布局里比用LinearLayout的weight更直观。原报告里没写android:divider="@null",实际跑起来列表项之间会有默认分隔线,气泡界面看起来会多一条横线,建议加上。

聊天气泡的左右布局用的是两个独立文件。chatting_left_item用于机器人消息,里面是两个控件:一个ImageView显示机器人头像,一个TextView显示文本内容,TextView的背景引用chat_left_selector;chatting_right_item结构完全对称,ImageView换成了用户头像,背景换成了chat_right_selector。这种“一左一右两个独立布局文件”的设计是ListView时代最常用的做法,简单直接,适配器里通过消息的state字段决定加载哪个布局。

2.2 ChatBean:消息体拆成状态与内容两个字段的设计依据

机器人和用户的聊天记录不能只存一个字符串,界面需要判断这条消息到底显示在左边还是右边。报告里创建了ChatBean类来承载消息属性:一个int类型的state字段,一个String类型的message字段,外加对应的get/set方法。

public class ChatBean { private int state; private String message; public int getState() { return state; } public void setState(int state) { this.state = state; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }

代码逻辑说明:state表示消息方向,1代表用户发送,2代表机器人接收,适配器拿这个字段来决定加载左右哪个布局。message存放纯文本内容,发送和接收共用同一个字段。当然如果你愿意,给ChatBean加一个头像资源id字段也行,但这份资源里没有这么做,头像直接写死在两个布局文件里。

参数说明:state用int而不用String或boolean是有道理的——如果以后要做“机器人正在输入”这种中间态,int可以扩展枚举值而boolean不够用;如果要做本地消息记录落库,int字段在SQLite里存取也更省事。message只存文本,不存富文本格式。接口返回的JSON里如果带表情包链接或语音地址,那就是另一个需求了,这是课设资源所以限定在纯文本场景就够了。这个小类没有复杂逻辑,但它定义了整个列表数据的基本单元,适配器和Activity都围绕它转。

2.3 ChatAdapter:用 if/else 分左右气泡为什么在 ListView 里够用

ListView的适配器核心就在getView方法里。报告里ChatAdapter的思路是:遍历当前消息,如果state等于2就加载左边布局(机器人),否则加载右边布局(用户)。

@Override public View getView(int position, View convertView, ViewGroup parent) { ChatBean bean = dataList.get(position); ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); if (bean.getState() == 2) { convertView = inflater.inflate(R.layout.chatting_left_item, parent, false); } else { convertView = inflater.inflate(R.layout.chatting_right_item, parent, false); } holder.ivHead = convertView.findViewById(R.id.iv_head); holder.tvContent = convertView.findViewById(R.id.tv_content); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.tvContent.setText(bean.getMessage()); return convertView; }

代码逻辑说明:position决定取哪条消息,convertView是ListView滚动时回收的旧视图,非null时直接复用而不是重新inflate,这是ListView性能的关键。ViewHolder通过setTag挂在视图上,省掉每次都findViewById的开销。气泡方向的判断放在convertView == null分支里,意味着一条消息的布局类型在第一次创建时就被锁定,复用过程中不会再切换。

参数说明:inflater.inflate(R.layout.chatting_left_item, parent, false)里的第三个参数false表示不把inflate出来的视图立即挂到parent上,因为ListView会自己负责attach它,这里如果写成true会造成双重添加报错。state == 2对应报告里ChatBean的接收消息约定,如果你的接口文档把状态值定义反了,聊天记录会左右颠倒。

对比RecyclerView的多布局方案,ListView + if/else的做法在数据量小、布局只有两种的场景下完全没有性能问题,实现还更直观。RecyclerView的getItemViewType虽然更规范,但课设报告用ListView恰恰能展示对适配器机制的理解,答辩时更容易讲清楚。真要说缺点,就是如果以后消息类型扩展到四种以上,这种if/else会变得难维护,但那是后话。

3. 让机器人开口说话:OkHttp 请求、JSON 解析与五个核心方法

3.1 先注册一个机器人:身份 Key 与请求参数的作用

报告里第一步是去开放对话平台注册成为用户并创建一个机器人,每创建一个机器人会得到一个Key值。这个Key就是访问API的身份标识,相当于服务器判断“你是谁”的凭证。没有Key,请求会被拒绝;Key无效,返回的不会是正常回复而是一段错误信息。

注册完机器人之后要做的事是明确API地址和请求参数。不同版本平台的接口风格有差异,常见的有两种:一种是表单形式,参数是key和info;另一种是JSON形式,参数是apikey和text。以旧版文本接口为例,一个典型请求长这样:

RequestBody body = new FormBody.Builder() .add("key", "你的32位Key") .add("info", "你好") .build();

参数说明:key字段对应申请到的身份标识,info字段是用户输入的原话。接口地址需要填在Request的url里。我在实测中发现,有些平台文档更新滞后,旧版参数名用key+info,新版用apikey+text,对不上就直接报param error。所以拿到Key之后第一件事不是写代码,而是打开接口文档看参数名,文档和你申请到的Key版本一定是对应的。

3.2 getDataFromServer:OkHttp 3.12.0 异步请求的正确写法

报告里明确用了okhttp库中的OkHttpClient向服务器请求数据,版本是3.12.0。这个类负责建立连接、设置超时、发送请求、接收响应。下面是抽取出来的核心请求方法,我在自己的工程里复现过,去掉业务代码后结构如下:

private void getDataFromServer(String input) { OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .build(); RequestBody body = new FormBody.Builder() .add("key", ROBOT_API_KEY) .add("info", input) .build(); Request request = new Request.Builder() .url(ROBOT_API_URL) .post(body) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { runOnUiThread(() -> showToast("网络异常:" + e.getMessage())); } @Override public void onResponse(Call call, Response response) throws IOException { String json = response.body().string(); String reply = parseReply(json); runOnUiThread(() -> updateView(reply)); } }); }

代码逻辑说明:OkHttpClient实例通过Builder模式创建,connectTimeout是建立TCP连接的最长等待时间,readTimeout是服务器返回数据的最大等待时间,两个都设10秒是聊天场景比较常用的配置。newCall(request).enqueue(callback)表示异步执行,callback的两个方法分别对应网络失败和服务器响应成功。response.body().string()拿到的是原始JSON字符串,需要解析出text字段才是真正的回复内容。注意onResponse不在主线程,所以刷新UI必须通过runOnUiThread切换回主线程。

参数说明:ROBOT_API_KEY和ROBOT_API_URL是常量,我建议放在单独的配置类里,而不是散落在Activity中,源码里直接写字符串常量也能跑,但后续换Key就要全文搜索。FormBody意味着请求体是application/x-www-form-urlencoded格式,这是旧版文本接口常见的请求格式。如果你申请的平台接口要求JSON格式,就需要改用RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonStr)。

有个细节值得注意:在onResponse里声明了throws IOException,这是OkHttp回调接口的方法签名决定的,编译器强制你处理IO异常。我在第一次写的时候在这个方法里直接做了JSON解析,结果解析异常会在子线程里崩溃而不是被捕获,后来加了一层try-catch把new JSONObject(json)包进去才稳定。如果你的平台接口不稳定,建议在parseReply里捕获所有异常并返回一个兜底文案,比如“我好像没听清,再说一遍”。

3.3 sendData 与 updateView:从发送到刷新的完整链路

报告里在Activity中定义了五个方法:initView()负责获取界面控件并初始化数据,showData()负责把消息显示到界面上,sendData()负责取出输入框内容并发起请求,getDataFromServer()负责网络请求,updateView()负责更新界面信息。这五个方法拼起来就是一条完整的消息处理链路:点发送 → 取出文本 → 本地展示用户消息 → 请求服务器 → 获取回复 → 展示机器人消息。

private void initView() { lvChat = findViewById(R.id.lv_chat); etInput = findViewById(R.id.et_input); dataList = new ArrayList<>(); adapter = new ChatAdapter(this, dataList); lvChat.setAdapter(adapter); btnSend.setOnClickListener(v -> sendData()); } private void showData(String message, int state) { ChatBean bean = new ChatBean(); bean.setMessage(message); bean.setState(state); dataList.add(bean); adapter.notifyDataSetChanged(); lvChat.setSelection(dataList.size() - 1); } private void sendData() { String input = etInput.getText().toString().trim(); if (TextUtils.isEmpty(input)) { return; } showData(input, 1); etInput.setText(""); getDataFromServer(input); } private void updateView(String reply) { showData(reply, 2); }

代码逻辑说明:showData把消息封装成ChatBean后添加到list尾部,然后调用notifyDataSetChanged()通知适配器重新绘制列表,接着用setSelection(dataList.size() - 1)把ListView滚到最后一条,让最新消息始终可见。sendData先做空输入拦截,再先把自己的消息上屏并清空输入框,最后才发起网络请求,这样界面不会因为等待网络而显得卡死。updateView接收服务器解析出的文本,按state=2走机器人布局。

参数说明:showData里的state参数就是ChatBean的状态字段,调用时传1或2来区分左右气泡,这个数值必须和适配器里的判断保持一致。etInput.setText("")放在getDataFromServer之前执行,是为了让用户发完消息立刻能输入下一条,不用等服务返回。TextUtils.isEmpty同时覆盖null和空串两种情况,比直接判断equals("")更稳妥。

我在复现时发现报告里没有处理一种情况:快速连续点击发送按钮,会出现多条用户消息依次上屏,而机器人回复是异步的,后发的请求可能先返回,导致回复顺序跟消息顺序错位。如果课设答辩被问到这个问题,可以说“用requestId关联请求和回复”来兜住,但实际Demo里大概率不会有人连续快速发消息,这个缺陷暂时不用修。

3.4 strings.xml 随机欢迎语:从资源里拿文案比硬编码稳

报告里提到欢迎信息存放在res/values文件夹的strings.xml中,第一次进入应用时机器人会从这些预设文案里挑一条发出来。这个设计有两个好处:一是文案集中管理,改欢迎语不用改代码;二是支持从资源文件读数组实现随机挑选。

<string name="welcome_one">你好,我是机器人小明</string> <string name="welcome_two">欢迎来到聊天室,有什么想聊的?</string> <string-array name="welcome_messages"> <item>你好,我是机器人小明</item> <item>欢迎来到聊天室,有什么想聊的?</item> <item>今天天气不错,适合聊点开心的</item> </string-array>

对应在Activity中读取的代码:

Resources res = getResources(); String[] welcomeArray = res.getStringArray(R.array.welcome_messages); String welcome = welcomeArray[new Random().nextInt(welcomeArray.length)]; showData(welcome, 2);

参数说明:welcome_messages是一个字符串数组资源,getStringArray一次性读入数组内容,new Random().nextInt(length)生成0到length-1的随机下标。这样做的好处是以后加欢迎语只需要在xml里加一个<item>,不需要动Java代码。报告里只写了字符串存放在strings.xml中,没写随机逻辑,我猜它用的可能是固定文案。如果是给答辩演示,随机欢迎语比固定文案更有“智能感”——虽然只是随机取了一条。

4. 从报告到可运行工程:依赖、权限、真机与模拟器的一次性配置

4.1 依赖添加:为什么课程设计里要用 okhttp 3.12.0

报告截图里添加依赖的路径是右键项目 → Open Module Settings → Dependencies → 绿色加号 → Library dependency,然后搜索com.squareup.okhttp3:okhttp:3.12.0。在Android Studio的图形化界面里确实可以这样操作,但更稳妥的方式是直接在build.gradle里声明依赖,因为IDE搜索库的过程偶尔会卡在索引阶段。

dependencies { implementation 'com.squareup.okhttp3:okhttp:3.12.0' }

为什么不选4.x版本?3.12.0是OkHttp 3.x系列的最后一个版本,API风格是传统的OkHttpClient+Call,网上教程和课程设计的资料积累最多,遇到问题更容易搜到答案。OkHttp 4.x改用Kotlin重写,虽然用法上差异不大,但报错信息里的Kotlin堆栈会让课设阶段的人一头雾水。此外,3.12.0对Android低版本兼容性更好,API 21以上的设备都能正常跑,如果模拟器或真机是旧系统,这个版本更省心。

依赖同步后需要确认一件事情:项目里是否同时存在多个OkHttp版本。有时候其他库会传递依赖一个更高版本的OkHttp,Gradle会解析成高版本优先,导致低版本代码编译失败。排查方法是在Gradle面板里查看dependency insight,或者简单点,直接统一模块的OkHttp版本为3.12.0。

4.2 AndroidManifest:网络权限与明文流量开关

聊天机器人必须联网,所以INTERNET权限是起步配置。但只有权限还不够,如果你的接口地址是http开头的明文URL,Android 9及以上系统默认会拦截明文流量,直接报CLEARTEXT communication to xxx not permitted by transport security profile。

<uses-permission android:name="android.permission.INTERNET" /> <application android:name=".App" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:usesCleartextTraffic="true" android:theme="@style/Theme.AppCompat">

参数说明:android:usesCleartextTraffic="true"表示允许应用使用HTTP明文流量,这是调试阶段最快速的解决方案。如果你不想放开全局明文,可以改用networkSecurityConfig并在xml里配置只对特定域名放行,但课设场景没必要这么精细。INTERNET权限只声明在uses-permission里,不需要在运行时申请,因为它是普通权限而不是危险权限,这点和定位、相机权限不同。

我还遇到过一种情况:模拟器里能联网,真机死活连不上。排除掉网络开关后,检查一下是不是AndroidManifest里权限写在application标签内部了。权限必须作为manifest根节点的子元素,写在application里面会被静默忽略,编译器也不一定报错,这是初始化工程时很隐蔽的坑。

4.3 首次运行验证流程:欢迎语、输入法与头像资源

工程能跑起来之后,建议按下面的顺序做一次完整验证,每一项都有明确的通过标准。先看应用启动后是否弹出欢迎消息,这里能确认strings.xml读取、ChatBean创建、适配器左布局加载三个环节是否正常。再点输入框打字发送一条消息,观察右侧气泡是否出现在列表末尾,输入框是否被清空,服务器回复是否在几秒内出现在左侧。

报告里的运行截图暴露了一个有意思的问题:截图里发的都是数字和字母,注释写的是“没有装中文输入法”。如果模拟器没有安装中文输入法,确实只能输入英文和数字,机器人收到的文本就是一堆字母,回复会出现“往下接”“额”这种勉强关联的答案,演示效果看起来很人工智障。解决办法有两个,一个是在模拟器里安装中文输入法APK,另一个是临时在代码里写死一个测试字符串作为输入来源。我一般选择后者,因为演示时直接点按钮就能看到机器人回复,不用现场敲字。

头像资源也是容易出问题的地方。chatting_left_item里的ImageView引用的@mipmap/robot_head如果没放在对应目录,编译期不报错,运行到getView加载该布局时才抛Resources.NotFoundException,而且只在机器人消息出现时崩溃。首次验证时建议先把两条消息都发出来,确保左右两个布局的图片资源都实际加载过一遍。

5. 避坑排查:聊天机器人课设最容易翻车的五个工程细节

5.1 返回键行为异常:onKeyDown 里 exit 的时机问题

现象:连续按两次返回键,第一次没反应,第二次直接退出应用;或者按一次返回键就直接杀进程,没有回到桌面。

原因:报告里重写onKeyDown()实现“点击返回键退出智能聊天程序”,但很多初次写的代码是if (keyCode == KEYCODE_BACK) { finish(); },没有任何时间间隔判断。第一次点击已经触发了finish(),只是Activity销毁动画还没结束,第二次点击又触发了一次。更常见的是把退出逻辑写成了直接退出整个进程而不是返回到桌面,如果是从桌面图标启动的应用,finish()后看起来像“退出了”,实际上回到桌面才是预期行为。

解决:finish()本身就是退出当前Activity,从桌面启动应用时会回到桌面,这个行为没问题。问题在于很多同学把“退出程序”理解成了System.exit(0)或Process.killProcess,这会导致应用彻底挂掉,下次启动要重新走启动流程。正确的做法就是finish(),如果担心误触,可以加一个两次按键间隔判断:

@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { finish(); return true; } return super.onKeyDown(keyCode, event); }

核心是把return true和return super分开,表示返回键已被消费,不再交给系统默认处理。

5.2 气泡头像错位:convertView 复用导致的显示混乱

现象:连续发送多条消息后,某条消息的头像或气泡背景和内容对不上,机器人消息的文本串到了用户气泡里。

原因:ListView的convertView复用了之前的视图。如果适配器里先判convertView == null,在复用分支里不重新设置头像资源或背景资源,那么滚出屏幕再滚回来的消息会带着上一次的显示状态。更隐蔽的是,如果布局判断写在复用分支的外部,同一个复用视图在两种布局之间切换时会沿用convertView的旧布局,造成内容与气泡样式不一致。

解决:严格遵循“布局类型决定convertView来源”的原则。要么用getItemViewType区分视图类型,要么像我前面给的代码那样,把布局inflate放在convertView == null分支里,根据bean.getState()选择对应的左右布局。复用分支只更新文本内容,不再碰布局相关属性。如果头像之间有差异,也要在复用分支里重新setImageResource。

5.3 Activity 命名不一致:MainActivity 与 RobotActivity 的版本残留

现象:报告文字提到RobotActivity,代码和截图里又是MainActivity,按文档里的类名去查代码找不到对应文件。

原因:这份课程设计报告在编写过程中Activity被重命名过,文档没同步更新。项目正文里Activity的五个方法描述用了MainActivity,程序设计和说明章节又冒出了RobotActivity,同一个类两种叫法。课设报告本身就是批量模板改出来的,这种现象很常见,不代表代码有问题。

解决:复现时以AndroidManifest里注册的Activity名为准。打开AndroidManifest.xml,看<activity android:name=".MainActivity">指向的是哪个文件,那就是真正运行的入口。报告里的方法描述只用来理解逻辑,不用严格对应类名。我拿到这类资源时第一件事就是跳转Manifest,先确认入口Activity再读代码,能省下不少对名字的时间。

5.4 高版本 Android 拦 HTTP:CLEARTEXT communication 的处理

现象:应用在Android 8及以下版本正常回复,在Android 9及以上版本点发送后没有反应,Logcat刷出CLEARTEXT communication ... not permitted。

原因:从Android 9开始,系统默认禁止应用使用明文HTTP流量,所有http://请求都会被拦截。报告写成的年代还在Android 8时代,用的是http://接口地址,所以才没遇到这个问题。模拟器如果跑的是API 28以上系统镜像,必现这个坑。

解决:在<application>节点上配置android:usesCleartextTraffic="true",或者用网络安全配置精确放行API域名。课设场景用前者最省事。如果只是想演示而不改配置,把模拟器系统镜像换成Android 8也能跑,但这不是正经解法。

5.5 文档与代码脱节:实验目的里的“音乐播放器”是模板残留

现象:报告的实验目的写着“开发设计一款简单的连接数据库的音乐播放器APP”,实验内容却全是聊天机器人的实现步骤,文不对题。

原因:课程设计报告是套模板写的,实验目的那段文字是从音乐播放器项目里复制过来忘了改,这是学校课设报告里的大量存在现象。正文内容和代码主体完全对应聊天机器人,所以这不影响复现,只影响阅读体验。

解决:读报告时以实验内容、程序设计、类的说明三章为准,实验目的那一段直接跳过。如果你要交自己的课程设计报告,务必把实验目的改成和聊天机器人一致,否则答辩老师扫一眼就会问“音乐播放器在哪”。我见过好几份因为模板残留被扣分的报告,这种低级错误不值得犯。

6. 进阶验证:把聊天 Demo 变成拿得出手的演示程序

6.1 三招让课设演示更顺畅

第一招是解决中文输入法问题。模拟器默认不带中文输入法,演示时临时打字很尴尬。我在实测中常做的做法是通过ADB命令先安装一款中文输入法APK,或者更简单,写一个调试按钮直接注入预设的中文文本:

String testMessage = "介绍一下你自己"; showData(testMessage, 1); etInput.setText(""); getDataFromServer(testMessage);

从长远看,这个调试入口还能当“机器人指令面板”用,展示时点一下就触发,不用现场敲键盘。

第二招是把Key从Activity里抽出来。原报告把Key直接写在Activity里,每次换账号都要翻代码。放到build.gradle的buildConfigField里,以后改Key只动一个位置:

buildTypes { release { buildConfigField "String", "ROBOT_API_KEY", "\"你的Key\"" } debug { buildConfigField "String", "ROBOT_API_KEY", "\"你的Key\"" } }

对应代码里读的时候用BuildConfig.ROBOT_API_KEY。别把真实Key提交到公开仓库,这算是给自己的第一个安全习惯。

第三招是验证阶段过一遍完整验收清单。我每次拿到这类资源都按下面的表走一遍,全过才算真的复现成功。

验收项通过标准
首次进入左侧出现欢迎气泡
中文消息左侧机器人回复,内容与发送内容关联
英文/数字消息机器人正常回复,不报错
网络断开Toast提示网络异常,界面不崩溃
连续发送每条消息右侧气泡按顺序排列,回复不串位
返回键应用退出,回到桌面
旋转屏幕聊天记录保留,界面不闪退

最后提醒一个容易被忽略的细节:演示前把输入法切换到英文模式再发消息,机器人回复会很依赖平台词库的语义能力,有些平台对纯数字或单字母的回复质量很低,看起来像“傻子”。我一开始也觉得这个锅要甩给平台,后来发现换个说法——“帮我写个300字的自我介绍”,回复质量立刻不一样。从那以后我每次演示前都强制自己先想好三条有代表性的问题,而不是随手打几个字。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询