手把手教你做Android聊天机器人
我相信大家应该知道有款应用叫小黄鸡吧!
如果不知道,那你见过那种可以秒回复的聊天应用么?
如果仍然没看到!那你总见过可以迅速回复你的微信公共账吧!
如果仍然....亲出门左拐
好,不多说。
首先大家都应该了解程序,程序就是由人为的设定搭建起来的一套系统,
这里的机器人也是,简单的原理就是当你输入关键字后,通过一套算法,
在数据库中找到与之最为匹配的内容在返回给你。这个已经有人实现,我们这节教程就用别人
已经实现好的东西去做一??个应用来玩耍~~
(当然如果你非要想知道如何去做,给我留言。看情况我会出篇教程去交大家如何去做这个后端的机器人)
首先我们需要设计程序。
需要用到的类
豆
-------ChatMessage.java(自己创建的类,目的是为了在接受与发送的时候把信息封装对象化)
------- Result.java(接受信息时候需要用到的返回信息类)
直到
------- AiaiUntil.java(自己创建的类型,用来发送信息与得到返回信息的工具)
------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- -------
CharMessageAdapter.java (因为是聊天形式的应用,所以布局需要时动态的,这里引用的布局Adapter需要继承BaseAdapter )
MainActivity.java(程序入口,程序的总展示层)
以上就是用到的所有类,很少吧。
为什么这么少,是因为我们借用的是别人写好的机器人后台- 图灵机器人
大家可以点开连接,简单看看里面的API是如何用的。
【手把手教你做Android聊天机器人】
请求方式
API地址:http://www.tuling123.com/openapi/api
请求方式:HTTP GET
数据格式:JSON
返回的数据都是JSON。还有不论是否返回成功都会返回一个代码,用来判断是否返回成功
下面我们就进行代码的编写,首先是封装信息的对象。
ChatMessage。java的
包装com.www.xiaoaiai.com.bean;
进口java.util.Date的;
公共类ChatMessage {
私人字符串名称;
私人弦乐味精;
私人类型类型;
私人时间日期;
公共ChatMessage(){}
公共ChatMessage(弦乐味精,类型类型,日期为准){
this.msg =味精;
this.type =类型;
this.date =日期;
}//定义枚举定义类型
//枚举是用来区分数据类型
公共枚举类型
{
来料,OUTCOMING
}
公共字符串的getName(){
返回的名称;
}
公共无效的setName(字符串名称){
this.name =名称;
}
公共字符串的getMsg(){
返回味精;
}
公共无效setMsg(弦乐味精){
this.msg =味精;
}
公共类型的getType(){
返回类型;
}
公共无效的setType(类型类型){
this.type =类型;
}
公开日期GETDATE(){
返回日期;
}
公共无效的setDate(日期为准){
this.date =日期;
}}
下面是信息结果类
包装com.www.xiaoaiai.com.bean;
/ **
*
* @author Srain_zhou
*为了发送一个对话对象到服务器所需要的映射对象
* /
公共类结果{
//此处注意开头字母组好小写,因为返回的结果键都是小谢的
私人诠释代码;
私人字符串文本;
公众诠释引用代码(){
返回代码;
}
公共无效setCode(INT代码){
this.code =代码;
}
公共字符串的getText(){
返回文本;
}
公共无效的setText(字符串文本){
this.text =文本;
}
}
下面是核心交换类,可以理解为DAO
AiaiUntil.java
包com.www.xiaoaiai.com.until;
进口java.io.ByteArrayOutputStream中;
进口java.io.IOException的;
进口的java.io.InputStream;
进口java.io.UnsupportedEncodingException;
进口java.net.HttpURLConnection中;
进口java.net.MalformedURLException;
进口java.net.URLEncoder中;
进口java.util.Date的;
进口com.google.gson.Gson;
进口com.www.xiaoaiai.com.bean.ChatMessage;
进口com.www.xiaoaiai.com.bean.ChatMessage.Type;
进口com.www.xiaoaiai.com.bean.Result;
公共类AiaiUntil {
//连接图灵机器人的接口
私有静态最后字符串URL =“htt??p://www.tuling123.com/openapi/api”;
//自己的apikey
私有静态最后弦乐API_KEY =“自己去申请的一个APP_KEY体验下开发的快感吧!”;
//发送一个消息,得到返回的消息
公共静态ChatMessage的sendMessage(弦乐味精){
//创建一个封装信息对象
ChatMessage chatmessage =新ChatMessage();
//此处请看的doGet方法
字符串jsonRes =的doGet(MSG);
// GSON是谷歌提供的一个JAR包主要用途为序列化的Java对象为JSON字符串,或反序列化JSON字符串成的Java对象。
//序列化是为了网路传输
GSON GSON =新GSON();
结果结果= NULL;
尝试{
//为了获得返回字符串
结果= gson.fromJson(jsonRes,Result.class);
chatmessage.setMsg(result.getText());
}赶上(例外五){
chatmessage.setMsg(“服务器繁忙”);
}chatmessage.setDate(新日期());
chatmessage.setType(Type.INCOMING);
返回chatmessage;
}
公共静态字符串的doGet(弦乐味精){
字符串结果=“”;
//拼接网址此处需要详细了解图灵机器人的请求方式
字符串URL = setRarams(MSG);
//输入流
InputStream的是= NULL;
// ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个字节数组。
ByteArrayOutputStream BAOS = NULL;
//构建发送请求的对象
尝试{
的java.net.URL url_net =新的java.net.URL(URL);
HttpURLConnection的CONN =(HttpURLConnection类)url_net.openConnection();
//设置从主机读取数据超时
conn.setReadTimeout(5 * 1000);
//设置连接主机超时
conn.setConnectTimeout(5 * 1000);
//设置连接方式
conn.setRequestMethod(“GET”);
//获取写入流
是= conn.getInputStream();
//设置缓冲区
整型长度= -1;
//设置缓冲区128字节
byte []的BUF =新的字节[128];
//吧流转换成字符串的类
BAOS =新ByteArrayOutputStream();
//判断是否读完
而((长度= is.??read(BUF))!=-1){
baos.write(BUF,0,长度);
}
//清除缓冲区
baos.flush();
//把流转换为字符串
结果=新的String(baos.toByteArray());
}赶上(MalformedURLException的E){
// TODO自动生成的catch块
e.printStackTrace();
}赶上(IOException异常E){
// TODO自动生成的catch块
e.printStackTrace();
}最后{
//释放资源
尝试{
如果(BAOS!= NULL){
baos.close();
}
}赶上(IOException异常E){
// TODO自动生成的catch块
e.printStackTrace();
}
尝试{
如果(是!= NULL){
is.close();
}
}赶上(IOException异常E){
// TODO自动生成的catch块
e.printStackTrace();
}
}返回结果;
} //构建请求路径的方法
公共静态字符串setRarams(弦乐味精){
字符串URL_value = https://www.it610.com/article/NULL;
尝试{
URL_value =网址+ + + API_KEY“与信息=”+ URLEncoder.encode(MSG,“UTF-8”)“键=?”;
}赶上(UnsupportedEncodingException E){
// TODO自动生成的catch块
e.printStackTrace();
}
返回URL_value;
}
}
CharMessageAdapter.java内容提供者,里面关于对话的布局文件你可以按照自己的喜欢自己去设计 简单解释下。其中对话框是一个listView 里面分别是两组不同的ListView(红色与蓝色),请结合下面
代码去模拟定义自己的对话布局,我就觉得我的布局丑,所以就不贴代码了。自己DIY吧~~
文章图片
包com.www.xiaoaiai.com;
进口java.text.SimpleDateFormat的;
进口的java.util.List;
进口com.www.xiaoaiai.com.bean.ChatMessage;
进口com.www.xiaoaiai.com.bean.ChatMessage.Type;
进口android.content.Context;
进口android.view.LayoutInflater;
进口android.view.View;
进口android.view.ViewGroup;
进口android.widget.BaseAdapter;
进口android.widget.TextView;
公共类CharMessageAdapter扩展了BaseAdapter {
/ **
*对于一个没有被载入或者想要动态载入的界面,都需要使用充气来载入。
*的Andr??oid里面想要创建一个画面的时候,初学一般都是新建一个类,继承活动基类,
*然后在的onCreate里面使用的setContentView方法来载入一个在XML里定义好的界面。
*其实在活动里面就使用了LayoutInflater来载入界面,
*通过getSystemService(Context.LAYOUT_INFLATER_SERVICE)方法可以获得一个LayoutInflater,
*也可以通过LayoutInflater吹气= getLayoutInflater();
*来获得。然后使用充气方法来载入布局的XML,
*在实际开发种LayoutInflater这个类还是非常有用的,它的作用类似于findViewById()
*不同点是LayoutInflater是用来找布局下的xml布局文件,
*并且实例化!而findViewById()是找具体的xml下的具体窗口小部件控件。
* /
//用来重载布局的对象,是机器人已经帮我们做好的类
私人LayoutInflater mInflater;
//聊天信息数据集合
私人名单 mDatas;
公共CharMessageAdapter(上下文语境,名单 mDatas){
mInflater = LayoutInflater.from(上下文);
this.mDatas = mDatas;
}
//继承BaseAdapter需要重写的方法,获取数据的长度
@覆盖
公众诠释getCount将(){
// TODO自动生成方法存根
返回mDatas.size();
}
//继承BaseAdapter需要重写的方法,获取数据所处的项目
@覆盖
公共对象的getItem(INT位置){
// TODO自动生成方法存根
返回mDatas.get(位置);
}
//继承BaseAdapter需要重写的方法,获取ITEMID
@覆盖
众长getItemId(整数位){
// TODO自动生成方法存根
回到位置;
}
/ **
*因为本次需要布局两次不同位置所以需要多写两个方法
* /
// getItemViewType方法告诉ListView中每行该显示哪种项目
@覆盖
公众诠释getItemViewType(整数位){
ChatMessage chatMessage = mDatas.get(位置);
如果(chatMessage.getType()== Type.INCOMING){
返回0;
}
返回1;
}
// getViewTypeCount这个方法告诉ListView控件我共有多少种项目
@覆盖
公众诠释getViewTypeCount(){
// TODO自动生成方法存根
返回2;
}
/ **
*就是一个持有者的类,他里面一般没有方法,
*只有属性,作用就是一个临时的储存器,
*把你getView方法中每次返回的视图存起来,可以下次再用。
*这样做的好处就是不必每次都到布局文件中去拿到你的视图,提高了效率。
* /
私人final类ViewHolder {
TextView的mDate;
TextView的MMSG;
}
//如下这个就是如何动态布局的代码
@覆盖
公共查看getView(INT位置,查看convertView,父母的ViewGroup){
ChatMessage chatMessage = mDatas.get(位置);
//上文中说出用处,提高页面效率
ViewHolder viewholder = NULL;
如果(convertView == NULL){
//通过的ItemType设置不同的布局
如果(getItemViewType(位置)== 0){
convertView = mInflater.inflate(R.layout.item_from_msg,父母,假);
viewholder =新ViewHolder();
viewholder.mDate =(TextView的)convertView.findViewById(R.id.from_msg_date);
viewholder.mMsg =(TextView的)convertView.findViewById(R.id.from_msg);
}
其他{
convertView = mInflater.inflate(R.layout.item_to_msg,父母,假);
viewholder =新ViewHolder();
viewholder.mDate =(TextView的)convertView.findViewById(R.id.to_msg_date);
viewholder.mMsg =(TextView的)convertView.findViewById(R.id.to_msg);
}
//在使用LayoutInflater对象进行查看扩充的标签的使用
//用来标记convertView,如果viewholder对象有就不在重新生成对象,为了效率!
convertView.setTag(viewholder);
}其他{
viewholder =(ViewHolder)convertView.getTag();
}
//下面这段代码慢慢看,很简单
SimpleDateFormat的DF =新的SimpleDateFormat(“YYYY-MM-DD HH:MM:SS”);
viewholder.mDate.setText(df.format(chatMessage.getDate()));
viewholder.mMsg.setText(chatMessage.getMsg());
返回convertView;
}
}
下面就是最主要的主MainActivity了~~
package com.www.xiaoaiai.com;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.www.xiaoaiai.com.bean.ChatMessage;
import com.www.xiaoaiai.com.bean.ChatMessage.Type;
import com.www.xiaoaiai.com.until.AiaiUntil;
import android.support.v7.app.ActionBarActivity;
import android.text.TextUtils;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
//最外边的对话布局
private ListView mMsg;
//内容提供对象
private CharMessageAdapter mAdapter;
//数据集合
private List mDatas;
//VIEW
private EditText mInputMsg;
private Button mSendMsg;
//因为要更新界面所以要用 Handler mHandler
private Handler mHandler =new Handler(){
public void handleMessage(android.os.Message msg) {
//等待ijieshou子线程
ChatMessage cm=(ChatMessage)msg.obj;
mDatas.add(cm);
mAdapter.notifyDataSetChanged();
mMsg.setSelection(mDatas.size()-1);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
//初始化视图
initView();
//初始化数据
initDatas();
//初始化监听
initListener();
} private void initListener() {
mSendMsg.setOnClickListener(new OnClickListener() {@Override
public void onClick(View v) {
final String toMsg = mInputMsg.getText().toString();
if(TextUtils.isEmpty(toMsg)){
Toast.makeText(MainActivity.this, "发送消息不可以为空", Toast.LENGTH_SHORT).show();
return;
}
//为了做聊天的效果
ChatMessage toMessage = new ChatMessage();
toMessage.setDate(new Date());
toMessage.setMsg(toMsg);
toMessage.setType(Type.OUTCOMING);
mDatas.add(toMessage);
mAdapter.notifyDataSetChanged();
mMsg.setSelection(mDatas.size()-1);
mInputMsg.setText("");
new Thread(
new Runnable() {
public void run() {
//网络访问不能用在主线程中应该在子线程中
ChatMessage fromMessage =AiaiUntil.sendMessage(toMsg);
Message m =Message.obtain();
m.obj=fromMessage;
//发送后 会在handler中的handleMessage中接受到
mHandler.sendMessage(m);
}
}).start();
}
});
}
private void initDatas() {
mDatas =new ArrayList();
mDatas.add(new ChatMessage("你好,我是小艾艾",Type.INCOMING,new Date()));
mAdapter = new CharMessageAdapter(this,mDatas);
mMsg.setAdapter(mAdapter);
}
private void initView() {
mMsg=(ListView)findViewById(R.id.id_list_view_01);
mInputMsg=(EditText)findViewById(R.id.input_msg);
mSendMsg=(Button)findViewById(R.id.id_send_msg);
}
}
希望对大家的学习有帮助~~~
提示!~~~
1如果你编译不出现R文件,也就是说R. 不出来 说明你的XML文件绝对有错误
2在这个APP中,千万别忘记加网络访问权限~
在
AndroidManifest.xml 文件中
加入如下代码
推荐阅读
- 我要做大厨
- 2.6|2.6 Photoshop操作步骤的撤消和重做 [Ps教程]
- 我从来不做坏事
- 子龙老师语录
- 做一件事情的基本原理是什么()
- 做个俗物有什么不好
- 28岁|28岁,做一个通透又自由的姑娘。
- 良心
- 原生家庭之痛与超越
- 我喜欢做菜,是因为懂得了什么是爱