5.1三级缓存 ##
三级缓存流程分析
内存缓存 速度快, 优先读取
本地缓存 速度其次, 内存没有,读本地
网络缓存 速度最慢, 本地也没有,才访问网络
三级缓存工具类
MyBitmapUtils
/**
-
自定义图片加载工具类
* -
@author Kevin
*
*/
public class MyBitmapUtils {private NetCacheUtils mNetCacheUtils; private LocalCacheUtils mLocalCacheUtils; private MemoryCacheUtils mMemoryCacheUtils; public MyBitmapUtils() { mMemoryCacheUtils = new MemoryCacheUtils(); mLocalCacheUtils = new LocalCacheUtils(); mNetCacheUtils = new NetCacheUtils(mLocalCacheUtils, mMemoryCacheUtils); } /**
-
加载图片的核心api
* -
@param ivPic
-
ImageView对象
-
@param url
-
图片链接
*/
public void display(ImageView ivPic, String url) {
ivPic.setImageResource(R.drawable.pic_item_list_default);
// 从内存缓存读
Bitmap bitmap = mMemoryCacheUtils.getBitmapFromMemory(url);
if (bitmap != null) {// 如果内存存在,就直接设置并返回
ivPic.setImageBitmap(bitmap);
System.out.println("从内存读取图片");
return;
}
// 从本地缓存读
bitmap = mLocalCacheUtils.getBitmapFromLocal(url);
if (bitmap != null) {// 如果本地文件存在,就直接设置并返回
ivPic.setImageBitmap(bitmap);
System.out.println("从本地读取图片");
mMemoryCacheUtils.putBitmapToMemory(url, bitmap);// 设置内存图片
return;
}
// 从网络缓存下载
mNetCacheUtils.getBitmapFromNet(ivPic, url);
}
}
网络缓存
NetCacheUtils
/**
-
网络缓存工具类
* -
@author Kevin
*
*/
public class NetCacheUtils {LocalCacheUtils mLocalCacheUtils; MemoryCacheUtils mMemoryCacheUtils; public NetCacheUtils(LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) { mLocalCacheUtils = localCacheUtils; mMemoryCacheUtils = memoryCacheUtils; } public void getBitmapFromNet(ImageView ivPic, String url) { BitmapTask task = new BitmapTask(); task.execute(new Object[] { ivPic, url }); } class BitmapTask extends AsyncTask<Object, Void, Bitmap> { private ImageView imageView; private String url; /**
-
返回的对象会自动回传到onPostExecute里面
*/
@Override
protected Bitmap doInBackground(Object… params) {
imageView = (ImageView) params[0];
url = (String) params[1];
imageView.setTag(url);
Bitmap bitmap = downloadBitmap(url);
return bitmap;
}@Override protected void onPostExecute(Bitmap result) { // 这里的result就是doInBackground返回回来的对象 if (result != null) { String ivUrl = (String) imageView.getTag(); if (url.equals(ivUrl)) {// 确保imageview设置的是正确的图片(因为有时候listview有重用机制,多个item会公用一个imageview对象,从而导致图片错乱) imageView.setImageBitmap(result); System.out.println("从网络缓存读取图片"); // 向本地保存图片文件 mLocalCacheUtils.putBitmapToLocal(url, result); // 向内存保存图片对象 mMemoryCacheUtils.putBitmapToMemory(url, result); } } } } /**
-
下载图片
* -
@param url
-
@return
*/
private Bitmap downloadBitmap(String url) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestMethod(“GET”);
conn.connect();int responseCode = conn.getResponseCode(); if (responseCode == 200) { InputStream inputStream = conn.getInputStream(); //图片压缩 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;//表示压缩比例,2表示宽高都压缩为原来的二分之一, 面积为四分之一 options.inPreferredConfig = Config.RGB_565;//设置bitmap的格式,565可以降低内存占用 Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options); return bitmap; } } catch (Exception e) { e.printStackTrace(); } finally { conn.disconnect(); } return null; }
}
本地缓存
LocalCacheUtils
/**
-
本地缓存工具类
* -
@author Kevin
*
*/
public class LocalCacheUtils {private static final String LOCAL_PATH = Environment .getExternalStorageDirectory().getAbsolutePath() + "/zhbj_cache"; /**
-
从本地读取图片
* -
@param url
-
@return
*/
public Bitmap getBitmapFromLocal(String url) {
try {
String fileName = MD5Encoder.encode(url);
File file = new File(LOCAL_PATH, fileName);if (file.exists()) { // 图片压缩 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;// 表示压缩比例,2表示宽高都压缩为原来的二分之一, 面积为四分之一 options.inPreferredConfig = Config.RGB_565;// 设置bitmap的格式,565可以降低内存占用 Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream( file), null, options); return bitmap; } else { return null; } } catch (Exception e) { e.printStackTrace(); } return null; } /**
-
向本地存图片
* -
@param url
-
@param bitmap
*/
public void putBitmapToLocal(String url, Bitmap bitmap) {
try {
String fileName = MD5Encoder.encode(url);
File file = new File(LOCAL_PATH, fileName);
File parent = file.getParentFile();// 创建父文件夹 if (!parent.exists()) { parent.mkdirs(); } bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file)); } catch (Exception e) { e.printStackTrace(); } }
}
内存缓存
引用级别
强引用 默认引用, 即使内存溢出,也不会回收
软引用 SoftReference, 内存不够时, 会考虑回收
弱引用 WeakReference 内存不够时, 更会考虑回收
虚引用 PhantomReference 内存不够时, 最优先考虑回收!
//用法举例
Bitmap bitmap = new Bitmap();
SoftReference<Bitmap> sBitmap = new SoftReference<Bitmap>(bitmap);
Bitmap bitmap2 = sBitmap.get();
这些避免内存溢出的引用方式在Android 2.3+的版本上已经不再起太大作用, 因为垃圾回收器会频繁回收非强引用的对象, Android官方建议使用LRUCache. 相关链接: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
LRUCache
可以自动控制内存大小, 及时回收不常用的对象, 用法和HashMap类似
MemoryCacheUtils /**
-
内存缓存工具类
* -
@author Kevin
*
*/
public class MemoryCacheUtils {// HashMap<String, SoftReference<Bitmap>> mMemoryCache = new HashMap<String, // SoftReference<Bitmap>>(); LruCache<String, Bitmap> mMemoryCache; public MemoryCacheUtils() { int maxMemory = (int) Runtime.getRuntime().maxMemory();// 当前手机分配给app进程的最大内存,虚拟机默认16M System.out.println("maxMemory:" + maxMemory); mMemoryCache = new LruCache<String, Bitmap>(maxMemory / 8) { @Override protected int sizeOf(String key, Bitmap value) { int size = value.getRowBytes() * value.getHeight();// 返回bitmap占用的内存大小 System.out.println("sizeof:" + size); return size; } }; } /**
-
从内存读取图片
* -
@param url
-
@return
*/
public Bitmap getBitmapFromMemory(String url) {
// SoftReference softBitmap = mMemoryCache.get(url);
// System.out.println(“读取内存图片。。。” + softBitmap);
// if (softBitmap != null) {
// Bitmap bitmap = softBitmap.get();
// System.out.println(“读取内存图片成功。。。” + bitmap);
// return bitmap;
// }Bitmap bitmap = mMemoryCache.get(url); return bitmap; } /**
-
向内存存图片
* -
@param url
-
@param bitmap
*/
public void putBitmapToMemory(String url, Bitmap bitmap) {
// System.out.println(“设置内存图片。。。”);
// SoftReference softBitmap = new
// SoftReference(bitmap);// 通过软引用对对象包装
// mMemoryCache.put(url, softBitmap);
mMemoryCache.put(url, bitmap);
}
}
5.2屏幕适配 ##
图片适配
开启4种分辨率的模拟器
在drawable的多个目录下放置内容不同但命名相同的图片
运行程序,查看在不同模拟器上的显示效果
常规做法: 美工只做一套1280*720的图片,放置在drawable-xhdpi的目录下, ImageView宽高指定为确定的值, 不包裹屏幕
布局适配
针对特定分辨率,创建layout文件夹: layout-800x480, layout-land(表示横屏)
800x480 和其他分辨率模拟器对比
常规做法: 该方式不到万不得已,一般不用
尺寸(dimens)适配
设备密度:
float density = getResources().getDisplayMetrics().density;
dp = px / 设备密度
常规设备密度: 320x240(0.75), 480x320(1), 800x480(1.5), 1280x720(2)
设置dp值, 在不同屏幕上查看显示的比例
创建文件夹values-1280x720, 在dimens.xml中制定尺寸, 适配屏幕
常规做法: 此方法比布局适配更常用. 美工提供像素px值, 我们使用前需要用px除以设备密度,转换成dp后,写在布局文件中
案例分析: 智慧北京新手引导页小圆点处理
权重适配
android:weightSum="3" //表示总权重数
常规做法: 当布局有严格比例分配时, 可以使用权重来处理
代码适配
int width = getWindowManager().getDefaultDisplay().getWidth();
int height = getWindowManager().getDefaultDisplay().getHeight();
tv1.setLayoutParams(new LayoutParams((int)(width0.5), (int)(height0.2)));
常规做法: 如果是自定义的控件, 没有使用xml布局文件时, 可以在代码中动态设置宽高
案例分析: 智慧北京侧边栏宽度处理
5.3 消息推送 ##
极光推送
官方地址: https://www.jpush.cn/
创建应用,获取appkey
按照文档流程, 写推送例子程序
下载sdk
拷贝sdk中的AndroidManifest.xml文件, 修改相应内容
自定义MyReceiver
后台发送消息, 演示效果
查看高级功能, 在MyReceiver中打印获取的信息及附加信息
注意: 极光推送后台最多只能创建3个应用, 所以演示前需要确保已存在应用少于3个
下载Demo并演示
推送原理介绍
XMPP协议
一种基于TCP/IP的应用层协议, 专门用于消息推送, 数据格式为xml
长连接
使用socket请求时, 服务端和客户端都不主动关闭输入输出流, 从而实现长连接
心跳包
客户端每隔一段时间(比如1分钟)向服务器发送一段极短的数据,称为心跳包. 服务器收到数据, 就证明客户端还活着, 就会保持连接,向客户端推送消息. 否则断开连接,节省服务器性能. 客户端重连后,服务器将未发送成功的消息重新发出.
5.4语音识别 ##
科大讯飞语音云
http://open.voicecloud.cn/
下载SDK, 阅读SDK文档(MSC开发手册), 按照文档,实现如下三个功能
语音识别
语音识别弹窗
语音朗诵