Android第十八期 - 智能机器人
这回比较复杂,所以就一步步的教学弟们怎么写出来一个可以和你聊天的智能机器人Android版。
首先我们找一个第三方的api接口,我选择的是图灵机器人,地址是http://www.tuling123.com/openapi/, 如图:
然后我们挑一个做一个demo - 一问一答的例子:
那么调用的方式url = http://www.tuling123.com/openapi/api?key=ad5f0729523118c422f47e4dba0cf4c6&info=从西直门到东直门怎么走
在地址栏查看返回的json如图:
布局文件分别是main.xml,left.xml,right.xml,首先要说明的是main.xml:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<
ListView
android:id
=
"@+id/listview"
android:layout_width
=
"fill_parent"
android:layout_height
=
"0dip"
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/ed"
android:layout_width
=
"0dip"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
/>
<
Button
android:id
=
"@+id/seach"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/send1"
/>
</
LinearLayout
>
|
接下来是给listview的item的xml,首先是left.xml,用户显示在左边的对话部分:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<?
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"
android:orientation
=
"vertical"
>
<
TextView
android:id
=
"@+id/time"
android:layout_width
=
"fill_parent"
android:layout_height
=
"wrap_content"
android:gravity
=
"center_horizontal"
android:paddingTop
=
"5dip"
/>
<
RelativeLayout
android:layout_width
=
"fill_parent"
android:layout_height
=
"wrap_content"
android:layout_below
=
"@+id/time"
android:padding
=
"5dip"
>
<
ImageView
android:id
=
"@+id/iv"
android:layout_width
=
"60dp"
android:layout_height
=
"60dp"
android:src
=
"@drawable/right_icon"
/>
<
TextView
android:id
=
"@+id/tv"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginRight
=
"50dip"
android:layout_marginTop
=
"10dip"
android:layout_toRightOf
=
"@+id/iv"
android:background
=
"@drawable/left"
android:gravity
=
"center"
android:textColor
=
"#000000"
android:text
=
"测试"
/>
</
RelativeLayout
>
</
RelativeLayout
>
|
然后是right.xml,显示右边的回答部分:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<?
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"
android:orientation
=
"vertical"
>
<
TextView
android:id
=
"@+id/time"
android:layout_width
=
"fill_parent"
android:layout_height
=
"wrap_content"
android:gravity
=
"center_horizontal"
android:paddingTop
=
"5dip"
/>
<
RelativeLayout
android:layout_width
=
"fill_parent"
android:layout_height
=
"wrap_content"
android:layout_below
=
"@+id/time"
android:padding
=
"5dip"
>
<
ImageView
android:id
=
"@+id/iv"
android:layout_width
=
"60dp"
android:layout_height
=
"60dp"
android:layout_alignParentRight
=
"true"
android:src
=
"@drawable/left_icon"
/>
<
TextView
android:id
=
"@+id/tv"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginLeft
=
"50dip"
android:layout_marginTop
=
"10dip"
android:layout_toLeftOf
=
"@+id/iv"
android:background
=
"@drawable/right"
android:gravity
=
"center"
android:text
=
"测试"
android:textColor
=
"#000000"
/>
</
RelativeLayout
>
</
RelativeLayout
>
|
效果图如下:
然后是主窗体的效果图,如下显示:
接着就是代码部分:我给大家解析一下:
思路是这样的,你要实例化一个用于调用listviewData的方法类,用来对listview中的item进行操作和修改:
ListData.java:其中flag做为用于显示左右区别的标识,SEND为右边,RECEIVE为左边,time做为显示当前消息的时间记录
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package
com.xiaosan;
public
class
ListData {
private
String content;
public
static
final
int
SEND =
1
;
public
static
final
int
RECEIVE =
2
;
private
int
flag;
private
String time;
public
int
getFlag() {
return
flag;
}
public
void
setFlag(
int
flag) {
this
.flag = flag;
}
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
String getTime() {
return
time;
}
public
void
setTime(String time) {
this
.time = time;
}
}
|
接下来是给listview写一个适配器TextAdapter.java来适配listview中的item,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
package
com.xiaosan;
import
java.util.List;
import
net.sourceforge.simcpux.R;
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
TextAdapter
extends
BaseAdapter {
private
List<ListData> lists;
private
Context context;
private
RelativeLayout Rlayout;
public
TextAdapter(List<ListData> lists, Context context) {
this
.lists = lists;
this
.context = context;
}
@Override
public
int
getCount() {
// TODO Auto-generated method stub
return
lists.size();
}
@Override
public
Object getItem(
int
position) {
// TODO Auto-generated method stub
return
lists.get(position);
}
@Override
public
long
getItemId(
int
position) {
// TODO Auto-generated method stub
return
position;
}
@Override
public
View getView(
int
position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
if
(lists.get(position).getFlag() == ListData.RECEIVE) {
Rlayout = (RelativeLayout) inflater
.inflate(R.layout.leftitem,
null
);
}
if
(lists.get(position).getFlag() == ListData.SEND) {
Rlayout = (RelativeLayout) inflater.inflate(R.layout.rightitem,
null
);
}
TextView tv = (TextView) Rlayout.findViewById(R.id.tv);
TextView time = (TextView) Rlayout.findViewById(R.id.time);
time.setText(lists.get(position).getTime());
tv.setText(lists.get(position).getContent());
return
Rlayout;
}
}
|
然后接着写一个监听事件的接口类,声明方法用来调用异步加载部分的传值,HttpGetDataListener.java,代码如下:
|
1
2
3
4
5
|
package
com.xiaosan;
public
interface
HttpGetDataListener {
void
getDataUrl(String data);
}
|
接着是定义一个异步加载的方法用来加载listview中的数据,HttpData.java,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
package
com.xiaosan;
import
java.io.BufferedReader;
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.InputStreamReader;
import
org.apache.http.HttpEntity;
import
org.apache.http.HttpResponse;
import
org.apache.http.client.ClientProtocolException;
import
org.apache.http.client.HttpClient;
import
org.apache.http.client.methods.HttpGet;
import
org.apache.http.impl.client.DefaultHttpClient;
import
android.os.AsyncTask;
public
class
HttpData
extends
AsyncTask<String, Void, String> {
private
HttpClient nhttHttpClient;
private
HttpGet nHttpGet;
private
HttpResponse nHttpResponse;
private
HttpEntity nhttHttpEntity;
private
InputStream in;
private
String url;
private
HttpGetDataListener listener;
public
HttpData(String url, HttpGetDataListener listener) {
this
.url = url;
this
.listener = listener;
}
@Override
protected
String doInBackground(String... arg0) {
try
{
nhttHttpClient =
new
DefaultHttpClient();
nHttpGet =
new
HttpGet(url);
nHttpResponse = nhttHttpClient.execute(nHttpGet);
nhttHttpEntity = nHttpResponse.getEntity();
in = nhttHttpEntity.getContent();
BufferedReader br =
new
BufferedReader(
new
InputStreamReader(in));
String line =
null
;
StringBuffer sb =
new
StringBuffer();
while
((line = br.readLine()) !=
null
) {
sb.append(line);
}
return
sb.toString();
}
catch
(ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch
(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return
null
;
}
@Override
protected
void
onPostExecute(String result) {
listener.getDataUrl(result);
super
.onPostExecute(result);
}
}
|
最后获得result就是json返回的String类型的内容部分。
接着我们继续看MainActivity.java是怎么写的,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
package
com.xiaosan;
import
java.text.SimpleDateFormat;
import
java.util.ArrayList;
import
java.util.Date;
import
java.util.List;
import
net.sourceforge.simcpux.Constants;
import
net.sourceforge.simcpux.R;
import
net.sourceforge.simcpux.uikit.MMAlert;
import
org.json.JSONException;
import
org.json.JSONObject;
import
android.app.Activity;
import
android.content.DialogInterface;
import
android.os.Bundle;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
import
android.widget.CheckBox;
import
android.widget.EditText;
import
android.widget.LinearLayout;
import
android.widget.ListView;
import
android.widget.TextView;
import
android.widget.Toast;
import
com.tencent.mm.sdk.openapi.IWXAPI;
import
com.tencent.mm.sdk.openapi.SendMessageToWX;
import
com.tencent.mm.sdk.openapi.WXAPIFactory;
import
com.tencent.mm.sdk.openapi.WXMediaMessage;
import
com.tencent.mm.sdk.openapi.WXTextObject;
public
class
MainActivity
extends
Activity
implements
HttpGetDataListener,
OnClickListener {
private
HttpData httpData;
private
TextView code;
private
TextView text;
private
EditText et;
private
Button btn;
private
List<ListData> lists;
private
ListView lv;
private
String str;
private
TextAdapter adapter;
private
String[] welcome_array;
private
double
currentTime, oldTime =
0
;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
initview();
}
public
void
initview() {
et = (EditText) findViewById(R.id.ed);
btn = (Button) findViewById(R.id.seach);
btn.setOnClickListener(
this
);
lv = (ListView) findViewById(R.id.listview);
lists =
new
ArrayList<ListData>();
adapter =
new
TextAdapter(lists,
this
);
lv.setAdapter(adapter);
ListData listData;
listData =
new
ListData(getRandomWelcomeTips(), ListData.RECEIVE,
getTime());
lists.add(listData);
}
@Override
public
void
onClick(View v) {
// getTime();
if
(v == btn) {
str = et.getText().toString();
// 去掉空格和回车部分
String a = str.replace(
" "
,
""
);
String b = a.replace(
"\n"
,
""
);
et.setText(
""
);
ListData listData;
listData =
new
ListData(str, ListData.SEND, getTime());
lists.add(listData);
// 移除多余的字部分
if
(lists.size() >
30
) {
for
(
int
i =
0
; i < lists.size(); i++) {
lists.remove(i);
}
}
adapter.notifyDataSetChanged();
httpData = (HttpData)
new
HttpData(
"http://www.tuling123.com/openapi/api?key=ad5f0729523118c422f47e4dba0cf4c6&info="
+ b,
this
).execute();
}
}
@Override
public
void
getDataUrl(String data) {
// Toast.makeText(MainActivity.this, data, Toast.LENGTH_LONG).show();
// System.err.println(data);
text(data);
}
public
void
text(String data) {
try
{
JSONObject jb =
new
JSONObject(data);
// code.setText(jb.getString("code"));
// text.setText(jb.getString("text"));
ListData listData;
listData =
new
ListData(jb.getString(
"text"
), ListData.RECEIVE,
getTime());
lists.add(listData);
adapter.notifyDataSetChanged();
}
catch
(JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 欢迎语部分
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
""
;
}
}
}
|
我们来分析一下这段代码,要先implement HttpGetDataListener, onClickListener,然后声明所需的对象:
|
1
2
3
4
5
6
7
8
9
10
11
|
private
HttpData httpData;
private
TextView code;
private
TextView text;
private
EditText et;
private
Button btn;
private
List<ListData> lists;
private
ListView lv;
private
String str;
private
TextAdapter adapter;
private
String[] welcome_array;
private
double
currentTime, oldTime =
0
;
|
注明的是welcome_array是保存进入程序的欢迎语数组集合,double的currentTime和oldYime是记录时间变化的用以判断间隔多久将对话的item归为一个时间段内的变量。
接着看简单的两个public方法:getRandomWelcomeTips()//欢迎语部分,getTime()//时间部分返回的都是String类型。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// 欢迎语部分
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
""
;
}
}
|
需要注意的是欢迎语里面我用的是random随机给index来寻找value目录下的strings.xml里面的string-array中的item,如下代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
<
string-array
name
=
"welcome_tips"
>
<
item
>主人,奴婢梁小三在此等候您多时了(*^__^*)</
item
>
<
item
>主人,奴婢梁小三为你服务( # ▽ # )</
item
>
<
item
>主人,最近可好(┬_┬)</
item
>
<
item
>主人,奴婢梁小三想你(ˇ?ˇ) </
item
>
<
item
>欢迎回来,我亲爱的主人</
item
>
<
item
>主人,你有时候很凶的〒_〒</
item
>
<
item
>主人,我想抱抱你么~</
item
>
<
item
>主人,中午吃什么了?</
item
>
<
item
>主人,晚上要好好睡觉,别玩我了--!</
item
>
<
item
>主人,梁小三特别喜欢你,听到ta的呼喊了嘛。。</
item
>
</
string-array
>
|
这里我们也可以getResources()一个url去读取服务器上的xml,就可以实现实时的控制欢迎语的内容显示了,大家可以自己试试,我在这里就不说了。
接下来的就是请求url来异步加载listview中的数据了:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@Override
public
void
getDataUrl(String data) {
// Toast.makeText(MainActivity.this, data, Toast.LENGTH_LONG).show();
// System.err.println(data);
text(data);
}
public
void
text(String data) {
try
{
JSONObject jb =
new
JSONObject(data);
// code.setText(jb.getString("code"));
// text.setText(jb.getString("text"));
ListData listData;
listData =
new
ListData(jb.getString(
"text"
), ListData.RECEIVE,
getTime());
lists.add(listData);
adapter.notifyDataSetChanged();
}
catch
(JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
|
注意的是这地方是触发到button事件才会有数据回传值得,也就是说在欢迎语之前是没有进行异步加载的操作的。
欢迎语的操作如下代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
void
initview() {
et = (EditText) findViewById(R.id.ed);
btn = (Button) findViewById(R.id.seach);
btn.setOnClickListener(
this
);
lv = (ListView) findViewById(R.id.listview);
lists =
new
ArrayList<ListData>();
adapter =
new
TextAdapter(lists,
this
);
lv.setAdapter(adapter);
ListData listData;
listData =
new
ListData(getRandomWelcomeTips(), ListData.RECEIVE,
getTime());
lists.add(listData);
}
|
注意的是里面的ListData的实例化把三个参数都传值进去后,加载到lists这个ArrayList的数据组存放,再通过真正的listview去设置适配器然后显示到listview中。
最后是button事件的解析:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
str = et.getText().toString();
// 去掉空格和回车部分
String a = str.replace(
" "
,
""
);
String b = a.replace(
"\n"
,
""
);
et.setText(
""
);
ListData listData;
listData =
new
ListData(str, ListData.SEND, getTime());
lists.add(listData);
// 移除多余的字部分
if
(lists.size() >
30
) {
for
(
int
i =
0
; i < lists.size(); i++) {
lists.remove(i);
}
}
adapter.notifyDataSetChanged();
httpData = (HttpData)
new
HttpData(
"http://www.tuling123.com/openapi/api?key=ad5f0729523118c422f47e4dba0cf4c6&info="
+ b,
this
).execute();
|
注意的是这里面有一个edittext你输入后把String传入到str中药做一个过滤,因为api中是不认字符夹杂""和"\n"换行的,过滤后的String的b就是想要的,我们把它传入ListData中的方法中,并加入到arraylist中,显示出来,并且设置超过多少条数据后自动去掉的方法,然后notifyDataSetChanged这个TextAdapter,最后异步加载请求HttpData,得到数据,显示出来,至此完成整个操作。
不会的可以问我,应该能看的懂吧--!最后的效果图和源码如下:
你也可以去360手机助手去下载 - 梁小三 ,谢谢大家!国庆节快乐!
![V{YU9~0]8Y0GMDECX{0A(LJ.jpg wKioL1QqR1jj8vfWAAS3z9RpmOg568.jpg](http://s3.51cto.com/wyfs02/M02/4B/5D/wKioL1QqR1jj8vfWAAS3z9RpmOg568.jpg)



![QA]TPJ9(Y}C8(0LY8ZMWDTM.png wKioL1QqS4LRoHkrAADWJLm3sT4664.jpg](http://s3.51cto.com/wyfs02/M02/4B/5E/wKioL1QqS4LRoHkrAADWJLm3sT4664.jpg)
![R}90ULBI142VFW0Y3T6])K7.jpg wKiom1QqS--DaGXCAACiu5BCIk0058.jpg](http://s3.51cto.com/wyfs02/M02/4B/5B/wKiom1QqS--DaGXCAACiu5BCIk0058.jpg)




