练手小项目(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("服务器不在服务区内!");
							}
						});

					}

				}

			}
		});
	}

	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("服务器走神拉!");
					}

					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>

不知不觉,就走到了最后一步,相信 你一定会觉得,好简单呀,是的很简单,因为最难的在后面

业务逻辑 :

1.Edittext 和listview 和button的实例化

2.button点击事件的处理

获取 Edittext输入的内容,进行处理————>去掉空格和回车的信息,替代成空 。  然后将数据封装到实体类中去。 当大于30条的时候清空一次 然后刷新一下适配器

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

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("\n", "");
		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;
	}

}

点击下载源码

如有问题,可以在我博客上面留言

时间: 2024-10-30 17:58:00

练手小项目(1)——智能聊天机器人的相关文章

练手的小项目(1)——智能聊天机器人

我一直坚信.即使是一个简单APP,他也有难度,假设一个复杂APP你可以这样做.这当然不是一个坚实的基础,你,我总是问我身边的人.为什么要学习安卓忘记,总是学不好.有些事情要记住,事实上这不能怪你.假设别人开发了那么久的东西,你一下子就学会了,你让谷歌怎么活. 篇幅有限.假设读者看不懂的话,能够复习下基础.我尽量将代码简单化了.  先看效果图 假设你是初学安卓.这个APP你可能要半小时 假设你是有经验的开发人员,OK,你可能看一遍就能将自己的开发类带入,10分钟不到就搞定. watermark/2

练手小项目(2)-生活小助手--周公解梦

第一篇 练手小项目(2)-生活小助手--身份证查询 第二篇 练手小项目(2)-生活小助手--星座运势查询 我在想就是第三个药品查询要不要写出来,因为布局还在讨论用什么展示,因为药品有很多展示,我也不知道用什么展示. 这是一个很纠结的事情 我就先写第四个吧 周公解梦 其中代码有点错误我想用for循环进行判断返回数据有几个 但是总是失败,如果有看本篇贴子,解决了,给我留个言,在这篇帖子我只显示一个结果 布局跟简单的说 一个Edittext 获取数据,然后button进行数据提取发送到服务器 返回的数

练手小项目(2)-生活小助手--星座运势查询

上一篇内容 练手小项目(2)-生活小助手 今天星期一.趁着中午的歇息时间把 第二个写出来 星座运势,近期看看极客学院 用聚合数据做了天气预报的视频教程,不好评价他.看他在后面的代码变更那么大,我就知道,后面肯定做不下去,于是.就改代码了.代码变更那么大,有几个人会去理解,还不如我自己写................ 先看布局 点击去就是一个spinner 用几个textview显示查询内容   布局有点丑,主要是给别人做功能,UI我就不考虑 关于UI  我还是要贴下代码.假设你有想法就把他美化

vue练手小项目--眼镜在线试戴

最近看到了一个眼镜在线试戴小项目使用纯js手写的,本人刚学习vue.js没多久,便试试用vue做做看了,还没完善. 其中包括初始图片加载,使用keywords查找,父子组件之间传递信息,子组件之间传递信息 1. 使用keywords查找 1.1 给每个li添加初始data smallImg: [ { keywords: "椭圆脸", src: "images/model_1.jpg", addClass: false }, { keywords: "圆形脸

java练手小项目!要想java学得好,练手项目不可少!

Java小项目,实现电影院的自动售票机 运行界面如下 2.类的设计 该系统中必须包括两个类,类名及属性方法设置如下. 电影类(Movie) ²  名称(name) ²  上映日期(date) ²  票价(price) 售票机类(TicketSell) ²  方法:查询所有电影信息  查询指定电影票价以及上映日期  购买电影票 3.具体要求及推荐实现步骤 1.创建电影类 2.创建售票机类 3.开发售票机类初始化电影方法,查询方法和买票方法. 1)初始化方法initial():  初始化5个电影对象

练手小项目(5)安全卫士——手机加速

不知不觉已经写到了第八篇了,手机卫士作为一个复习基础的项目,我基本也快做完了,如果大家继续看完的话,基本做东西有思路了. 怎么让手机加入加速呢,其实安卓系统是本身不会这么卡的,只因为国内软件太过流氓了,导致内存占用很大,所以手机加速 就说下内存清理 如果看过上一节的软件管理器,应该会很快学懂,因为布局都差不多,还是一个复杂的listview布局 本章涉及到知识点: 1.你猜 2.SP的使用 3.listview的复杂布局 OK ,我还是按照我写教程的思路,先看布局 ①.布局的编写 布局就和软件管

练手小项目(5)安全卫士_程序锁bug修复一

程序锁的基本功能,已经实现了,但是你如果输入密码进入 APP以后,看门狗,还是监听你想进入的APP,这时候又会出现一个输入密码的界面. 我先说一下思路. ①思路 1.通过发送自定义广播在服务里面,监控多一个判断如果是临时取消保护的程序就不再启动程序锁 ,这时候,我们要解决的就是什么时候再让他启动监听呢,答案就是 锁屏的时候. 2.通过锁屏将零时保护值设为空就可以继续保护了 但是bug 还是有 那就不停的安返回键 取消 输入密码界面,可以慢慢把界面内容看完,怎么解决呢 解决方案的是: 3. 如果在

练手小项目:利用pygame库编写飞机大战游戏

pygame库已经很久不更新,毕竟使用python开发游戏的不多.本项目的目的在于训练自己的pthon基本功.了解中小型程序框架以及学习代码重构等.项目出自<Python编程 从入门到实践>中12-14章节的例子.另外写的博客貌似也没人看啊,有点沮丧.不过还是要沉住气,就权当自己的私人技术日记了.或许以后能成为技术大牛呢,傻笑:) giyhub地址: 效果图如下: 程序框架 alien_invasion.py 包含运行游戏的run_game函数 alien.py 外星人类 bullet.py

Spring+Mybatis整合的练手小项目(一)项目部署

声明:教程是网上找的,代码是自己敲的 项目目录大致如下: 1. 首先创建Maven工程,在pom.xml中加入项目所需依赖: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"