手把手教你做Android聊天机器人

我相信大家应该知道有款应用叫小黄鸡吧!

如果不知道,那你见过那种可以秒回复的聊天应用么?

如果仍然没看到!那你总见过可以迅速回复你的微信公共账吧!

如果仍然....亲出门左拐


好,不多说。

首先大家都应该了解程序,程序就是由人为的设定搭建起来的一套系统,

这里的机器人也是,简单的原理就是当你输入关键字后,通过一套算法,

在数据库中找到与之最为匹配的内容在返回给你。这个已经有人实现,我们这节教程就用别人

已经实现好的东西去做一??个应用来玩耍~~

(当然如果你非要想知道如何去做,给我留言。看情况我会出篇教程去交大家如何去做这个后端的机器人)


首先我们需要设计程序。

需要用到的类

-------ChatMessage.java(自己创建的类,目的是为了在接受与发送的时候把信息封装对象化)

------- Result.java(接受信息时候需要用到的返回信息类)

直到

------- AiaiUntil.java(自己创建的类型,用来发送信息与得到返回信息的工具)


------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- -------

CharMessageAdapter.java (因为是聊天形式的应用,所以布局需要时动态的,这里引用的布局Adapter需要继承BaseAdapter )

MainActivity.java(程序入口,程序的总展示层)


以上就是用到的所有类,很少吧。

为什么这么少,是因为我们借用的是别人写好的机器人后台- 图灵机器人

大家可以点开连接,简单看看里面的API是如何用的。

请求方式

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 = 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;
	//聊天信息数据集合
	私人名单<ChatMessage> mDatas;
	公共CharMessageAdapter(上下文语境,名单<ChatMessage> 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<ChatMessage> 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<ChatMessage>();
		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 文件中

加入如下代码

 <uses-permission android:name="android.permission.INTERNET"/> 加载application  标签外面




郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。