今天做了一个智能聊天机器人,其实相对比较简单,用到的知识点如下:
1.listView的熟练使用
2.第三方API的调用,发送数据请求和返回数据解析
3.网络请求时使用的异步任务和Handler
不过学会了之前没有接触的东西,在IDE里测试工具类,写完工具类测试是一个好习惯
public class HttpUtil {
private static final String URL = "http://www.tuling123.com/openapi/api";
private static final String API_KEY = "";
private static final String CHARSET = "UTF-8";
/*
* 发送一个消息,得到ChatMessage类型返回值
*/
public static ChatMessage sendChatmessage(String msg){
ChatMessage chatMessage = new ChatMessage();
String JsonResult = getMsg(msg);
Gson gson = new Gson();
Result result = null;
try {
result = gson.fromJson(JsonResult, Result.class);
chatMessage.setMsg(result.getText());
} catch (JsonSyntaxException e) {
chatMessage.setMsg("服务器异常");
e.printStackTrace();
}
chatMessage.setDate(new Date());
chatMessage.setType(Type.INCOMING);
return chatMessage;
}
/*
* 发送请求,得到返回这为json数组
*/
public static String getMsg(String msg){
StringBuffer result = new StringBuffer();
StringBuffer outBuf = new StringBuffer();
try {
outBuf.append("key=").append(API_KEY).append("&info=").append(URLEncoder.encode(msg, CHARSET));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
HttpURLConnection conn;
try {
//POST方式向服务器端发送信息
conn = (HttpURLConnection) new URL(URL).openConnection();
conn.setRequestMethod("POST");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setDoOutput(true);
//一行行读取和字节读取哪个更好?
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), CHARSET));
out.write(outBuf.toString());
out.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), CHARSET));
String line = "";
while((line = in.readLine()) != null){
result.append(line);
}
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result.toString();
}
}
在这里首先使用POST方式发送消息给服务器(也可以采用GET方式),解析返回值时,返回值是JSON数组,用BufferReader的readline()一行行读取(也可以用字节流读取,相对来说应该更加可靠,但是效率比较慢,因此我使用字符流)。返回的JSON字符串在sendChatMessage()中使用GSON来把JSON字符串解析为对应了Bean,这里我把JSON字符串转化为了Result。工具类写好了,接下来开始测试:
<application
android:allowBackup="true"
android:icon="@drawable/xiaomeng"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<uses-library android:name="android.test.runner"></uses-library>
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<instrumentation
android:targetPackage="com.liu.androidxiaofeng"//指定测试程序的包名
android:label="This is a test"//可以随便写
android:name="android.test.InstrumentationTestRunner">
</instrumentation>
在apalication里写了uses-library,接着编写instrucmentaction,这就是配置测试的必要步骤
接着编写测试类
public class TestHttpUtil extends AndroidTestCase {
private static final String TAG = "TestHttpUtil";
public void testUtil(){
String res = HttpUtil.getMsg("你好");
Log.d(TAG, res);
res = HttpUtil.getMsg("给我讲个笑话");
Log.d(TAG, res);
res = HttpUtil.getMsg("我帅不帅");
Log.d(TAG, res);
}
}
创建一个类继承AndroidTestCase,在里面编写测试逻辑,然后对逻辑测试方法右键 run-as-Android-JUtil-Test
说明测试成功!!
还有一点需要注意,由于listView是对话模式,因此要有两个子项布局,在编写Adapter时,要实现另外两个方法getItemViewType(int position) 和 getViewTypeCount()
public class MsgAdapter extends BaseAdapter {
private List<ChatMessage> data;
private LayoutInflater inflater;
public MsgAdapter(Context context, List<ChatMessage> data){
this.data = data;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
ChatMessage chatMessage = data.get(position);
if(chatMessage.getType() == Type.INCOMING){//如果是接受消息,返回0
return 0;
}else{
return 1;//如果是发送消息,返回1
}
}
@Override
public int getViewTypeCount() {
return 2;//有发送消息和接受消息两种view
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ChatMessage chatMessage = data.get(position);
ViewHolder viewHolder = null;
if(convertView == null){
if(getItemViewType(position) == 0){//说明是接受布局
convertView = inflater.inflate(R.layout.item_from_msg, parent, false);
viewHolder = new ViewHolder();
viewHolder.date = (TextView) convertView.findViewById(R.id.tv_from_msg_date);
viewHolder.msg = (TextView) convertView.findViewById(R.id.tv_from_msg);
}else{//说明是发送布局
convertView = inflater.inflate(R.layout.item_to_msg, parent, false);
viewHolder = new ViewHolder();
viewHolder.date = (TextView) convertView.findViewById(R.id.tv_to_msg_date);
viewHolder.msg = (TextView) convertView.findViewById(R.id.tv_to_msg);
}
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
//设置数据
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
viewHolder.date.setText(dateFormat.format(new Date()));
viewHolder.msg.setText(chatMessage.getMsg());
return convertView;
}
private final class ViewHolder{
TextView date;
TextView msg;
}
}