安卓智能聊天機器人開發(二)


接上一篇文章《安卓智能聊天機器人開發(一)》,晚上繼續寫。

在上一篇文章中,已經實現了對網絡數據的獲取和處理封裝,這篇文章來講下如何嵌入到安卓應用中。

先看下效果圖:

從上面兩張圖我們可以發現,這個聊天布局其實就是一個ListView,只不過它和傳統的ListView有些區別,因為它使用了多Item樣式布局

首先,先來分析下基礎布局:

這個界面是由3個布局文件組成,分別是主布局,發送消息樣式布局,接收消息樣式布局

先來看下主布局:

這里是對應的主布局代碼:

android:divider="@null"  --去除ListView的Item分割線

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:background="@drawable/chat_bg_default" >
 6 
 7     <LinearLayout
 8         android:id="@+id/title"
 9         android:layout_width="fill_parent"
10         android:layout_height="wrap_content"
11         android:layout_alignParentTop="true"
12         android:background="@drawable/title_bar"
13         android:gravity="center"
14         android:orientation="vertical" >
15 
16         <TextView
17             android:layout_width="wrap_content"
18             android:layout_height="fill_parent"
19             android:layout_gravity="center"
20             android:text="機器兔"
21             android:textColor="@android:color/white"
22             android:textSize="20sp" />
23     </LinearLayout>
24 
25     <RelativeLayout
26         android:id="@+id/bottom"
27         android:layout_width="fill_parent"
28         android:layout_height="55dp"
29         android:layout_alignParentBottom="true"
30         android:background="@drawable/bottom_bar"
31         android:padding="5dp" >
32 
33         <EditText
34             android:id="@+id/send_message"
35             android:layout_width="fill_parent"
36             android:layout_height="wrap_content"
37             android:layout_alignParentLeft="true"
38             android:layout_centerVertical="true"
39             android:layout_marginLeft="5dp"
40             android:layout_marginRight="5dp"
41             android:background="@drawable/login_edit_normal" />
42 
43         <Button
44             android:id="@+id/send_bt"
45             android:layout_width="wrap_content"
46             android:layout_height="fill_parent"
47             android:layout_alignParentRight="true"
48             android:layout_alignRight="@id/send_message"
49             android:background="@drawable/send_button_selector"
50             android:gravity="center_vertical"
51             android:text="發送" />
52     </RelativeLayout>
53 
54     <ListView
55         android:id="@+id/chatlistview"
56         android:layout_width="fill_parent"
57         android:layout_height="fill_parent"
58         android:layout_above="@id/bottom"
59         android:layout_below="@id/title"
60         android:divider="@null" >
61     </ListView>
62 
63 </RelativeLayout>

再來看下消息布局:(由於消息布局只是左右兩邊方向的不同,這里只給出其中一個)

這是2個消息布局的代碼:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical" >
 6 
 7     <TextView
 8           android:id="@+id/sendtime"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:layout_gravity="center"
12         android:background="#999999"
13         android:text="2014-11-07 18:00"
14         android:textColor="@android:color/white" />
15 
16     <LinearLayout
17         android:layout_width="match_parent"
18         android:layout_height="wrap_content"
19         android:orientation="horizontal" >
20 
21         <LinearLayout
22             android:layout_width="wrap_content"
23             android:layout_height="wrap_content"
24             android:orientation="vertical" >
25 
26             <!-- 頭像昵稱部分 -->
27 
28             <ImageView
29                 android:layout_width="50dp"
30                 android:layout_height="50dp"
31                 android:src="@drawable/icon1" />
32 
33             <TextView
34                 android:layout_width="wrap_content"
35                 android:layout_height="wrap_content"
36                 android:layout_gravity="center"
37                 android:text="機器兔" />
38         </LinearLayout>
39 
40         <TextView
41             android:id="@+id/sendmsg"
42             android:layout_width="wrap_content"
43             android:layout_height="wrap_content"
44             android:background="@drawable/chatfrom_bg_normal"
45             android:text="你好,我是機器兔。" />
46     </LinearLayout>
47 
48 </LinearLayout>
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical" >
 6 
 7     <TextView
 8         android:id="@+id/receivetime"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:layout_gravity="center"
12         android:background="#999999"
13         android:text="2014-11-07 18:00"
14         android:textColor="@android:color/white" />
15 
16     <LinearLayout
17         android:layout_width="fill_parent"
18         android:layout_height="wrap_content"
19         android:gravity="right"
20         android:orientation="horizontal" >
21 
22         <TextView
23             android:id="@+id/receivemsg"
24             android:layout_width="wrap_content"
25             android:layout_height="wrap_content"
26             android:background="@drawable/chatto_bg_normal"
27             android:text="你好,我是機器兔。"
28             android:textColor="@android:color/black" />
29 
30         <LinearLayout
31             android:layout_width="wrap_content"
32             android:layout_height="wrap_content"
33             android:orientation="vertical" >
34 
35             <!-- 頭像昵稱部分 -->
36 
37             <ImageView
38                 android:layout_width="50dp"
39                 android:layout_height="50dp"
40                 android:src="@drawable/icon" />
41 
42             <TextView
43                 android:layout_width="wrap_content"
44                 android:layout_height="wrap_content"
45                 android:layout_gravity="right"
46                 android:text="我" />
47         </LinearLayout>
48     </LinearLayout>
49 
50 </LinearLayout>

 

接下來看下關於ListView的自定義適配器,和往常一樣自定義適配器需要繼承BaseAdapter,並實現一些必須的方法

這里有個需要注意的是,因為傳統的ListView是統一一個樣式的,而這里的聊天布局是左右兩邊收發信息多Item樣式

所以需要額外的多覆寫2個方法:

1、getViewTypeCount  --返回樣式的種類數目

2、getItemViewType    --給定類型標示符,便於在回調函數getView時讓系統知道我們需要顯示的哪個樣式

代碼里還提到了ViewHolder,這個是優化ListView加載速度的一種方法,關於這個知識點我整理一篇筆記《安卓開發筆記——ListView加載性能優化ViewHolder

》出來,不熟悉的朋友可以看看。

  1 package com.example.androidchat;
  2 
  3 import java.text.SimpleDateFormat;
  4 import java.util.List;
  5 
  6 import com.example.pojo.Msg;
  7 import com.example.pojo.Msg.Type;
  8 
  9 import android.content.Context;
 10 import android.view.LayoutInflater;
 11 import android.view.View;
 12 import android.view.ViewGroup;
 13 import android.widget.BaseAdapter;
 14 import android.widget.TextView;
 15 /**
 16  * 
 17  * ListView適配器
 18  *
 19  */
 20 public class ChatAdapter extends BaseAdapter {
 21 
 22     private List<Msg> data;
 23     private LayoutInflater inflater;// 布局工廠,可以把res/layout的xml布局文件轉換成view對象
 24 
 25     public ChatAdapter(Context context, List<Msg> data) {
 26         inflater = LayoutInflater.from(context);
 27         this.data = data;
 28     }
 29 
 30     @Override
 31     public int getCount() {
 32         return data.size();
 33     }
 34 
 35     @Override
 36     public Object getItem(int position) {
 37         return data.get(position);
 38     }
 39 
 40     @Override
 41     public long getItemId(int position) {
 42         return position;
 43     }
 44 
 45     @Override
 46     public View getView(int position, View convertView, ViewGroup parent) {
 47         Msg message = data.get(position);
 48         ViewHolder viewHolder = null;
 49         if (convertView == null) {// 未加載布局文件對象
 50             // 可以通過getItemViewType所定義的標識來設定對應的item樣式
 51             if (getItemViewType(position) == 0) {// 接收信息
 52                 viewHolder = new ViewHolder();
 53                 convertView = inflater.inflate(R.layout.send_msg, null);
 54                 viewHolder.time = (TextView) convertView
 55                         .findViewById(R.id.receivetime);
 56                 viewHolder.msg = (TextView) convertView
 57                         .findViewById(R.id.receivemsg);
 58             } else {
 59                 viewHolder = new ViewHolder();
 60                 convertView = inflater.inflate(R.layout.receive_msg, null);
 61                 viewHolder.time = (TextView) convertView
 62                         .findViewById(R.id.sendtime);
 63                 viewHolder.msg = (TextView) convertView
 64                         .findViewById(R.id.sendmsg);
 65             }
 66             convertView.setTag(viewHolder);
 67         } else {// 已經存在布局文件對象
 68             viewHolder = (ViewHolder) convertView.getTag();
 69         }
 70 
 71         // 設置數據
 72         SimpleDateFormat dateFormat = new SimpleDateFormat(
 73                 "yyyy-MM-dd HH:mm:ss");
 74         viewHolder.time.setText(dateFormat.format(message.getTime()));
 75         viewHolder.msg.setText(message.getMsg());
 76         return convertView;
 77     }
 78 
 79     /**
 80      * 由於此處我們要返回2種ListView的Item樣式,需要再額外多覆寫2個方法 
 81      * (1)、getItemViewType(int position)給定類型標示符 
 82      * (2)、getViewTypeCount() 類型數量
 83      */
 84     @Override
 85     public int getItemViewType(int position) {
 86         Msg message = data.get(position);
 87         if (message.getType() == Type.INCOME) {
 88             return 0;// 如果消息類型為接收,則值為0
 89         }
 90         return 1;// 如果消息類型為發送,則值為1
 91     }
 92 
 93     @Override
 94     public int getViewTypeCount() {
 95         return 2;
 96     }
 97 
 98     private final class ViewHolder {
 99         TextView time;// 消息時間
100         TextView msg;// 消息內容
101     }
102 
103 }

 

然后就是主程序代碼了:

這里就沒什么好說的了,網絡數據獲取工具類包括ListView的適配器類在之前已經提過,這里就只剩下調用了。

注意點有3:

1、那就是在UI主線程里不能直接取獲取網絡數據,這里我們需要另開一個子線程去獲取,然后在通過Handler去更新UI界面。

2、當數據源發生更新的時候,需要在UI主線程去操作,而不是子線程,還有就是不應該去重新設置Adapter,只需要去調用Adapter的notifyDataSetChanged()就行。

3、記得設置下ListView的setSelection選項,便於焦點自動往下拉。

不在UI主線程里做耗時操作,會使得UI現成阻塞。不在子線程里去更新UI界面,會導致應用程序無響應。

 1 package com.example.androidchat;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Date;
 5 import java.util.List;
 6 
 7 import android.app.Activity;
 8 import android.os.Bundle;
 9 import android.os.Handler;
10 import android.os.Message;
11 import android.view.View;
12 import android.view.View.OnClickListener;
13 import android.widget.Button;
14 import android.widget.EditText;
15 import android.widget.ListView;
16 
17 import com.example.pojo.Msg;
18 import com.example.pojo.Msg.Type;
19 import com.example.utils.GetDataUtils;
20 
21 public class MainActivity extends Activity {
22 
23     
24     private ListView listview;
25     private EditText sendmsg;
26     private Button sendbt;
27     private ChatAdapter adapter;//ListView自定義適配器
28     private List<Msg> data;//數據源
29 
30     
31     private Handler handler=new Handler(){
32         public void handleMessage(Message msg) {
33                 Msg receiveMsg=(Msg) msg.obj;
34                 data.add(receiveMsg);
35                 adapter.notifyDataSetChanged();
36                 listview.setSelection(data.size()-1);//定位位置,自動下拉
37             
38         };
39     };
40     @Override
41     protected void onCreate(Bundle savedInstanceState) {
42         super.onCreate(savedInstanceState);
43         setContentView(R.layout.activity_main);
44         
45         initView();//初始化控件
46         initData();//初始化數據
47         initAction();//初始化事件
48     }
49 
50     private void initAction() {
51         this.sendbt.setOnClickListener(new OnClickListener() {
52             
53             @Override
54             public void onClick(View v) {
55                 /**
56                  * 點擊發送按鈕執行步驟
57                  * 1、獲取用戶輸入的內容並顯示到ListView(判斷是否為空)
58                  * 2、發送用戶輸入的內容到服務端獲取服務端返回內容並顯示到ListView(注意線程處理)
59                  * 3、清空輸入框
60                  */
61                 final String sendInfo=sendmsg.getText().toString();//獲取用戶輸入數據(用於發送)
62                 data.add(new Msg("",sendInfo,new Date(),Type.INCOME));
63                 adapter.notifyDataSetChanged();//更新數據源
64                 listview.setSelection(data.size()-1);//定位位置,自動下拉
65                 sendmsg.setText("");
66                 
67                 
68                 //向服務端發送信息並接收返回信息,由於UI主線程不能執行網絡獲取操作,這里需要開一個子線程
69                 new Thread(){
70 
71                     @Override
72                     public void run() {
73                         //執行網絡操作
74                         GetDataUtils dataUtils=new GetDataUtils();
75                         Msg msg=dataUtils.getInfo(sendInfo);//獲取到一個Msg對象,但由於子線程不能夠更新UI,所以需要用到一個Handler
76                         Message message=Message.obtain();
77                         message.obj=msg;//封裝信息
78                         handler.sendMessage(message);
79                     }
80                     
81                 }.start();
82             }
83         });
84     }
85 
86 private void initData() {
87         data=new ArrayList<Msg>();
88         adapter=new ChatAdapter(MainActivity.this,data);//獲取ListView適配器實例
89         listview.setAdapter(adapter);
90     }
91 
92     private void initView() {
93         this.listview=(ListView) MainActivity.this.findViewById(R.id.chatlistview);
94         this.sendmsg=(EditText) findViewById(R.id.send_message);
95         this.sendbt=(Button) findViewById(R.id.send_bt);
96     }
97 
98 
99 }

好了,到此"安卓智能聊天機器人”就已經完成了,雖說這個機器人有點二,不過在無聊之余還是可以打發打發時間的哈~

 

作者:Balla_兔子
出處:http://www.cnblogs.com/lichenwei/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,日后必有一番作為!旁邊有“推薦”二字,你就順手把它點了吧,相得准,我分文不收;相不准,你也好回來找我!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM