对Android开发者,我相信绝对会困扰着。它不像IOS那么好用,有方便的LIBS提供你去使用,以及它本系统自动处理,那么作为Android开发者的你们该如何去处理这个问题?
性能优化 Android应用程序运行的移动设备受限于其运算能力,存储空间,及电池续航。由此,它必须是高效的。电池续航可能是一个促使你优化程序的原因,即使他看起来已经运行的足够快了。由于续航对用户的重要性,当电量耗损陡增时,意味这用户迟早会发现是由于你的程序。 虽然这份文档主要包含着细微的优化,但这些绝不能成为你软件成败的关键。选择合适的算法和数据结构永远是你最先应该考虑的事情,但这超出这份文档之外。
从程序中我们所遇到的内存问题 使用涉及到图片控件时,如果载入的图片过多,过大,就很容易出现OutOfMemoryError异常 在程序中,适时释放资源,是相当关键:
- class ImageManager {
- private WeakHashMap<Integer, WeakReference<Bitmap>> mBitmaps;
- private WeakHashMap<Integer, WeakReference<Drawable》> mDrawables;
-
- private boolean mActive = true;
-
- public ImageManager() {
- mBitmaps = new WeakHashMap<Integer, WeakReference<Bitmap>>();
- mDrawables = new WeakHashMap<Integer, WeakReference<Drawable>>();
- }
-
-
- public Bitmap getBitmap(int resource) {
- if (mActive) {
- if (!mBitmaps.containsKey(resource)) {
- mBitmaps.put(resource,
- new WeakReference<Bitmap>(BitmapFactory.decodeResource(MainActivity.getContext().getResources(), resource)));
- }
- return ((WeakReference<Bitmap>)mBitmaps.get(resource)).get();
- }
- return null;
- }
-
- public Drawable getDrawable(int resource) {
- if (mActive) {
- if (!mDrawables.containsKey(resource)) {
- mDrawables.put(resource, new WeakReference<Drawable>(getApplication().getResources().getDrawable(resource)));
- }
- return ((WeakReference<Drawable>)mDrawables.get(resource)).get();
- }
- return null;
- }
-
- public void recycleBitmaps() {
- Iterator itr = mBitmaps.entrySet().iterator();
- while (itr.hasNext()) {
- Map.Entry e = (Map.Entry)itr.next();
- ((WeakReference<Bitmap>) e.getValue()).get().recycle();
- }
- mBitmaps.clear();
- }
-
- public ImageManager setActive(boolean b) {
- mActive = b;
- return this;
- }
-
- public boolean isActive() {
- return mActive;
- }
- }
复制代码
在处理网络连接的时候,通常程序下开发,都会采用HTTP协议,而对应的在连接的时候,移动端就要做好对3G或者WIFI的检查连接
- private boolean isConnected(){
- ConnectivityManager mConnectivity = (ConnectivityManager) this.getSystemService(CONNECTIVITY_SERVICE);
- TelephonyManager mTelephony = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
-
- // 检查网络连接,如果无网络可用,就不需要进行连网操作等
- NetworkInfo info = mConnectivity.getActiveNetworkInfo();
- if (info == null ||
- !mConnectivity.getBackgroundDataSetting()) {
- return false;
- }
- //判断网络连接类型,只有在3G或wifi里进行一些数据更新。
- int netType = info.getType();
- int netSubtype = info.getSubtype();
- if (netType == ConnectivityManager.TYPE_WIFI) {
- return info.isConnected();
- } else if (netType == ConnectivityManager.TYPE_MOBILE
- && netSubtype == TelephonyManager.NETWORK_TYPE_UMTS
- && !mTelephony.isNetworkRoaming()) {
- return info.isConnected();
- } else {
- return false;
- }
- }
复制代码
对于一些Android项目,影响性能瓶颈的主要是Android自己内存管理机制问题,我们需要做什么? 缓存类
- public class FileCache {
-
- private File cacheDir;
- private static final int DEFAULT_DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
-
- public FileCache(Context context) {
- // 如果有SD卡则在SD卡中建一个LazyList的目录存放缓存的图片
- // 没有SD卡就放在系统的缓存目录中
- //cacheDir = new File(Environment.getExternalStorageDirectory(),"Cache_memory");
- context.getCacheDir();
- cacheDir = new File(context.getCacheDir(), "cache");
- if(!cacheDir.exists())
- {
- cacheDir.mkdirs();
- }
- }
-
- public static String hashKeyForDisk(String key) {
- String cacheKey;
- try {
- final MessageDigest mDigest = MessageDigest.getInstance("加密算法");
- mDigest.update(key.getBytes());
- cacheKey = bytesToHexString(mDigest.digest());
- } catch (NoSuchAlgorithmException e) {
- cacheKey = String.valueOf(key.hashCode());
- }
- return cacheKey;
- }
-
- private static String bytesToHexString(byte[] bytes) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < bytes.length; i++) {
- String hex = Integer.toHexString(0xFF & bytes[i]);
- if (hex.length() == 1) {
- sb.append('0');
- }
- sb.append(hex);
- }
- return sb.toString();
- }
-
- public File getFile(String url) {
- String filename = hashKeyForDisk(url);
- File f = new File(cacheDir, filename);
- return f;
- }
-
- public void clear() {
- File[] files = cacheDir.listFiles();
- if (files == null)
- return;
- for (File f : files)
- f.delete();
- }
-
- public void checkAndClear() {
- if (cacheDir != null) {
- if (cacheDir.length() > DEFAULT_DISK_CACHE_SIZE) {
- clear();
- }
- }
- }
-
- }
复制代码
释放内存,释放资源,是关键,图片异步加载更是一个层次,不要不注意警告,有时候警告也是一个关键
- public class ImageLoader {
-
- public final static int TYPE_HEAD = 1;
-
- private Activity activity;
- MemoryCache memoryCache = new MemoryCache();
- FileCache fileCache;
-
- private Map<ImageView, String> imageViews = Collections
- .synchronizedMap(new WeakHashMap<ImageView, String>());
- // 线程池
- ExecutorService executorService;
-
- private static final ThreadFactory sThreadFactory = new ThreadFactory() {
- private final AtomicInteger mCount = new AtomicInteger(1);
-
- public Thread newThread(Runnable r) {
- return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
- }
- };
-
- public ImageLoader(Context context) {
- this.activity = (Activity) context;
- fileCache = new FileCache(context);
- executorService = Executors.newFixedThreadPool(5, sThreadFactory);
- }
-
- // 最主要的方法
- public void DisplayImage(String url, ImageView imageView, int defaultId) {
- /* if (HQClubApplication.getInstance().getSaveingMode()) {
- imageView.setImageResource(defaultId);
- return;
- }*/
- imageViews.put(imageView, url);
- // 先从内存缓存中查找
- Bitmap bitmap = memoryCache.get(url);
- if (bitmap != null) {
- imageView.setImageBitmap(bitmap);
- } else {
- // 若没有的话则开启新线程加载图片
- queuePhoto(url, imageView, defaultId, 0);
- imageView.setImageResource(defaultId);
- }
- }
-
- // 最主要的方法
- public void DisplayImage(String url, ImageView imageView,
- int defaultId, int type) {
- /* if (HQClubApplication.getInstance().getSaveingMode()) {
- imageView.setImageResource(defaultId);
- return;
- }*/
- imageViews.put(imageView, url);
- // 先从内存缓存中查找
- Bitmap bitmap = memoryCache.get(url);
- if (bitmap != null) {
- imageView.setImageBitmap(bitmap);
- } else {
- // 若没有的话则开启新线程加载图片
- queuePhoto(url, imageView, defaultId, type);
- imageView.setImageResource(defaultId);
- }
- }
- private void queuePhoto(String url, ImageView imageView, int defaultId, int type) {
- PhotoToLoad p = new PhotoToLoad(url, imageView, defaultId, type);
- executorService.submit(new PhotosLoader(p));
- }
-
- private Bitmap getBitmap(String url) {
- File f = fileCache.getFile(url);
- // 先从文件缓存中查找是否有
- Bitmap b = decodeFile(f);
- if (b != null)
- return b;
-
- // 最后从指定的url中下载图片
- try {
- Bitmap bitmap = null;
- URL imageUrl = new URL(url);
- HttpURLConnection conn = (HttpURLConnection) imageUrl
- .openConnection();
- conn.setConnectTimeout(30000);
- conn.setReadTimeout(30000);
- conn.setInstanceFollowRedirects(true);
- InputStream is = conn.getInputStream();
- OutputStream os = new FileOutputStream(f);
- CopyStream(is, os);
- os.close();
- is.close();
- bitmap = decodeFile(f);
- return bitmap;
- } catch (Exception ex) {
- ex.printStackTrace();
- return null;
- }
- }
-
- // decode这个图片并且按比例缩放以减少内存消耗,虚拟机对每张图片的缓存大小也是有限制的
- private Bitmap decodeFile(File f) {
- try {
- // decode image size
- BitmapFactory.Options o = new BitmapFactory.Options();
- o.inJustDecodeBounds = true;
- BitmapFactory.decodeStream(new FileInputStream(f), null, o);
- // Find the correct scale value. It should be the power of 2.
- // final int REQUIRED_SIZE = 70;
- // int width_tmp = o.outWidth, height_tmp = o.outHeight;
- // int scale = 1;
- // while (true) {
- // if (width_tmp / 2 < REQUIRED_SIZE
- // || height_tmp / 2 < REQUIRED_SIZE)
- // break;
- // width_tmp /= 2;
- // height_tmp /= 2;
- // scale *= 2;
- // }
- // decode with inSampleSize
- BitmapFactory.Options o2 = new BitmapFactory.Options();
- //o2.inSampleSize = scale;
- return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
- } catch (FileNotFoundException e) {
- }
- return null;
- }
-
- // Task for the queue
- private class PhotoToLoad {
- public String url;
- public ImageView imageView;
- public int defaultId;
- public int type;
-
- public PhotoToLoad(String u, ImageView i, int d, int t) {
- url = u;
- imageView = i;
- defaultId = d;
- type = t;
- }
- }
-
- class PhotosLoader implements Runnable {
- PhotoToLoad photoToLoad;
-
- PhotosLoader(PhotoToLoad photoToLoad) {
- this.photoToLoad = photoToLoad;
- }
-
- @Override
- public void run() {
- if (imageViewReused(photoToLoad))
- return;
- if (TextUtils.isEmpty(photoToLoad.url)) {
- return;
- }
- Bitmap bmp = getBitmap(photoToLoad.url);
- if (photoToLoad.type == TYPE_HEAD) {
- //bmp = getRoundedCornerBitmap(bmp);
- }
- memoryCache.put(photoToLoad.url, bmp);
- if (imageViewReused(photoToLoad))
- return;
- BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
- // 更新的操作放在UI线程中
- activity.runOnUiThread(bd);
- }
- }
-
- /**
- * 防止图片错位
- *
- * @param photoToLoad
- * @return
- */
- boolean imageViewReused(PhotoToLoad photoToLoad) {
- String tag = imageViews.get(photoToLoad.imageView);
- if (tag == null || !tag.equals(photoToLoad.url))
- return true;
- return false;
- }
-
- // 用于在UI线程中更新界面
- class BitmapDisplayer implements Runnable {
- Bitmap bitmap;
- PhotoToLoad photoToLoad;
-
- public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
- bitmap = b;
- photoToLoad = p;
- }
-
- public void run() {
- if (imageViewReused(photoToLoad)) {
- return;
- }
- if (bitmap != null) {
- photoToLoad.imageView.setImageBitmap(bitmap);
- } else {
- photoToLoad.imageView.setImageResource(photoToLoad.defaultId);
- }
- }
- }
-
- public void clearCache() {
- memoryCache.clear();
- fileCache.clear();
- }
-
- public static void CopyStream(InputStream is, OutputStream os) {
- final int buffer_size = 1024;
- try {
- byte[] bytes = new byte[buffer_size];
- for (;;) {
- int count = is.read(bytes, 0, buffer_size);
- if (count == -1)
- break;
- os.write(bytes, 0, count);
- }
- } catch (Exception ex) {
- }
- }
-
- //圆角处理
- // public Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
- // Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
- // bitmap.getHeight(), Config.ARGB_8888);
- // Canvas canvas = new Canvas(output);
- // final int color = 0xff424242;
- // final Paint paint = new Paint();
- // final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
- // final RectF rectF = new RectF(rect);
- // float roundPx;
- // if(bitmap.getHeight()>70||bitmap.getWidth()>70){
- // roundPx = 15;
- // }else{
- // roundPx = 5;
- // }
- // paint.setAntiAlias(true);
- // canvas.drawARGB(0, 0, 0, 0);
- // paint.setColor(color);
- // canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
- // paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
- // canvas.drawBitmap(bitmap, rect, rect, paint);
- // return output;
- // }
- //
-
- }
复制代码
移动终端的资源有限,特别是在Android上,而资源的读取无疑来自两个方面:
- <font color="#ff0000">**</font><font color="#000000">电池优化是一门不可忽视的问题!</font>
复制代码
优化不仅源于程序,在虚拟机和原生库层面,Android同样进行了很多的优化! 在这边,我把内存泄漏的情况总结下:
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder vHolder = null;
- //如果convertView对象为空则创建新对象,不为空则复用
- if (convertView == null) {
- convertView = inflater.inflate(..., null);
- // 创建 ViewHodler 对象
- vHolder = new ViewHolder();
- vHolder.img= (ImageView) convertView.findViewById(...);
- vHolder.tv= (TextView) convertView
- .findViewById(...);
- // 将ViewHodler保存到Tag中
- convertView.setTag(vHolder);
- } else {
- //当convertView不为空时,通过getTag()得到View
- vHolder = (ViewHolder) convertView.getTag();
- }
- // 给对象赋值,修改显示的值
- vHolder.img.setImageBitmap(...);
- vHolder.tv.setText(...);
- return convertView;
- }
- //将显示的View 包装成类
- static class ViewHolder {
- TextView tv;
- ImageView img;
- }
复制代码
3.调用registerReceiver()后未调用unregisterReceiver(). (这个可以忽略)
4.
6.Context泄漏
1.使用Application这种Context类型。
2.注意对Context的引用不要超过它本身的生命周期。
3.慎重的使用“static”关键字。
4.Context里如果有线程,一定要在onDestroy()里及时停掉。
- private static Drawable sBackground;
- @Override
- protected void onCreate(Bundle state) {
- super.onCreate(state);
-
- TextView label = new TextView(this);
- label.setText("Leaks are bad");
-
- if (sBackground == null) {
- sBackground = getDrawable(R.drawable.large_bitmap);
- }
- label.setBackgroundDrawable(sBackground);
-
- setContentView(label);
- }
-
复制代码
在涉及到性能优化方面,内存是占据第一位的,而Android的垃圾收集中,内存泄漏和引用,在文档中,我们注意到一个典型的例子就是:屏幕旋转,activiity对象会有泄漏,很严重,却常常被忽略掉,毕竟在应用中占据内存的是activity,在Android中DDMS,可以使用Heap以及Allocation Tracker跟踪内存使用和分配情况去检测内存情况。 从android 3.0以上的版本中,可以检测到潜在的泄漏:1.activity泄漏;2.其他对象泄漏;3.对象没有关闭造成的泄漏; 通常下,使用strictMode类来检测内存泄漏
- public void onCreate() {
- if (DEVELOPER_MODE) {
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- .detectDiskReads()
- .detectDiskWrites()
- .detectNetwork() // or .detectAll() for all detectable problems
- .penaltyLog()
- .build());
- StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
- .detectLeakedSqlLiteObjects()
- .detectLeakedClosableObjects()
- .penaltyLog()
- .penaltyDeath()
- .build());
- }
- super.onCreate();
- }
复制代码
- public class MyApplication extends Application {
- @Override
- public void onCreate() {
- super.onCreate();
- StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
- builder.detectLeakedSqlLiteObjects();
- if(VERSION.SDK_INT >=Build.VERSION_CODES.HOMEYCOMB)
- {
- builder.detectLeakedSqlLiteObjects().detectLeakedSqlLiteObjects();
- }
- //或者可以简单的调用builder.detectAll();
- //采取措施
- builder.penaltyLog();//若有其他措施(如penaltyDeath())可以在这合并处理
- StrictMode.VmPolicy vmp = builder.build();
- StrictMode.setVmPolicy(vmp);
- }
- }
复制代码
转载自http://www.apkbus.com/forum.php?mod=viewthread&tid=157030&page=1&extra= 作者:清雨轩
|