最近写了一个与机器人聊天的demo,现在发一个教程,希望能对大家有帮助
先发几张效果图
一、布局
这是一个简单的demo,所以就一个页面,用了三个布局文件,主布局中一个List,两个对话样式布局。
<?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/robot_chat_time"
android:layout_width="match_parent"
android:layout_height="25dp"
android:gravity="center"
android:text="@string/time_ui" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/robot_photo"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="25dp"
android:src="@drawable/robotportrait" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:text="@string/robot_name" />
</LinearLayout>
<TextView
android:id="@+id/robot_speak"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/chatfrom_bg_focused"
android:gravity="center"
android:text="@string/hello" />
</LinearLayout>
</RelativeLayout>
效果图:
二、实体类的布置
布局已经有了,接下来就是代码了,首先我们需要定义需要的实体类
一、对于一个简单的聊天平台,我们需要打印的信息有(聊天实体类)
1、聊天时间 (data)
2、聊天内容 (message)
3、消息类型(type)
/*
* 聊天数据类
* */
public class ChatMessager {
private String messager;// 消息
private Date date;// 时间
private Type type;// 类型:发送者.0 接受者.1
public ChatMessager() {
}
public ChatMessager(String messager, Date date, Type type) {
super();
this.messager = messager;
this.date = date;
this.type = type;
}
public String getMessager() {
return messager;
}
public void setMessager(String messager) {
this.messager = messager;
}
public Date getDate() {
return date;
}
public void setData(Date date) {
this.date = date;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public enum Type {
INCOUNT, OUTCOUNT
}
}
三、用于与网络进行交互的有(反应服务端映射的结果类)
1、code码(code是用另一个词、数字或标志来置换一个词或短语,达到隐藏原来的词或短语的目的,它主要起到置换的作用。)
2、网络返回的信息text
public class IntentCode {
private int code;// code码
private String text;// 消息
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return text;
}
public void setMessage( String text) {
this.text = text;
}
}
三、http的配置信息类
数据请求的配置,从图灵网注册了一个账号,获取到的api地址
/*
* 配置类
* */
public class HttpRrequest {
public static final String URL_KEY = "http://www.tuling123.com/openapi/api";
public static final String APP_KEY = "817259da4b7b4f105d1ca8d3072ed7ab";
}
这个里面我们需要将要发送的信息向网络端发送过去,所以这里我们需要将数据请求类中的API地址跟URL地址用到,并将用户发送的信息,根据接口提供的请求方式结合,返回url
/**
* 设置参数 返回url
* */
private static String grtUrl(String message) {
String url = "";
try {
url = HttpRrequest.URL_KEY + "?" + "key=" + HttpRrequest.APP_KEY
+ "&info=" + URLEncoder.encode(message, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return url;
}
网络请求类别有两种,这里我们用到get方式。
/**
* 请求方式:get
*
* @return: 返回发送的数据
* */
public static String toGet(String message) {
String result = "";
String utils = grtUrl(message);
InputStream is = null;
ByteArrayOutputStream ba = null;
try {
URL urls = new URL(utils);
HttpURLConnection connection = (HttpURLConnection) urls
.openConnection();
// 超时时间
connection.setReadTimeout(5 * 1000);
connection.setConnectTimeout(5 * 1000);
connection.setRequestMethod("GET");
is = connection.getInputStream();
ba = new ByteArrayOutputStream();
int len = -1;
byte[] buff = new byte[1024];
while ((len = is.read(buff)) != -1) {
ba.write(buff, 0, len);
}
// 确保数据写入
ba.flush();
// 将信息传给返回值
result = new String(ba.toByteArray());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 关闭相应的流
if (is != null) {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (ba != null) {
try {
ba.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return result;
}
然后,我们要把信息内容发送给服务器,并从服务器端,获取信息
/**
* 将获取到的消息数据进行处理
*
* @param messager
* @return 消息
*/
public static ChatMessager sendMassager(String messager) {
ChatMessager chatMessager = new ChatMessager();
String toresult = toGet(messager);
Gson gs = new Gson();
IntentCode result = null;
if (toresult != null) {
try {
// Java 对象转成一个将JSON 字符串
result = gs.fromJson(toresult, IntentCode.class);
chatMessager.setMessager(result.getMessage());
} catch (Exception e) {
chatMessager.setMessager("服务器繁忙,请稍候再试...");
}
}
chatMessager.setData(new Date());
chatMessager.setType(Type.INCOUNT);
return chatMessager;
}
这样,关于HTTP工具类的布置就差不多了。
对了在之前我还有说到过时间,所以,我们还要建立一个时间格式化类。
/**
* 时间格式化工具类
* */
public class DataUtil {
@SuppressLint("SimpleDateFormat")
public static String getDataString(Date date) {
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sd.format(date);
}
}
四、适配器
从网上了解BaseAdapter就Android应用程序中经常用到的基础数据适配器,它的主要用途是将一组数据传到像ListView、Spinner、Gallery及GridView等UI显示组件,继承与adapter。
这里我决定我的ChatAdater继承与BaseAdapter,更好实现我想要的功能。
继承后复写父类的一系列需要的方法,这里复写了 getCount()、 ChatAdater(List list)、getItem(int position)、getItemId(int position)、getItemViewType(int position)、getViewTypeCount()、getView(int position, View convertView, ViewGroup parent),在getview中通过getItemViewType(int position)返回type的不同,来控制用户或端口发送效力的类型
public class ChatAdater extends BaseAdapter {
private List<ChatMessager> list;
public int getCount() {
return list.isEmpty() ? 0 : list.size();
}
public ChatAdater(List<ChatMessager> list) {
super();
this.list = list;
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
/**
* 返回消息类型:0、接受 1、发送
*
* */
public int getItemViewType(int position) {
ChatMessager chatMessager = list.get(position);
if (chatMessager.getType() == Type.INCOUNT) {
return 0;
}
return 1;
}
public int getViewTypeCount() {
return 2;
}
/**
* 根据type加载不同布局
* */
public View getView(int position, View convertView, ViewGroup parent) {
ChatMessager chatMessager = list.get(position);
if (convertView == null) {
ViewHolder viewHolder = null;
if (getItemViewType(position) == 0) {
System.out.println("type" + getItemViewType(position));
convertView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.robot_chatlist, null);
viewHolder = new ViewHolder();
viewHolder.vh_time = (TextView) convertView
.findViewById(R.id.robot_chat_time);
viewHolder.vh_message = (TextView) convertView
.findViewById(R.id.robot_speak);
} else {
System.out.println("type2" + getItemViewType(position));
convertView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.user_chatlist, null);
viewHolder = new ViewHolder();
viewHolder.vh_time = (TextView) convertView
.findViewById(R.id.user_chat_time);
viewHolder.vh_message = (TextView) convertView
.findViewById(R.id.user_speak);
}
convertView.setTag(viewHolder);
}
ViewHolder vh = (ViewHolder) convertView.getTag();
vh.vh_time.setText(DataUtil.getDataString(chatMessager.getDate()));
System.out.println("time"
+ DataUtil.getDataString(chatMessager.getDate()));
vh.vh_message.setText(chatMessager.getMessager());
System.out.println("text" + chatMessager.getMessager());
return convertView;
}
private class ViewHolder {
private TextView vh_time, vh_message;
}
}
五、activity的布置
public class MainActivity extends ActionBarActivity {
private List<ChatMessager> list;
private ListView ch_list;
private Button ch_send;
private EditText ch_input;
private ChatAdater adater;
private ChatMessager chatMessager = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initview();
initListener();
initdata();
}
// 获取控件id,初始视图
private void initview() {
ch_list = (ListView) findViewById(R.id.chat_listview);
ch_input = (EditText) findViewById(R.id.chat_input_message);
ch_send = (Button) findViewById(R.id.chat_input_send);
}
// 设置监听事件
private void initListener() {
ch_send.setOnClickListener(clickListener);
}
// 点击事件监听
OnClickListener clickListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (v.getId() == R.id.chat_input_send) {
chat();
}
}
};
// 初始化数据
private void initdata() {
list = new ArrayList<ChatMessager>();
list.add(new ChatMessager("小桃子为你服务", new Date(), Type.INCOUNT));
// list.add(new ChatMessager("小桃子为你服务", new Date(), Type.OUTCOUNT));
adater = new ChatAdater(list);
ch_list.setAdapter(adater);
// 刷新数据
adater.notifyDataSetChanged();
}
private void chat() {
final String send_message = ch_input.getText().toString().trim();
if (TextUtils.isEmpty(send_message)) {
Toast.makeText(MainActivity.this, "对不起,您还未发送任何消息",
Toast.LENGTH_SHORT).show();
return;
}
ChatMessager messager = new ChatMessager();
messager.setMessager(send_message);
messager.setData(new Date());
messager.setType(Type.OUTCOUNT);
list.add(messager);
adater.notifyDataSetChanged();
ch_input.setText("");
new Thread() {
public void run() {
ChatMessager chat = HttpUtils.sendMassager(send_message);
Message message = new Message();
// 0*1十六进制的一个标识
message.what = 0x1;
message.obj = chat;
handler.sendMessage(message);
};
}.start();
}
// handler创建在主线程之中
private Handler handler = new Handler() {
@SuppressLint("HandlerLeak")
public void handleMessage(android.os.Message msg) {
if (msg.what == 0x1) {
if (msg.obj != null) {
chatMessager = (ChatMessager) msg.obj;
}
// 添加数据到list中,更新数据
list.add(chatMessager);
adater.notifyDataSetChanged();
}
};
};
}
恩,教程就这样吧,我是一个初学者,所以描述的不是很详细,希望可以帮到同样是初学者的朋友们。
对了,因为这个demo是要联网的,所以还需要在AndroidManifest.xml,注册<uses-permission android:name="android.permission.INTERNET" />
关于这个demo的API大家可以去http://www.tuling123.com/openapi/api看看