【Android】《App研发录》总结
说明
看这本书的时候,总感觉怪怪的。
因为在地铁上看完的,作者书中基本都是他自己工作中遇到的问题和坑,虽说这样会让人感觉找到了解决方案,可以再进行深入的研究,可是某些地方介绍的有点片面,仅仅是引用部分博客就以偏概全了。还有可能是涉及的内容大部分都是我自己已经踩过的坑,所以觉得学到的东西不太多。
再说说值得一看的地方吧,首先也如前面提到的,书中内容基本都是作者工作之谈,所以有很实用的内容,推荐阅读章节:
App竞品技术分析
个人认为这是本书的精华,很少看到有人愿意这样详尽的介绍自己的“机密”经验,感谢作者的无私分享。
五、六、七章的异常和ProGuard
介绍很详细,网上都是非常琐碎的介绍,推荐新人看看这部分,尤其是ProGuard,虽然现在第三方已经给出了完善的解决方案,帮我们做了这部分事情,不过了解最基本的原理才能学得更透彻。
项目、团队管理部分
这部分是时间的积累才能收获的,提前学习了解以后我们必须经历的路没什么不好的。测试部分相关的部分是很少有书籍能够提及,值得看看。
第一章小结
重构目录
将混乱类文件按照自己的职责划分并存放在相关目录下,如:
com.xxx.xxx. | -- activity
| -- utils
| -- adapter
| -- entity
| -- ui
| -- interface
| -- listener
有了清晰的目录结构,寻找各功能的类文件方便得多,而且便于团队间多人协作开发。谁也不愿意找个相关类全路径的到处搜,干这种事的人不被同事骂死才怪。
归类注意的几个点:
- 遵循单一职责原则,业务、功能耦合过多的文件、代码尽量拆分为多个文件或方法
- 形象化,类名、方法名一眼就应该知道干嘛的,取名别太抽象,Activity1.java这种名是欠打呢。与视频相关的Activity应取名:VideoActivity.java,听过有人喜欢把Activity放在前面(ActivityVideo.java)看起来统一,但感觉那样进行索引文件的时候不方便,每次都要打全Activity + Suffix,不如Prefix来得方便。
重定义生命周期
该部分主要说明对Activity一个简单的封装,Activity都继承一个基类BaseActivity,其中BaseActivity将常用的操作封装起来当作一种规范,如onCreate() —> initViews() —> loadData() 。事实上现在很多项目都是使用的各种框架库,如ButterKnife、EventBus,Otto等,所以这种较老的方式或许慢慢少了起来,可主要的抽象思想都应该有嘛。
统一编程模型
这个地方个人不是太赞同作者推荐的View.setOnClickListener(new OnClickListener() { Override onclick() { … } }这种方式来进行事件注册。确实switch … case … 有点“扰乱”面向对象的风格,可想想一个代码较多的Activity中,你要迅速定位某个onClick事件使用后者有多么方便,并且onClick的事件都能统一管理,无需再担心某个地方漏了一个onClIck。
实体化编程
通过固定的类库达到我们想要的目的,常用类库Gson、FastJson等,不用过多赘述。其中有一点值得一看,就是关于后面提到的Crash事件处理,其实在传递Intent的时候也可进行避免某些Crash的操作,如长时间的闲置导致内存回收时将关键的变量给回收了,当前跳转页面的时候是需要那个变量的,而传递变量的同时可以进行检查判断是否为null来减少跳转后的NPE(NullPointerException) Crash。这些都是我个人的经验。
推荐工具:
这里书中提到的工具都过时了吧(绝对没有嘲讽的意思,能分享的人都是伟大的)。因为拿来主义的我一般用的都是Android Studio中的插件GsonFormat ,不支持Eclipse!
关于更多工具,推荐看看我的博文:Android-Classical-OpenSource的工具篇,有我常用的AS的插件和相关工具的介绍。
第二章小结
第二章主讲网络框架的经验,涉及到的有对网络底层框架的封装,作者遇到的坑和某些网络类库的使用优化建议等。对于网络请求这类操作,当前衍生的各种相关类库功能十分强大,而且基本都封装好了,在使用方便的同时可不要忽略底层的概念,一门技术要做到:知其然,知其所以然。这样无论遇到什么问题都能有一颗冷静沉着的心去面对和挑战。
网络底层封装
家家使用的工具都不同,但常用的也就那么几个:
Volley
目前公司项目用的就是这一个,还是我当时建项以来综合对比后挑的一个,那时候的OkHttp还没有现在这样火好不好。所以我们也当然对Volley进行了简单的封装,这里不说文章,先谈谈我对Volley封装的看法吧。
打开Volley的目录结构,在toolbox中可以看到网络请求类常用的有这么几个
String
- StringRequest :常用的文本、字符串都可以使用此方式。这里给出封装的例子:
接口类RequestCallbackable.java,用于进行请求结果的回调。
public interface RequestCallbackable<T> {
void onSuccess(T model);
void onFailure(T msg);
}
封装方法中,由于请求分为Get和Post两种,并且很可能Post会含有Body,因此需要二次封装,下面是基于StringRequest的一个完整封装类
public class HttpUtils {
private static final int VOLLEY_REQUEST_TIMEOUT_MS = 20 * 1000;
private static final int VOLLEY_REQUEST_RETRY_TIMES = 0;
/**
* Get请求
*
* @param strKVs 这里的strKVs代表Get的参数字段,
* 如果没有参数或者body则不填,
* 格式为:
* "user[name]", username,
* "user[password]", userPassword,
* "user[id]", userId
*/
public static void doVolleyGet(String getUrl,
final RequestCallbackable requestResult,
final String... strKVs) {
doVolleyRequest(Request.Method.GET, getUrl, requestResult, strKVs);
}
/**
* Post请求
*
* @param strKVs 这里的strKVs代表Post的参数、body字段,
* 如果没有参数或者body则不填,
* 格式为:
* "user[name]", username,
* "user[password]", userPassword,
* "user[id]", userId
*/
public static void doVolleyPost(String getUrl,
final RequestCallbackable requestResult,
final String... strKVs) {
doVolleyRequest(Request.Method.POST, getUrl, requestResult, strKVs);
}
/**
* RequestManager需要在Application初始化
* 关于RequestManager的使用详情请自行谷歌
*/
private static void doVolleyRequest(int requestMethod, String requestUrl,
final RequestCallbackable requestCallbackable,
final String... paramsStrKVs) {
if (TextUtils.isEmpty(requestUrl)) return;
// 使用的是StringRequest
StringRequest requestPost = new StringRequest(requestMethod, requestUrl,
new Response.Listener<String>() {
@Override
public void onResponse(String resultStr) {
if (requestCallbackable != null) {
requestCallbackable.onSuccess(resultStr);
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
if (requestCallbackable != null) {
requestCallbackable.onFailure(volleyError);
}
}
}) {
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Authentication", "here put your Token");
return params;
}
@Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> map = new HashMap<String, String>();
if (paramsStrKVs != null && (paramsStrKVs.length % 2 == 0)) {
for (int i = 0; i < paramsStrKVs.length; i += 2) {
map.put(paramsStrKVs[i], paramsStrKVs[i + 1]);
}
}
return map;
}
@Override
public byte[] getBody() throws AuthFailureError {
String httpPostBody = "";
if (paramsStrKVs != null && (paramsStrKVs.length % 2 == 0)) {
for (int i = 0; i < paramsStrKVs.length; i += 2) {
httpPostBody += (i == 0 ? "" : "&") + paramsStrKVs[i] + "=" + paramsStrKVs[i + 1];
}
}
return httpPostBody.getBytes();
}
};
// 设置volley的请求超时时间,重试次数
requestPost.setRetryPolicy(new DefaultRetryPolicy(VOLLEY_REQUEST_TIMEOUT_MS, VOLLEY_REQUEST_RETRY_TIMES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
// queueTag 用于调用cancelAll(queueTag)取消加入队列的请求
requestPost.setTag(RequestManager.getRequestQueue.getQueueTag());
RequestManager.getRequestQueue().add(requestPost);
}
}
使用方式
HttpUtils.doVolleyGet("your request url",
new RequestCallbackable() {
@Override
public void onSuccess(Object model) {
// request onSuccess callback
// this callback on UI main thread
}
@Override
public void onFailure(Object msg) {
// request onFailure callback
// this callback on UI main thread
}
},
"user[name]", username,
"user[password]", userPassword,
"user[id]", userId);
}
Iamge
ImageRequest
比起上面的StringRequest要简单,封装方式差不多,也就不多说了。ImageRequest的简单使用方式:
ImageRequest imagerequest = new ImageRequest("your image url",
new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
// callback on UI main thread
}
},
maxWidth, maxHeight,
ImageView.ScaleType.CENTER,
Bitmap.Config.ARGB_8888,
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
// error callback on UI main thread
}
});
NetworkImageView
这可是个重头戏,通过NetworkImageView.setImageUrl()来进行ImageView的图片下载,结合LRU进行图片的二级缓存(内存、磁盘),需要注意的是,Volley的请求方式都是通过RequestQueue这个队列进行网络访问的,也就是说通常全局只需要使用同一个Queue,那么RequestManager的目的就是为了实例化Queue以保证方法对其正常的调用。
NetworkImageView的使用方式:
NetworkImageView imageview = null;
imageview = (ImageView) findViewById(R.id.your_image_view_id);
imageview.setImageUrl("your image url", ImageCacheManager.getInstance().getImageLoader());
说到这里,慢慢引申出了ImageCacheManager这个神奇的Manager类,实际上ImageCacheManager也是一个封装类,将Volley的ImageLoader包装起来,实现了二级缓存策略。详情见该作者的GitHub。
JSON
Json请求方式和StringRequest大同小异,只不过回调的对象是JSONObject罢了,不介绍了。相关请求类如下:
JsonRequest
JsonObjectRequest
JsonArrayRequest
【Android】《App研发录》总结的更多相关文章
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- 配置android sdk 环境
1:下载adnroid sdk安装包 官方下载地址无法打开,没有vpn,使用下面这个地址下载,地址:http://www.android-studio.org/
- Android SwipeRefreshLayout 下拉刷新——Hi_博客 Android App 开发笔记
以前写下拉刷新 感觉好费劲,要判断ListView是否滚到顶部,还要加载头布局,还要控制 头布局的状态,等等一大堆.感觉麻烦死了.今天学习了SwipeRefreshLayout 的用法,来分享一下,有 ...
- Android Studio配置 AndroidAnnotations——Hi_博客 Android App 开发笔记
以前用Eclicps 用习惯了现在 想学学 用Android Studio 两天的钻研终于 在我电脑上装了一个Android Studio 并完成了AndroidAnnotations 的配置. An ...
- Android请求网络共通类——Hi_博客 Android App 开发笔记
今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- Android Studio 多个编译环境配置 多渠道打包 APK输出配置
看完这篇你学到什么: 熟悉gradle的构建配置 熟悉代码构建环境的目录结构,你知道的不仅仅是只有src/main 开发.生成环境等等环境可以任意切换打包 多渠道打包 APK输出文件配置 需求 一般我 ...
- JS调用Android、Ios原生控件
在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...
- Android UI体验之全屏沉浸式透明状态栏效果
前言: Android 4.4之后谷歌提供了沉浸式全屏体验, 在沉浸式全屏模式下, 状态栏. 虚拟按键动态隐藏, 应用可以使用完整的屏幕空间, 按照 Google 的说法, 给用户一种 身临其境 的体 ...
随机推荐
- Handlebars.js的学习
写在开头的话: 在使用Ghost搭建自己的博客的时候,发现不会Handlebars.js寸步难行,所以本人决定学习下Handlebars.js,因此在此做个记录 为什么选择Handlebars.js ...
- 在手机网页上模拟 js 控制台
在手机上模拟 console 做一些简单代码调试 在工作机上编辑好代码用QQ 之类的工具传到 手机上在调试当然你也可以尝试用一只手指写代码的壮举设置 window.console = mobiDeb ...
- Java程序开发.邱加永2.1节
by2016.9.8 2.7.1 一维数组 1. 声明 int[] m: char[] c: double[] d: 2. 创建 数组声明之后还不能使用,m = new int[10]: c = ...
- CGI和ISAPI
1) CGI概念CGI即通用网关接口(Common Gateway Interface),它是一段程序,运行在服务器上,提供同客户端HTML页面的交互,通俗的讲CGI就象是一座桥,把网页和WEB服务器 ...
- 关于全排列 next_permutation() 函数的用法
这是一个c++函数,包含在头文件<algorithm>里面,下面是基本格式. 1 int a[]; 2 do{ 3 4 }while(next_permutation(a,a+n)); 下 ...
- 学习笔记:delphi多线程知识
最近一直在温习旧的知识,刚好学习了一下Java的线程安全方面的知识,今天想起之前一直做的Delphi开发,所以还是有必要温习一下,看看这些不同的编程语言有什么不同之处. Delphi的线程同步方法: ...
- 【php爬虫】百万级别知乎用户数据爬取与分析
代码托管地址:https://github.com/hoohack/zhihuSpider 这次抓取了110万的用户数据,数据分析结果如下: 开发前的准备 安装Linux系统(Ubuntu14.04) ...
- NoSQL初探之人人都爱Redis:(2)Redis API与常用数据类型简介
一.Redis API For .Net 首先,不得不说Redis官方提供了众多的API开发包,但是目前Redis官方版本不支持.Net直接进行连接,需要使用一些第三方的开源类库.目前最流行的就是Se ...
- 让浏览器不再显示 https 页面中的 http 请求警报
HTTPS 是 HTTP over Secure Socket Layer,以安全为目标的 HTTP 通道,所以在 HTTPS 承载的页面上不允许出现 http 请求,一旦出现就是提示或报错: Mix ...
- Java ServletContextListener用法
ServletContext 被 Servlet 程序用来与 Web 容器通信.例如写日志,转发请求.每一个 Web 应用程序含有一个Context,被Web应用内的各个程序共享.因为Context可 ...