天天看點

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;
	}

}