天天看点

Android智能机器人

今天做了一个智能聊天机器人,其实相对比较简单,用到的知识点如下:

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

Android智能机器人

说明测试成功!!

还有一点需要注意,由于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;
	}

}