接上一篇文章《安卓智能聊天機(jī)器人開(kāi)發(fā)(一)》,晚上繼續(xù)寫(xiě)。
在上一篇文章中,已經(jīng)實(shí)現(xiàn)了對(duì)網(wǎng)絡(luò)數(shù)據(jù)的獲取和處理封裝,這篇文章來(lái)講下如何嵌入到安卓應(yīng)用中。
先看下效果圖:
從上面兩張圖我們可以發(fā)現(xiàn),這個(gè)聊天布局其實(shí)就是一個(gè)ListView,只不過(guò)它和傳統(tǒng)的ListView有些區(qū)別,因?yàn)樗褂昧硕郔tem樣式布局
首先,先來(lái)分析下基礎(chǔ)布局:
這個(gè)界面是由3個(gè)布局文件組成,分別是主布局,發(fā)送消息樣式布局,接收消息樣式布局
先來(lái)看下主布局:
這里是對(duì)應(yīng)的主布局代碼:
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 <TextView17 android:layout_width="wrap_content"18 android:layout_height="fill_parent"19 android:layout_gravity="center"20 android:text="機(jī)器兔"21 android:textColor="@android:color/white"22 android:textSize="20sp" />23 </LinearLayout>24 25 <RelativeLayout26 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 <EditText34 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 <Button44 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="發(fā)送" />52 </RelativeLayout>53 54 <ListView55 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>
再來(lái)看下消息布局:(由于消息布局只是左右兩邊方向的不同,這里只給出其中一個(gè))
這是2個(gè)消息布局的代碼:
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 <LinearLayout17 android:layout_width="match_parent"18 android:layout_height="wrap_content"19 android:orientation="horizontal" >20 21 <LinearLayout22 android:layout_width="wrap_content"23 android:layout_height="wrap_content"24 android:orientation="vertical" >25 26 <!-- 頭像昵稱部分 -->27 28 <ImageView29 android:layout_width="50dp"30 android:layout_height="50dp"31 android:src="@drawable/icon1" />32 33 <TextView34 android:layout_width="wrap_content"35 android:layout_height="wrap_content"36 android:layout_gravity="center"37 android:text="機(jī)器兔" />38 </LinearLayout>39 40 <TextView41 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="你好,我是機(jī)器兔。" />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 <LinearLayout17 android:layout_width="fill_parent"18 android:layout_height="wrap_content"19 android:gravity="right"20 android:orientation="horizontal" >21 22 <TextView23 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="你好,我是機(jī)器兔。"28 android:textColor="@android:color/black" />29 30 <LinearLayout31 android:layout_width="wrap_content"32 android:layout_height="wrap_content"33 android:orientation="vertical" >34 35 <!-- 頭像昵稱部分 -->36 37 <ImageView38 android:layout_width="50dp"39 android:layout_height="50dp"40 android:src="@drawable/icon" />41 42 <TextView43 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>
接下來(lái)看下關(guān)于ListView的自定義適配器,和往常一樣自定義適配器需要繼承BaseAdapter,并實(shí)現(xiàn)一些必須的方法
這里有個(gè)需要注意的是,因?yàn)閭鹘y(tǒng)的ListView是統(tǒng)一一個(gè)樣式的,而這里的聊天布局是左右兩邊收發(fā)信息多Item樣式
所以需要額外的多覆寫(xiě)2個(gè)方法:
1、getViewTypeCount --返回樣式的種類數(shù)目
2、getItemViewType --給定類型標(biāo)示符,便于在回調(diào)函數(shù)getView時(shí)讓系統(tǒng)知道我們需要顯示的哪個(gè)樣式
代碼里還提到了ViewHolder,這個(gè)是優(yōu)化ListView加載速度的一種方法,關(guān)于這個(gè)知識(shí)點(diǎn)我整理一篇筆記《安卓開(kāi)發(fā)筆記——ListView加載性能優(yōu)化ViewHolder
》出來(lái),不熟悉的朋友可以看看。
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布局文件轉(zhuǎn)換成view對(duì)象 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) {// 未加載布局文件對(duì)象 50 // 可以通過(guò)getItemViewType所定義的標(biāo)識(shí)來(lái)設(shè)定對(duì)應(yīng)的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 {// 已經(jīng)存在布局文件對(duì)象 68 viewHolder = (ViewHolder) convertView.getTag(); 69 } 70 71 // 設(shè)置數(shù)據(jù) 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樣式,需要再額外多覆寫(xiě)2個(gè)方法 81 * (1)、getItemViewType(int position)給定類型標(biāo)示符 82 * (2)、getViewTypeCount() 類型數(shù)量 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;// 如果消息類型為發(fā)送,則值為1 91 } 92 93 @Override 94 public int getViewTypeCount() { 95 return 2; 96 } 97 98 private final class ViewHolder { 99 TextView time;// 消息時(shí)間100 TextView msg;// 消息內(nèi)容101 }102 103 }
然后就是主程序代碼了:
這里就沒(méi)什么好說(shuō)的了,網(wǎng)絡(luò)數(shù)據(jù)獲取工具類包括ListView的適配器類在之前已經(jīng)提過(guò),這里就只剩下調(diào)用了。
注意點(diǎn)有3:
1、那就是在UI主線程里不能直接取獲取網(wǎng)絡(luò)數(shù)據(jù),這里我們需要另開(kāi)一個(gè)子線程去獲取,然后在通過(guò)Handler去更新UI界面。
2、當(dāng)數(shù)據(jù)源發(fā)生更新的時(shí)候,需要在UI主線程去操作,而不是子線程,還有就是不應(yīng)該去重新設(shè)置Adapter,只需要去調(diào)用Adapter的notifyDataSetChanged()就行。
3、記得設(shè)置下ListView的setSelection選項(xiàng),便于焦點(diǎn)自動(dòng)往下拉。
不在UI主線程里做耗時(shí)操作,會(huì)使得UI現(xiàn)成阻塞。不在子線程里去更新UI界面,會(huì)導(dǎo)致應(yīng)用程序無(wú)響應(yīng)。
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;//數(shù)據(jù)源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);//定位位置,自動(dòng)下拉37 38 };39 };40 @Override41 protected void onCreate(Bundle savedInstanceState) {42 super.onCreate(savedInstanceState);43 setContentView(R.layout.activity_main);44 45 initView();//初始化控件46 initData();//初始化數(shù)據(jù)47 initAction();//初始化事件48 }49 50 private void initAction() {51 this.sendbt.setOnClickListener(new OnClickListener() {52 53 @Override54 public void onClick(View v) {55 /**56 * 點(diǎn)擊發(fā)送按鈕執(zhí)行步驟57 * 1、獲取用戶輸入的內(nèi)容并顯示到ListView(判斷是否為空)58 * 2、發(fā)送用戶輸入的內(nèi)容到服務(wù)端獲取服務(wù)端返回內(nèi)容并顯示到ListView(注意線程處理)59 * 3、清空輸入框60 */61 final String sendInfo=sendmsg.getText().toString();//獲取用戶輸入數(shù)據(jù)(用于發(fā)送)62 data.add(new Msg("",sendInfo,new Date(),Type.INCOME));63 adapter.notifyDataSetChanged();//更新數(shù)據(jù)源64 listview.setSelection(data.size()-1);//定位位置,自動(dòng)下拉65 sendmsg.setText("");66 67 68 //向服務(wù)端發(fā)送信息并接收返回信息,由于UI主線程不能執(zhí)行網(wǎng)絡(luò)獲取操作,這里需要開(kāi)一個(gè)子線程69 new Thread(){70 71 @Override72 public void run() {73 //執(zhí)行網(wǎng)絡(luò)操作74 GetDataUtils dataUtils=new GetDataUtils();75 Msg msg=dataUtils.getInfo(sendInfo);//獲取到一個(gè)Msg對(duì)象,但由于子線程不能夠更新UI,所以需要用到一個(gè)Handler76 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適配器實(shí)例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 }
好了,到此"安卓智能聊天機(jī)器人”就已經(jīng)完成了,雖說(shuō)這個(gè)機(jī)器人有點(diǎn)二,不過(guò)在無(wú)聊之余還是可以打發(fā)打發(fā)時(shí)間的哈~
作者:Balla_兔子出處:http://www.companysz.com/lichenwei/本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文鏈接。正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,日后必有一番作為!旁邊有“推薦”二字,你就順手把它點(diǎn)了吧,相得準(zhǔn),我分文不收;相不準(zhǔn),你也好回來(lái)找我!
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注