最近写了一个与机器人聊天的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看看