Android--智能机器人聊天

Posted 邮递时光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android--智能机器人聊天相关的知识,希望对你有一定的参考价值。

借助API,可快速实现在安卓手机上的与智能机器人聊天的功能。大体的步骤有:1、异步请求数据;2、解析json数据;3、封装数据;4、实现布局;
源代码下载地址:http://download.csdn.net/detail/leyezhiqiu/9471571
实现效果如下图:
效果图

下面一一介绍。

1、在浏览器上获取与机器人对话的数据。

1)打开图灵机器人官网,注册账号www.tuling123.com/openapi 。
2)登录账号,记录下官方分配给账号的key。
3)在账号中查看获得数据的格式,如get的请求方式格式:http://www.tuling123.com/openapi/api?key=XXX&info=XXXXX&userid=XXXXXXX
4)在浏览器上测试能否通过get方式获得对应数据。

2、在android工程中获取数据。

1)编写异步通信类HttpData.java:发送请求,获取数据,读取数据。

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.os.AsyncTask;

/**
 * 异步通信类
 * 
 * @author mingyue
 * 
 */
public class HttpData extends AsyncTask<String, Void, String> {

    private HttpClient httpClient;
    private HttpGet httpGet;
    private HttpResponse httpResponse; // 获取请求返回的数据
    private HttpEntity httpEntity;// 创建http实体
    private InputStream in; // 将获取到的数据转化为流文件
    private HttpGetDataListener listener;// 实现自定义的HttpGetDataListener接口,并且构造化传递参数
    private String url;

    public HttpData(String url, HttpGetDataListener listener) {
        this.url = url;
        this.listener = listener;
    }

    @Override
    protected String doInBackground(String... params) {// 实现接口后重写此方法,此方法的作用是:发送get请求后,获取数据
        try {
            httpClient = new DefaultHttpClient();// 实例化客户端
            httpGet = new HttpGet(url);// 使用get方式,通过发送URL来请求
            httpResponse = httpClient.execute(httpGet); // 通过客户端发送请求
            httpEntity = httpResponse.getEntity();// 通过httpResponse对象获取数据

            in = httpEntity.getContent();// 获取实体的具体内容
            BufferedReader br = new BufferedReader(new InputStreamReader(in));// 获取到具体内容后,通过缓冲区进行读取

            String line = null; // 读取数据
            StringBuffer sb = new StringBuffer();// 储存所有数据
            while ((line = br.readLine()) != null) { // 读取缓冲区的数据
                sb.append(line); // 存储数据到StringBuffer中
            }
            return sb.toString();// 转换为String类型
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 重写此方法,通过这方法获取数据
     */
    @Override
    protected void onPostExecute(String result) {
        listener.getDataUrl(result);// 返回数据
        super.onPostExecute(result);
    }

}

2)由于要将获取到的数据传递给其它页面,所有这里新建一个接口,采用回调的方式。
//HttpGetDataListener.java

public interface HttpGetDataListener {
    void getDataUrl(String data);
}

3)在MainActivity中实现HttpGetDataListener接口,测试能否获得数据。
具体代码如下:

public class MainActivity extends Activity implements HttpGetDataListener{

    private HttpData httpData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        httpData = (HttpData) new HttpData(
                "http://www.tuling123.com/openapi/api?key=XXXXX&info=北京",
                this).execute();//execute()启动异步通信,注意:XXXXX应该是在步骤1获取的key值
    }

    /**
    *实现抽象方法
    */
    @Override
    public void getDataUrl(String data) {
        System.out.println(data);
    }
}

4)运行代码,在logcat中能看到相关的json数据,则说明数据获取成功。
图1

3、解析json数据。

在MainActivity.java中编写parseText()方法,解析数据,在getDataUrl()方法中调用parseText()方法。
代码如下:

    @Override
    public void getDataUrl(String data) {
        System.out.println(data);
        parseText(data);
    }

    public void parseText(String str){
        try {
            JSONObject jb = new JSONObject(str);
            System.out.println(jb.getString("code"));
            System.out.println(jb.getString("text"));
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

再次运行代码,可看到运行结果如下:
图2

4、封装数据

1)创建ListData.java,用于封装数据,如机器人的对话、时间等,现只是初步封装时间。代码如下:

public class ListData {
    private String content;

    public ListData(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

2)修改MainActivity.java,让解析出的json数据封装好(具体步骤:新建实例化方法initiView() 方法,实例化List lists;在parseText()方法中实例化ListData listData,将解析出的json数据封装到listData,再将listData添加到lists)。完成后,MainActivity.java的代码如下所示。

public class MainActivity extends Activity implements HttpGetDataListener {

    private HttpData httpData;
    private List<ListData> lists;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        httpData = (HttpData) new HttpData(
                "http://www.tuling123.com/openapi/api?key=XXXXX&info=北京",
                this).execute();//execute()启动异步通信,注意:XXXXX应该是在步骤1获取的key值
    }

    /**
     * 实例化方法
     */
    public void initView() {
        lists = new ArrayList<ListData>();
    }

    /**
     * 实现HttpGetDataListener接口的抽象方法,获取到HttpData得到的数据
     */
    @Override
    public void getDataUrl(String data) {
        System.out.println(data);
        parseText(data);
    }

    /**
     * 解析json、封装数据
     * 
     * @param data
     */
    public void parseText(String data) {
        System.out.println("data======" + data);
        try {
            JSONObject jb = new JSONObject(data);
            ListData listData;
            listData = new ListData(jb.getString("text"));// 封装数据
            lists.add(listData);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

5、实现布局。

1)在与MainActivity对应的layout中添加控件:一个ListView(作用:显示对话)、一个EditText(作用:对话输入框)、一个Button(作用:发送按钮)。
完整具体代码如下。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <!-- transcriptMode 自动向下滚动    alwaysScroll一直向下滚动状态;   divider设置间隔线效果 ;   listSelector设置没有滑动效果 -->

    <ListView
        android:id="@+id/lv"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:divider="@null"
        android:listSelector="@android:color/transparent"
        android:transcriptMode="alwaysScroll" >
    </ListView>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#229dec"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/et_sendText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="7dp"
            android:layout_weight="1"
            android:background="@drawable/bg_edittext_selector"
            android:paddingBottom="7dp"
            android:paddingTop="7dp" />

        <Button
            android:id="@+id/btn_send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="7dp"
            android:background="@drawable/bg_button"
            android:text="@string/send" />
    </LinearLayout>

</LinearLayout>

2)创建与ListView想对应的适配器
(1)要先在ListData中封装一标识flag,用于表示适配器加载哪一个view。因为在聊天对话ListView中,每一个item的中的控件摆放位置是不一样的。同时在ListData中添加String time,表示对话时间数据。ListData完整代码如下所示。

/**
 * 把获取到的数据封装起来
 * 
 * @author mingyue
 * 
 */
public class ListData {
    public static final int SEND = 1;
    public static final int RECEIVE = 2;
    private String content;
    private int flag;// 标识
    private String time;

    public ListData(String content, int flag, String time) {
        setContent(content);
        setFlag(flag);
        setTime(time);
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public int getFlag() {
        return flag;
    }

    public void setFlag(int flag) {
        this.flag = flag;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

(2)创建名为leftitem.xml的layout,在ListView中对应机器人item:一个TextView(作用:显示时间)、ImageView(作用:显示头像)和TextView(作用:显示对话内容)。代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/tv_time"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:padding="3dp" />

    <ImageView
        android:id="@+id/iv"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:layout_below="@id/tv_time"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:src="@drawable/person2" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_time"
        android:layout_marginRight="10dp"
        android:layout_marginTop="5dp"
        android:layout_toRightOf="@id/iv"
        android:background="@drawable/left"
        android:gravity="center"
        android:padding="10dp" />

</RelativeLayout>

(3)创建名为rightitem.xml的layout,在ListView中对应用户item:一个TextView(作用:显示时间)、ImageView(作用:显示头像)和TextView(作用:显示对话内容)。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/tv_time"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:padding="3dp" />

    <ImageView
        android:id="@+id/iv"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentRight="true"
        android:layout_below="@id/tv_time"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:src="@drawable/person3" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_time"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="5dp"
        android:layout_toLeftOf="@id/iv"
        android:background="@drawable/right"
        android:gravity="center"
        android:padding="12dp" />

</RelativeLayout>

(4)适配器完整代码。
//TextAdapter.java

public class TextAdapter extends BaseAdapter {// /继承BaseAdapter,实现方法

    private List<ListData> lists;// 集合的数据内容
    private Context mContext;// 承接上下文的Context

    private RelativeLayout layout;

    public TextAdapter(List<ListData> lists, Context mContext) {
        this.lists = lists;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {// 返回lists所承载的条数
        return lists.size();
    }

    @Override
    public Object getItem(int position) {
        return lists.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {// convertView表示要加载的view,在本例子中有两个view要加载的,一是机器人说话,二是用户说话,分别对应leftitem和rightitem
        LayoutInflater inflater = LayoutInflater.from(mContext);
        if (lists.get(position).getFlag() == ListData.RECEIVE) {
            layout = (RelativeLayout) inflater.inflate(R.layout.leftitem, null);
        }
        if (lists.get(position).getFlag() == ListData.SEND) {
            layout = (RelativeLayout) inflater
                    .inflate(R.layout.rightitem, null);
        }
        TextView tv = (TextView) layout.findViewById(R.id.tv);// 对话textView
        TextView tv_time = (TextView) layout.findViewById(R.id.tv_time);// 时间textView
        tv.setText(lists.get(position).getContent()); // 将数据内容放进TextView中
        tv_time.setText(lists.get(position).getTime());// 将事件写进TextView
        return layout;
    }
}

3)修改MainActivity.java:设置发送Button的监听事件、将ListView与adapter绑定。代码入下。

public class MainActivity extends Activity implements HttpGetDataListener,
        OnClickListener {

    private HttpData httpData;
    private List<ListData> lists;
    private ListView lv;
    private EditText et_sendText;
    private Button btn_send;
    private TextAdapter adapter;
    private double currentTime, oldTime = 0;// 对话时间
    private String content_str; // 存储在EditText获取到的数据

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    /**
     * 实例化方法
     */
    public void initView() {
        lists = new ArrayList<ListData>();
        lv = (ListView) findViewById(R.id.lv);
        et_sendText = (EditText) findViewById(R.id.et_sendText);
        btn_send = (Button) findViewById(R.id.btn_send);
        btn_send.setOnClickListener(this);
        adapter = new TextAdapter(lists, this);
        lv.setAdapter(adapter);// 绑定adapter
    }

    /**
     * 设置时间
     * 
     * @return
     */
    private String getTime() {
        currentTime = System.currentTimeMillis();
        SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日   HH:mm:ss");
        Date curDate = new Date();
        String str = format.format(curDate);
        if (currentTime - oldTime >= 5 * 60 * 1000) {// 如果超过5分钟,显示时间
            oldTime = currentTime;
            return str;
        } else {
            return "";
        }
    }

    /**
     * 实现HttpGetDataListener接口的抽象方法,获取到HttpData得到的数据
     */
    @Override
    public void getDataUrl(String data) {
        System.out.println(data);
        parseText(data);
    }

    /**
     * 解析json、封装数据
     * 
     * @param data
     */
    public void parseText(String data) {
        System.out.println("data======" + data);
        try {
            JSONObject jb = new JSONObject(data);
            ListData listData;
            listData = new ListData(jb.getString("text"), ListData.RECEIVE,
                    getTime());// 封装数据
            lists.add(listData);
            adapter.notifyDataSetChanged();// 重新適配
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onClick(View v) {
        content_str = et_sendText.getText().toString();// 获取EditText內容
        et_sendText.setText("");
        String dropk = content_str.replace(" ", "");// 去掉空格
        String droph = dropk.replace("\\n", "");// 去掉回车
        ListData listData;
        listData = new ListData(content_str, ListData.SEND, getTime());
        lists.add(listData);
        adapter.notifyDataSetChanged();// 刷新
        httpData = (HttpData) new HttpData(
                "http://www.tuling123.com/openapi/api?key=XXXXX&info=北京",
                this).execute();// 发送已经去掉空格和回车content_str的数据droph
                                // ;execute()启动异步通信
    }
}

4)点9图片处理,作用是处理聊天的对话框,让对话框背景图随对话内容适当拉升,使得界面更美观大方,本例子用模仿的是QQ气泡。点9图片的处理工具:打开sdk/tools/draw9patch.bat,就可以选择图片来处理了。
5)添加欢迎语。
(1)在string.xml中添加string-array。代码如下。

<!-- 添加欢迎语 -->
    <string-array name="welcome_tips">
        <item>主人,您好!O(∩_∩)O</item>
        <item>亲,你回来啦~</item>
        <item>Welcome!!</item>
        <item>呵呵,你来啦~</item>
        <item>Hi, long time no see !</item>
    </string-array>

(2)在MainActivity.java中添加欢迎语方法。

public String getRandomWelcomeTips() {
        String welcome_tip = null;
        welcome_arry = this.getResources().getStringArray(R.array.welcome_tips);// 从string.xml中获取名为welcome_tips的字符串数组
        int index = (int) (Math.random() * (welcome_arry.length - 1));// 获取一个随机数
        welcome_tip = welcome_arry[index];
        return welcome_tip;
    }

6)移除界面过多的信息,比如对话信息超过30条,就只显示最近的30条对话。在MainActivity.java中添加相关代码,如下。

if (lists.size() > 30) {// 如果屏幕上的对话数据多于30,则移除前面的数据
            for (int i = 0; i < lists.size(); i++) {
                lists.remove(i);
            }
        }

6、运行、调试、完善、重构、总结。

以上是关于Android--智能机器人聊天的主要内容,如果未能解决你的问题,请参考以下文章

16行代码实现微信聊天机器人,自动智能回复,打团了让它来陪老婆聊天

16行代码实现微信聊天机器人,自动智能回复,打团了让它来陪女朋友聊天!

用 AIML 开发人工智能聊天机器人

小程序智能聊天机器人

ChatGPT简单了解下智能聊天机器人的功能和示例代码

Python成长之路从零学GUI -- 制作智能聊天机器人