zoukankan      html  css  js  c++  java
  • 练手的小项目(1)——智能聊天机器人

    我一直坚信。即使是一个简单APP,他也有难度,假设一个复杂APP你可以这样做。这当然不是一个坚实的基础,你,我总是问我身边的人。为什么要学习安卓忘记,总是学不好。有些事情要记住,事实上这不能怪你。假设别人开发了那么久的东西,你一下子就学会了,你让谷歌怎么活。


    篇幅有限。假设读者看不懂的话,能够复习下基础。我尽量将代码简单化了。  先看效果图

    假设你是初学安卓。这个APP你可能要半小时

    假设你是有经验的开发人员,OK,你可能看一遍就能将自己的开发类带入,10分钟不到就搞定。



    开发步骤:

    1. 先去图灵机器人注冊KEY

    http://www.tuling123.com/

    2.准备好联网操作,将联网工具类放入

    PS:这里是我自己的联网工具类。假设喜欢能够收藏

    3.准备json解析

    json解析并不复杂,所以仅仅是用了自带json解析了

    4.UI准备


    5.业务逻辑准备




    第一步 你先去 图灵机器人的官网申请key 这个不复杂,由于能够QQ登录 假设不想申请 那就用我的呗


    key = 349baa5d2bd5d2d7612e4f2c1fcd973d   


    第二步  联网获取json 


    事实上这个请求数据。没什么差别的,看看他的请求演示样例

    private String url="http://www.tuling123.com/openapi/api?

    key=349baa5d2bd5d2d7612e4f2c1fcd973d&info=";


    后面增加你的输入的信息 就可以 

    联网:1.Httpclient  2. Httpconnection 3.Xutils 4.各种工具类。


    一个开发人员。随着开发的东西越来越来多。积累的工具也越来越多。在这个小Demo 里 你能够使用自己的工具类 

    我的联网工具类,是自己封装的  你能够在自带增加线程,用的是Httpconnection联网,然后依据IO操作 转成String  通过接口放回String类型。


    package com.example.AiComputer;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    import java.nio.ByteOrder;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Handler;
    
    /**
     * 封装的 网络 + 线程
     */
    public class HttpUtils {
    
    	// 使用线程池来下载图片。同一时刻。最多有3个线程在执行
    	private static ExecutorService execuotrs = Executors.newFixedThreadPool(3);
    
    	interface OnBitmapNetWorkResponse {
    		public void ok(Bitmap bitmap);
    
    		public void error(String error);
    	}
    
    	public static void RequestBitmapNetWork(final String path,
    			final OnBitmapNetWorkResponse response) {
    		
    		final Handler handler = new Handler();
    
    		execuotrs.execute(new Runnable() {
    			@Override
    			public void run() {
    				boolean isNetWorkOK = false;
    				try {
    					URL url = new URL(path);
    					HttpURLConnection openConnection = (HttpURLConnection) url
    							.openConnection();
    					openConnection.setConnectTimeout(5000);
    					openConnection.connect();
    					if (openConnection.getResponseCode() == 200) {
    						InputStream inputStream = openConnection
    								.getInputStream();
    						final Bitmap bitmap = BitmapFactory
    								.decodeStream(inputStream);
    
    						handler.post(new Runnable() {
    
    							@Override
    							public void run() {
    								response.ok(bitmap);
    							}
    						});
    
    						inputStream.close();
    						isNetWorkOK = true;
    					}
    
    				} catch (MalformedURLException e) {
    					e.printStackTrace();
    				} catch (IOException e) {
    					e.printStackTrace();
    				} finally {
    					if (!isNetWorkOK) {
    						handler.post(new Runnable() {
    
    							@Override
    							public void run() {
    								response.error("server不在服务区内!

    "); } }); } } } }); } public interface OnNetWorkResponse { public void ok(String response); public void error(String error); } public static void RequestNetWork(final String path, final OnNetWorkResponse response) { //实例化handler final Handler hanlder = new Handler(); new Thread() { public void run() { //标志位 boolean isWorkOK = false; InputStream inputStream = null; ByteArrayOutputStream outStream = null; try { URL url = new URL(path); System.out.println("=======path========="+path); HttpURLConnection connection = (HttpURLConnection) url .openConnection(); connection.setConnectTimeout(5000); connection.setDoInput(true); connection.connect(); if (connection.getResponseCode() == 200) { inputStream = connection.getInputStream(); outStream = new ByteArrayOutputStream(); byte[] b = new byte[1024]; int len = 0; while ((len = inputStream.read(b)) != -1) { outStream.write(b, 0, len); } outStream.flush(); final String result = new String( outStream.toByteArray()); hanlder.post(new Runnable() { @Override public void run() { response.ok(result); } }); isWorkOK = true; } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 网络操作出问题 if (!isWorkOK) { response.error("server走神拉!

    "); } if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (outStream != null) { try { outStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }; }.start(); } }


     假设对于这一节。不懂的能够看下 我写的 网络编程系列

    从java网络编程学起(2)     


    第三步,就是json 解析 

    我们在url后面增加 深圳的天气   返回的是

    {"code":100000,"text":"今天多云 24~19°C明天阴 26~21°C后天阴 22~17°C"}

    最外层是一个大括号,so 直接用JsonObject,解析就可以 

    JSONObject jb = new JSONObject(response);

    4.UI准备 

    事实上对于ui  并不复杂。  最外层是一个 线性布局。里面是 两个线性布局,第一个装着listview ----->显示聊天信息  第二个 装着 一个button 发送消息 一个Edittext 输入信息

    布局文件:activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <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:orientation="horizontal" >
    
            <EditText
                android:id="@+id/sendText"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />
            
            <Button 
                android:id="@+id/send_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="发送"
                />
        </LinearLayout>
    
    </LinearLayout>


    既然说道了listview  就知道我们的聊天信息。要在上面显示。我们要在适配器中 推断是那个发送的消息,进行推断是哪个发送过来的 显示那部分布局 。左边的是机器人的消息布局  右边是 我们发送消息的布局 

     也不复杂, 一个相对布局中有一个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="match_parent" > <TextView android:id="@+id/time" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" /> <ImageView android:id="@+id/iv" android:layout_width="70dp" android:layout_height="70dp" android:layout_below="@id/time" android:padding="10dp" android:src="@drawable/robot" /> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/time" android:layout_marginRight="50dp" android:layout_toRightOf="@id/iv" android:background="@drawable/aio_friend_bg_nor_11" android:gravity="center" /> </RelativeLayout>


    我们发送消息的内容 

    <?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="match_parent" > <TextView android:id="@+id/time" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" /> <ImageView android:id="@+id/iv" android:layout_width="70dp" android:layout_height="70dp" android:layout_alignParentRight="true" android:layout_below="@id/time" android:padding="10dp" android:src="@drawable/xiaoxin" /> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/time" android:layout_marginLeft="50dp" android:layout_toLeftOf="@id/iv" android:background="@drawable/aio_user_bg_nor_11" android:gravity="center" /> </RelativeLayout>



    不知不觉,就走到了最后一步,相信 你一定会认为,好简单呀。是的非常easy,由于最难的在后面

    业务逻辑 :

    1.Edittext 和listview 和button的实例化

    2.button点击事件的处理 

    获取 Edittext输入的内容,进行处理————>去掉空格和回车的信息。替代成空 。  然后将数据封装到实体类中去。

    当大于30条的时候清空一次 然后刷新一下适配器

    将处理好的信息 发送到server 获取 回复的信息 然后也封装进行实体类。刷新一下适配器


    3. 设置欢迎语言,每一次进来。为了提高用户体验,我们进行欢迎语出现, 先建立一个数组  用来装 欢迎语


    来到res/values/Strings 增加数组

       <string-array name="welcome_tips">
            <item>主人,奴婢在此等候多时了</item>
            <item>主人。近来一切可好</item>
            <item>亲爱的,我想死你了</item>
            <item>欢迎归来,我亲爱的主人</item>
            <item>我是小新机器人,非常高兴为您服务</item>
        </string-array>

    然后再 java 代码中如一个方法

    	private String getRandomWelcomeTips() {
    		String welcome_tip = null;
    		welcome_array = this.getResources()
    				.getStringArray(R.array.welcome_tips);
    		int index = (int) (Math.random() * (welcome_array.length - 1));
    		welcome_tip = welcome_array[index];
    		return welcome_tip;
    	}

    应该不难看懂 通过随机 得到数组内容 

    当中聊天嘛。应该把时间也增加

    	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 >= 500) {
    			oldTime = currentTime;
    			return str;
    		} else {
    			return "";
    		}
    
    	}
    也就是获取了下 系统时间,然后格式化了下   

    Java代码 MainActivity

    package com.example.AiComputer;
    
    
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import com.example.AiComputer.HttpUtils.OnNetWorkResponse;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ListView;
    
    public class MainActivity extends Activity implements OnClickListener{
    	//输入框
    	private EditText sendtext;
    	private Button send_btn;
        private ListView listView;
        private String content_str;
    	private String[] welcome_array;
    	private String url="http://www.tuling123.com/openapi/api?

    key=349baa5d2bd5d2d7612e4f2c1fcd973d&info="; private double currentTime=0, oldTime = 0; private List<ListData> lists; private ListData listData; private MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { listView = (ListView) findViewById(R.id.lv); sendtext = (EditText) findViewById(R.id.sendText); send_btn = (Button) findViewById(R.id.send_btn); lists = new ArrayList<ListData>(); //发送的点击事件 send_btn.setOnClickListener(this); adapter = new MyAdapter(lists, this); listView.setAdapter(adapter); listData = new ListData(getRandomWelcomeTips(), ListData.RECEIVER, getTime()); lists.add(listData); } private String getRandomWelcomeTips() { String welcome_tip = null; welcome_array = this.getResources() .getStringArray(R.array.welcome_tips); int index = (int) (Math.random() * (welcome_array.length - 1)); welcome_tip = welcome_array[index]; return welcome_tip; } /*1.获取 Edittext输入的内容,进行处理————>去掉空格和回车的信息,替代成空 。

    * 2.然后将数据封装到实体类中去。 当大于30条的时候清空一次 然后刷新一下适配器 * */ @Override public void onClick(View v) { getTime(); content_str = sendtext.getText().toString(); sendtext.setText(""); String dropk = content_str.replace(" ", ""); String droph = dropk.replace(" ", ""); listData = new ListData(content_str, ListData.SEND, getTime()); lists.add(listData); if (lists.size() > 30) { for (int i = 0; i < lists.size(); i++) { lists.remove(i); } } adapter.notifyDataSetChanged(); HttpUtils.RequestNetWork(url+droph, new OnNetWorkResponse() { @Override public void ok(String response) { try { JSONObject jb = new JSONObject(response); // System.out.println(jb.getString("code")); // System.out.println(jb.getString("text")); ListData listData; listData = new ListData(jb.getString("text"), ListData.RECEIVER, getTime()); lists.add(listData); adapter.notifyDataSetChanged(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void error(String error) { // TODO Auto-generated method stub } }); } 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 >= 500) { oldTime = currentTime; return str; } else { return ""; } } }

    事实上在没有点击的时候。欢迎语 已经通过适配器 显示到listview上面去了 所以我们能够放在adapter实例化以下  ,实体类。主要起的作用就是将 发送的时间和内容 封装好。在适配器中推断 进行展示

    事实上最重要的是 适配器的内容。应该怎么处理 发送过来的消息:

    我们向适配器 传了两个值集合。装满了实体类数据的集合 一个上下文 

     我们先建立一个相对布局。用来填充条目的内容  我们要想一个list装着实体类,实体类,有非常多数据 ,我们须要通过标识符来推断显示那部分内容。

    package com.example.AiComputer;
    
    import java.util.List;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    public class MyAdapter extends BaseAdapter{
    	
    	private List<ListData> lists;
    	private Context mContext;
    	private RelativeLayout layout;
    	
    	public MyAdapter(List<ListData> lists,Context mContext) {
    		
    		this.lists = lists;
    		this.mContext = mContext;
    	}
    	
    	@Override
    	public int getCount() {
    		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) {
    		LayoutInflater inflater = LayoutInflater.from(mContext);
    		if(lists.get(position).getFlag() == ListData.RECEIVER){
    			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 time = (TextView) layout.findViewById(R.id.time);
    		tv.setText(lists.get(position).getContent());
    		time.setText(lists.get(position).getTime());
    		return layout;
    	}
    
    }
    




    如有问题,能够在我博客上面留言


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    VMware虚拟机安装红帽系统无法上网解决办法(转)
    二维指针的malloc内存分配(转)
    c语言中如何通过二级指针来操作二维数组
    如何把一个二维数组的地址赋给一个二维指针?
    二维数组及二维指针的传递及一些思考(转)
    js怎么让时间函数的秒数在页面上显示是变化的
    jquery 实现各种统计图网址
    WEB的相关知识总结
    JS同名方法,
    web components思想如何应用于实际项目
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4888189.html
Copyright © 2011-2022 走看看