手把手教你做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; } }
简单解释下。其中对话框是一个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 标签外面
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。