您的位置:首页 > 移动开发 > Android开发

android学习笔记之客户端与服务端保持session登录状态

2015-08-21 18:06 489 查看
刚进公司不久,也没有具体项目任务,只有一个混合开发模式,使用AppCan开发的项目。

虽然混合开发很便捷、很高效,使用html和js就可以完成。

但我依然对android原生开发有着极高的热情,尤其是在体验了Android 5.0版本之后,更是对原生体验着迷。

所以,我利用空闲时间,使用Android原生开发,实现以下简单任务:

用户登录,查看用户信息,查看用户和领导的谈话列表。

难点:因为缺乏http通信基础,并不知道session和cookie的作用,所以在开发中绕了很多弯路,因为虽然我登录成功了,但是在查询谈话列表时,就会请求失败。

原因:经过一番学习,大概了解了session和cookie的作用,只有让服务器识别出当前登录用户的状态,才能给予其权限进行其他请求操作。

用到的知识点很多,总结一下重要的:

1、关于Volley框架

Volley框架是谷歌官方通信框架,适合小数据传输使用,之前使用都很顺手,可是其没有方法获取httpResponse中的header信息,即无法获取JSESSIONID,JSESSIONID是session的一个独一无二的标识,需要重写框架的方法才可以,故放弃之。

2、使用HttpUrlConnection

使用HttpUrlConnection进行网络请求,涉及网络请求的操作不能在UI线程即主线程执行,需要创建内部类继承自AsyncTask异步任务处理类。

其中最重要的就是通过 conn.getHeaderField("set-cookie")
方法得到返回头部的cookie部分;

然后通过 cookie.substring(0, cookie.indexOf(";"))
方法取出"JSESSIONID=XXXXXX"

private class LoginASyncTask extends AsyncTask<String, Void, String> {

		@Override
		protected String doInBackground(String... params) {
			mSharedPreferences = getSharedPreferences("cookie", MODE_PRIVATE);// 用来存储服务器响应cookie
			mEditor = mSharedPreferences.edit();
			String urlPath = "http://192.168.0.31:8080/jxyy/login/check";
			String result = null;
			try {
				URL url = new URL(urlPath);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setRequestMethod("POST"); // 设置请求方法为post
				conn.setUseCaches(false); // 禁止用户缓存
				conn.setDoOutput(true); // 必须设置:允许输出流
				DataOutputStream dos = new DataOutputStream(
						conn.getOutputStream());// 实例化输出流对象,用于写入参数
				StringBuffer paramsBuffer = new StringBuffer();
				paramsBuffer.append("&username=" + params[0]);
				paramsBuffer.append("&password=" + params[1]);
				paramsBuffer.append("&flag=" + "android");
				System.out.println("paramsBuffer=" + paramsBuffer.toString());
				dos.writeUTF(paramsBuffer.toString());// 使用UTF格式输出该参数
				dos.flush();// 输出缓冲
				dos.close();// 输出关闭
				if (conn.getResponseCode() == 200) {
					<strong>String cookie = conn.getHeaderField("set-cookie");// 获取服务器响应cookie
					String sessionId = cookie.substring(0, cookie.indexOf(";"));
					mEditor.putString("cookie", sessionId);
					mEditor.commit();// 将cookie存入mSharedPreferences中</strong>
					BufferedReader br = new BufferedReader(
							new InputStreamReader(conn.getInputStream()));
					StringBuffer sb = new StringBuffer();
					String temp = "";
					while ((temp = br.readLine()) != null) {
						sb.append(temp);
					}
					result = sb.toString();
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
			return result;
		}

	}


再次请求网络时,需要从SharedPreferences中取出该JSESSIONID

然后使用conn.setRequestProperty方法传入该cookie参数进行网络请求

URL url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("cookie", sharedPreferences.getString("cookie",""));


3、处理返回的JSONArray数据

服务端把每个谈话内容封装为一个JSONObject对象,将满足条件的所有谈话装入一个JSONArray中,以字符串返回客户端。

再看客户端,要以ListView来显示这些谈话内容,而ListView不能识别JSON格式的数据,需要将JSON转化为List<Map<String,String>>对象方可。

具体思路是 :

·循环遍历JSONArray依次取出每个谈话的JSONObject

·在每个JSONObject中,遍历key,value对,存入map对象中

·将map对象依次存入List<Map>中

·使用SimpleAdapter将该List<Map>与ListView绑定

下面是将JSONArray转为List<Map<String,String>>对象详细实现代码:

private List<HashMap<String, String>> jsonArrayToMapList(String result) {

		List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();// 实例化要绑定的List对象
		HashMap<String, String> talk = new HashMap<String, String>();// 用于存储单个谈话会议的map对象
		try {
			JSONArray ja = new JSONArray(result);
			for (int i = 0; i < ja.length(); i++) { // 遍历JSONArray,依次取出JSONObject
				JSONObject jo = ja.getJSONObject(i);
				Iterator<String> it = jo.keys(); // 遍历JSONObject的keys
				while (it.hasNext()) {
					String key = String.valueOf(it.next());
					String value = (String) jo.get(key);
					talk.put(key, value);// 将JSONObject中key,value转存如map
				}
				data.add(talk);// 把所有map存入list中
			}
		} 
		return data;
	}


下面是将List<Map<String,String>>对象绑定至ListView的详细实现代码:

private void bindToListView(List<HashMap<String, String>> data) {
		SimpleAdapter adapter = new SimpleAdapter(this, data,
				R.layout.list_talk, new String[] { "talktitle",
						"personName", "personOrg",
						"targetName", "targetOrg", "talkState" },
				new int[] { R.id.talkTitle, R.id.talkPerson,
						R.id.personOrg, R.id.talkTarget,
						R.id.targetOrg, R.id.talkState });
		lv_talks.setAdapter(adapter);
	}


其中,SimpleAdapter的参数依次是:

this:上下文context,用this即可

data:List<Map<String,String>>类型的要显示的数据

R.layout.list_talk:要用于显示的list布局资源

new String [ ] { "aa", "bb", "cc" }:要显示的map中的key值

new int [ ] { R.id.aa, R.id.bb, R.id.cc } :要显示到的具体的控件资源对应id
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: