该小项目是一个关于和智能机器人的聊天小项目,使用的是图灵api的聊天接口,并接入了科大讯飞的语音识别和语音合成功能实现语音聊天。有关更多的功能请关注本博客,博主会在有时间的时候进行更新的。
自己开发小项目首先遇到的问题就是要找图片资源,这里我推荐一个方法,就是下载一个常用的apk如QQ,将其格式改成zip格式,然后去提取我们所需要的图片,像这种大型公司的app基本能提取到我们所需要的大部分图片资源。
接下来就是实现我的智能小机器人了。
1、布局文件
首先是主界面activity_main的布局,用一个listview来显示聊天信息,不过listview的item有两种类型,分别是发送消息端和接收消息端。
主界面布局文件如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f2f2f2" >
<RelativeLayout
android:id="@+id/rl_chat_title"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@drawable/title_bg" >
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="小灰灰"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_chat_bottom"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="#f2f2f2" >
<ImageButton
android:id="@+id/ib_voice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/mal" />
<Button
android:id="@+id/btn_send"
android:layout_width="55dp"
android:layout_height="40dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/chat_send_btn"
android:text="发送"
android:textColor="@android:color/white"
android:textSize="13sp" />
<EditText
android:id="@+id/et_send"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_toLeftOf="@id/btn_send"
android:layout_toRightOf="@id/ib_voice"
android:background="@drawable/login_edit_normal"
android:singleLine="true"
android:textSize="18sp" />
</RelativeLayout>
<ListView
android:id="@+id/lv_info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/rl_chat_bottom"
android:layout_below="@id/rl_chat_title"
android:cacheColorHint="#0000"
android:divider="@null"
android:dividerHeight="5dp"
android:scrollbarStyle="outsideOverlay" >
</ListView>
</RelativeLayout>
发送端item的布局文件item_chat_send如下:
<?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" >
<TextView
android:id="@+id/tv_item_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center"
android:padding="2dp" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/iv_item_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentRight="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:src="@drawable/boy" />
<TextView
android:id="@+id/tv_item_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_toLeftOf="@id/iv_item_icon"
android:background="@drawable/chat_send_msg"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
android:lineSpacingExtra="2dp"
android:text="你好"
android:textColor="#000"
android:textSize="15sp" />
</RelativeLayout>
</LinearLayout>
因为接收端和发送端布局文件基本一致,就不贴代码了,最后会提供代码下载的。
2、HttpTask
封装了一个用于访问图灵API的AsyncTask异步类,其中doInBackground()用于执行耗时的网络操作即get请求,在onPostExecute()方法中对doInBackground执行后返回的结果进行处理,这里使用接口回调的方式监听请求的结果,代码如下:
public class HttpTask extends AsyncTask<Void, Void, String> {
private static final String tag = "HttpTask";
private String urlStr;
private OnHttpListener listener;
private boolean b;
public HttpTask(String urlStr, OnHttpListener listener) {
this.urlStr = urlStr;
this.listener = listener;
}
@Override
protected String doInBackground (Void... params) {
String res = null;
URL url;
InputStream is = null;
ByteArrayOutputStream baos = null;
HttpURLConnection conn = null;
try {
url = new URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
// 设置超时时间
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
// 获取响应码
int code = conn.getResponseCode();
if (code == 200) {
is = conn.getInputStream();
baos = new ByteArrayOutputStream();
int len = 0;
byte[] buffer = new byte[128];
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.flush();
res = baos.toString();
b = true;
Log.d(tag, "res====" + res);
}
} catch (Exception e) {
b = false;
res = e.toString();
} finally {
if (conn != null) {
conn.disconnect();
}
}
return res;
}
@Override
protected void onPostExecute(String result) {
if (b) {
listener.onFinish(result);
} else {
listener.onError(result);
}
}
}
如上,当activity中需访问服务器数据时,只需创建调用HttpTask子类的excute()方法即可,当访问成功时在onFinish()中对数据进行处理即可。这里将数据处理后封装成MessageInfo类。
3、MessageInfo
public class MessageInfo {
public static final int SEND = 10001;
public static final int RECEIVE = 10002;
private String time;
private String text;// 消息内容
private int msgType;// 消息类型
public MessageInfo() {
super();
}
public MessageInfo(int msgType, String msgContent, String time) {
setMsgType(msgType);
setText(msgContent);
setTime(time);
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getMsgType() {
return msgType;
}
public void setMsgType(int msgType) {
this.msgType = msgType;
}
}
4、MainActivity
我对主界面主要分成三个模块处理,分别是initView(),initData(),initEvent()。在initView中主要初始化布局中的控件,initData()中主要初始化数据这里主要为listview设置第一句欢迎问候语,在initListener()中设置各种监听事件这里主要给语音识别和发送消息按钮设置点击事件监听器。
由于代码比较多,这里只给出需要注意的部分:
如下,这里设置当两条信息的间隔时间超过两分钟,聊天的当前时间才不会为空,否则一律为空。
/**
* @return
* 获取聊天的当前时间
*/
private String getCurrentTime() {
currentTime = System.currentTimeMillis();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date curDate = new Date();
String time = format.format(curDate);
if (currentTime - oldTime >= 1000 * 60 * 2) {
oldTime = currentTime;
return time;
} else {
return "";
}
}
这里还需注意的是当退出activity时记得释放资源,如下:
@Override
protected void onDestroy() {
super.onDestroy();
// 退出时释放连接
if (mIat != null) {
mIat.cancel();
mIat.destroy();
}
if (mTts != null) {
mTts.stopSpeaking();
mTts.destroy();
}
}
5、科大讯飞的集成
要想在项目中集成科大讯飞语音,请登录科大讯飞开发平台http://www.xfyun.cn/,没有账号先进行注册。创建一个应用然后下载对应服务的sdk,每创建一个应用都会得到一个appid,这个appid在使用语音功能是需要用到的,接下来就按照其官方文档和demo的说明,将语音识别和语音合成集成到项目中即可,很简单。
6、适配器ChatAdapter
需要注意的是因为这里的listview的item有两种类型,所以需比平时多重写两个方法:
//发送消息为0,接收消息为1
@Override
public int getItemViewType(int position) {
// range 0 to getViewTypeCount - 1.
MessageInfo messageInfo = datas.get(position);
return messageInfo.getMsgType() == MessageInfo.SEND ? 0 : 1;
}
@Override
public int getViewTypeCount() {
return 2;
}
getViewTypeCount表示listview中item类型有多少种,getItemViewType()表示返回item的类型,根据当前position的item决定返回不同的整数,然后在getView()中根据item的类型去加载不同的item布局。
以上是对智能小机器人的简单分析,只给出了部分代码,有兴趣的朋友请点击此处下载。