Android模仿微信相册(上传和九宫格展示)
本人小白自学编程,把这段时间学到的和查到的所有知识点攒起来写了这个小程序,当作总结吧。第一次自己从搭架子到动手实现,写了这个小程序,期间各种查资料各种改觉得很有意思,最后终于算是能把想法实现了,虽说还是个雏形,还有很多地方需要改进,但是发现越来越喜欢编程这件事了。
首先介绍一下“SimpleAlbum”,Android端完成了登录、图片的仿个人相册浏览、图片的上传和更新的功能,服务器端用Shiro+SSM+MySQL搭的。
一、程序描述
登录模块
服务器端用Shrio完成认证过程(Shrio用Subject.login(token)方法实现认证,用户名密码的realm用.ini文件配置),认证是否通过用Json传回手机端,通过则返回true跳转AlbumActivity,不通过返回false,留在LoginActivity。
手机端的MainActivity访问“/check”路径,首次登陆与服务器建立会话,服务器返回false,跳转至登陆面页LoginActivity,登陆成功后再次登录,由于手机端已经与客户端建立会话,服务器保存有相应的会话ID,所以返回true,进入相册面页AlbumActivity。代码如下:
private void okCheck() {
OkHttpClient client = ClientFactory.getInstance(getApplicationContext());
Request okRequest = new Request.Builder()
.url("http://192.168.1.4:8080/SimpleAlbum/Kikyo/check")
.build();
client.newCall(okRequest).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
JSONObject result_obj = JSON.parseObject(result);
boolean isLogin = result_obj.getBooleanValue("login");
if (!isLogin) {
handler.sendEmptyMessage(0);
} else {
Intent intent = new Intent(MainActivity.this, AlbumActivity.class);
startActivity(intent);
finish();
}
}
});
}
ClientFactory类:
public class ClientFactory {
private static OkHttpClient client;
public static OkHttpClient getInstance(Context context) {
if (client == null) {
synchronized (ClientFactory.class) {
if (client == null)
client = new OkHttpClient.Builder().cookieJar(new
CookieManager(context)).build();
}
}
return client;
}
}
这里用okHttp的cookieJar来实现对cookie的存取和携带,需要自己实现CookieManager类,其中用PersistentCookieStore类将cookie存入sharedPreference,用SerializableOkHttpCookies类将cookie进行序列化。
具体参考:https://www.jianshu.com/p/41b4cbe1dbec
服务器端“/check”路径代码如下:
@RequestMapping("/check")
public @ResponseBody LoginJudgement check(HttpServletRequest req) throws Exception {
LoginJudgement judge = new LoginJudgement();
judge.setLogin(false);
judge.setErrorMsg("Please Login");
HttpSession session = req.getSession(false);
if(session == null) {
return judge;
}
//如果曾经成功登录,这里就返回true
Subject currentSubject = SubjectUtil.getCurrentSubject(session.getId());
if(currentSubject != null) {
if(currentSubject.isAuthenticated()) {
judge.setLogin(true);
return judge;
}
}
return judge;
}
这里的再次登录验证可以用自定义token的方法,可以参考:
如果用户未登录的话,服务器返回false,手机端跳转至loginActivity。我这里用post明文传输用户名和密码。访问“/login”路径,服务器端代码如下:
@RequestMapping("/login")
public @ResponseBody LoginJudgement login(String username, String password, HttpServletRequest req, HttpServletResponse resp) {
LoginJudgement judge = new LoginJudgement();
judge.setLogin(false);
//首次登陆执行代码
//启用支持Session servlet自动返回名为“Set-cookie”的cookie(Jsessionid=xxx)
HttpSession session = req.getSession();
//自定义工具类新建一个subject
Subject subject = SubjectUtil.createSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
judge.setLogin(true);
//如果认证成功,用sessionID作key将subject存入服务器内存中,下次进入首页是直接验证是否存在该SessionID并且拿出subject看是否islogin()就可以免去登录了
SubjectUtil.saveCurrentSubject(session.getId(), subject);
} catch (UnknownAccountException e) {
e.printStackTrace();
judge.setErrorMsg("UnknownAccount");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
judge.setErrorMsg("IncorrectCredentials");
} catch (Exception e) {
e.printStackTrace();
judge.setErrorMsg("LoginError");
}
return judge;
}
这其中用户名和密码的传输可以用加密的方式传输,比如加盐并且多次单向散列,再安全一点就用Https链接传输,涉及到服务器端的自签名证书和手机端处理Https请求的方法。
相册模块
AlbumActivity用来展示相册,用一个listview套自定义的NineGridLayout。NineGridLayout的原理和源码是参考的: ,我在那位大哥的基础上简化了一些。
AlbumActivity向服务器“/showMessages”路径请求主页数据,服务器读取数据库后用Json返回分页信息,其中图片以图片名形式传回,在手机端进行“服务器图片路径+图片名=图片url”的拼接再传给NineGridLayout的adapter。
AlbumActivity还初步实现了下拉加载,但是有时会出bug,没想到怎么铲,具体解决办法只能慢慢思考了。
上传模块
上传模块分为上传和本机图片浏览,这部分用了挺长一段时间琢磨,本人写这个应用也是从这部分开始写的。
跟着课程敲代码,然后把两部分合并来实现这部分功能。后来简化为用okHttp的模拟表单上传、用universalImageloader实现本机图片加载和浏览。
总结
这个小程序还有很多功能没有实现,比如:多用户登录,相册的评论功能,图片的点击放大浏览等等。
二、演示图
登录界面(认证登录后保持一直登录)
上传图片到服务器
三、流程图
程序资源请看我的github:(注:app测试用户名和密码baodi,1234)