OOM异常

堆内存用于存储实例对象,当程序不断创建对象,并且对象都有引用指向,那么垃圾回收机制就不会清理这些对象,当对象多到挤满堆内存的上限后,就产生OOM异常。Android系统为每个应用程序使用的内存设置了一个上限。这个上限值可以用下面的方法取得: long maxSize = Runtime.getRuntime().maxMemory();

OOM异常通常分为下面几种情况:
1.内存泄漏导致的OOM:new出来的很多对象已经不需要了,但仍然有引用指向,所以垃圾回收机制无法回收。
    其场景类似于:创建了一个Handler,并且执行了一个Delay的任务没有完成,此时拥有此Handler对象的宿主对象亦不能被回收。
    或者,static的方法或成员太多,被外部使用,而外部的牵引对象没有对其进行释放,那么整个static的类都不会被释放,也就造成内存泄漏。
2.内存溢出:new出来的对象都是需要的,但堆内存太小装不下了。
  如在一个GridView中显示图片,如果不压缩图片,采用为1920*1080的32位图片,每个将占用1920*1080*4=7MB内存,如此大的图片,只能存储几张,超出即可导致内存溢出。
3.关于 Bitmap 引起的泄漏,网上还有另一种说法:
  一个进程的内存可以由2个部分组成:java使用内存,C使用内存,这两个内存的和必须小于16M(假设为这么多),不然就会出现大家熟悉的OOM,这个就是第一种OOM的情况。
  一旦内存分配给Java后,以后这块内存即使释放后,也只能给Java的使用,这个估计和java虚拟机里把内存分成好几块进行缓存的原因有关。
  所以如果Java突然占用了一个大块内存,即使很快释放了,C代码也无法使用,而Bitmap的生成是通过malloc进行内存分配的,占用的是C的内存,如果Bitmap需要的内存大于C可用内存也会导致OOM。

避免OOM

对于java中不再使用的资源需要尽快的释放,即设置成null。
尽量少用static方法和static成员。
对于不再使用的bitmap应该手动调用recycle方法,并且设置成null。图片还应尽量使用软引用方式,这样可以加快垃圾回收。

LruCache

内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。其中最核心的类是LruCache,这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。

为了能够选择一个合适的缓存大小给LruCache, 有以下多个因素应该放入考虑范围内,例如:

1.设备可以为每个应用程序可分配多大的内存。
2.屏幕上一次最多需要显示多少个图片,有多少图片需要进行预加载,因为有可能很快也会显示在屏幕上。
3.屏幕大小和分辨率。一个超高分辨率的设备比起一个较低分辨率的设备,在持有相同数量图片的时候,需要更大的缓存空间。
4.图片的尺寸和大小,还有每张图片会占据多少内存空间。
5.图片被访问的频率有多高。如某些图片的访问频率比其它图片要高,应该使用多个 LruCache 对象来区分不同组的图片。
6.维持好数量和质量之间的平衡。存储多个低像素的图片,而在后台线程加载高像素的图片会更有效。

并没有一个指定的缓存大小可以满足所有的应用程序,应该去分析程序内存的使用情况,然后制定出一个合适的解决方案。
一个太小的缓存空间,有可能造成图片频繁地被释放和重新加载,这并没有好处。而一个太大的缓存空间,则更有可能会引起 java.lang.OutOfMemory 的异常,因为 LruCache 中的强引用不能被释放,而程序又需要内存。

使用LruCache,需要重写sizeOf方法,返回占用的内存大小。下面是一个图片缓存的实现:

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import android.util.Log;public class BitmapCache {private static final String TAG = "debug";private LruCache<String, Bitmap> mBitmapCache;public BitmapCache() {// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。long maxSize = Runtime.getRuntime().maxMemory();Log.d(TAG, "maxMemory size = " + toMB(maxSize));// LruCache 使用的缓存值,使用系统分配给应用程序大小的 1/8maxSize = maxSize >> 3;// maxSize = 1 << 1024 << 1024;Log.d(TAG, "cache used maxSize = " + toMB(maxSize));mBitmapCache = new LruCache<String, Bitmap>((int) maxSize) {@Overrideprotected int sizeOf(String key, Bitmap value) {return value.getByteCount();}};}public void add(String key, Bitmap value) {mBitmapCache.put(key, value);}public void remove(String key) {mBitmapCache.remove(key);}public Bitmap get(String key) {return mBitmapCache.get(key);}public boolean containsKey(String key) {return mBitmapCache.get(key) != null;}public static long toMB(long byteOfSize) {return byteOfSize >> 20;}
}

使用缓存技术从网络下载图片显示的实例类

BitmapDownloadTask 类从网络下载图片,并将其解析为适配ImageView大小的格式,以减少对内存的占用,并取得一个良好的显示效果。

import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;public class BitmapDownloadTask extends AsyncTask<Void, Void, Bitmap> {private static final String TAG = "debug";private String mImgUrl;private SoftReference<ImageView> mImageViewSoftReference;private BitmapCache mBitmapCache;private List<BitmapDownloadTask> mTaskList;private int mReqWidth;private int mReqHeight;public BitmapDownloadTask(BitmapCache bitmapCache, List<BitmapDownloadTask> tasks, ImageView imgView, String url) {mBitmapCache = bitmapCache;mTaskList = tasks;mImageViewSoftReference = new SoftReference<>(imgView);mImgUrl = url;mReqWidth = imgView.getMeasuredWidth();mReqHeight = imgView.getMeasuredHeight();}@Overrideprotected Bitmap doInBackground(Void... params) {Bitmap bitmap;HttpURLConnection conn = null;try {URL url = new URL(mImgUrl);conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5000);conn.setReadTimeout(5000);bitmap = BitmapTools.decodeSampledBitmapFromInputStream(conn.getInputStream(), mReqWidth, mReqHeight);Log.d(TAG, "bitmap size: " + bitmap.getWidth() + "/" + bitmap.getHeight() + ", " + bitmap.getConfig().name() + ", " + format(bitmap.getByteCount()));} catch (Exception e) {Log.e(TAG, "", e);bitmap = null;} finally {if (conn != null)conn.disconnect();}return bitmap;}@Overrideprotected void onPostExecute(Bitmap bitmap) {mTaskList.remove(this);if (bitmap != null) {mBitmapCache.add(mImgUrl, bitmap);}ImageView imgView = mImageViewSoftReference.get();if (isCancelled() || imgView == null || imgView.getTag() != mImgUrl) {bitmap = null;}if (bitmap != null) {imgView.setImageBitmap(bitmap);}super.onPostExecute(bitmap);}private String format(long byteOfSize) {long KB = byteOfSize >> 10;long MB = KB >> 10;if (MB != 0) {return MB + " MB";}return KB + " KB";}
}

public class BitmapTools {private static final String TAG = "debug";public static class Size {public Size(int width, int height) {this.width = width;this.height = height;}public void resize(int width, int height) {this.width = width;this.height = height;}public int getWidth() {return width;}public int getHeight() {return height;}@Overridepublic boolean equals(Object o) {if (this == o)return true;if (o == null || getClass() != o.getClass())return false;Size size = (Size) o;if (width != size.width)return false;return height == size.height;}@Overridepublic int hashCode() {int result = width;result = 31 * result + height;return result;}@Overridepublic String toString() {return "Size{" + "width=" + width + ", height=" + height + '}';}private int width;private int height;}public static Bitmap decodeSampledBitmapFromPath(String pathName, int reqWidth, int reqHeight) {// First decode with inJustDecodeBounds=true to check dimensionsBitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;BitmapFactory.decodeFile(pathName, opts);// Calculate inSampleSizeopts.inSampleSize = calculateInSampleSize(opts, reqWidth, reqHeight);// Decode bitmap with inSampleSize setopts.inJustDecodeBounds = false;return BitmapFactory.decodeFile(pathName, opts);}public static Bitmap decodeSampledBitmapFromData(byte[] data, int reqWidth, int reqHeight) {// First decode with inJustDecodeBounds=true to check dimensionsBitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;BitmapFactory.decodeByteArray(data, 0, data.length, opts);// Calculate inSampleSizeopts.inSampleSize = calculateInSampleSize(opts, reqWidth, reqHeight);// Decode bitmap with inSampleSize setopts.inJustDecodeBounds = false;return BitmapFactory.decodeByteArray(data, 0, data.length, opts);}public static Bitmap decodeSampledBitmapFromResource(Resources res, int id, int reqWidth, int reqHeight) {// First decode with inJustDecodeBounds=true to check dimensionsBitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;BitmapFactory.decodeResource(res, id, opts);// Calculate inSampleSizeopts.inSampleSize = calculateInSampleSize(opts, reqWidth, reqHeight);// Decode bitmap with inSampleSize setopts.inJustDecodeBounds = false;return BitmapFactory.decodeResource(res, id, opts);}public static Bitmap decodeSampledBitmapFromInputStream(InputStream is, int reqWidth, int reqHeight) {Bitmap bitmap = BitmapFactory.decodeStream(is);if (bitmap == null)return null;// Log.d(TAG, "req size: " + reqWidth + ", " + reqHeight);// Log.d(TAG, "bitmap size: " + bitmap.getWidth() + ", " + bitmap.getHeight());if (bitmap.getWidth() > reqWidth || bitmap.getHeight() > reqHeight) {Size srcSize = new Size(bitmap.getWidth(), bitmap.getHeight());Size reqSize = new Size(reqWidth, reqHeight);Size newSize = calculateNewSize(srcSize, reqSize);bitmap = Bitmap.createScaledBitmap(bitmap, newSize.getWidth(), newSize.getHeight(), false);}return bitmap;}public static Size calculateNewSize(Size srcSize, Size reqSize) {int newWidth;int newHeight;if (srcSize.getWidth() > srcSize.getHeight()) {newWidth = reqSize.getWidth();newHeight = newWidth * srcSize.getHeight() / srcSize.getWidth();} else {newHeight = reqSize.getHeight();newWidth = newHeight * srcSize.getWidth() / srcSize.getHeight();}return new Size(newWidth, newHeight);}public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {// Raw height and width of imagefinal int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {final int halfHeight = height / 2;final int halfWidth = width / 2;// Calculate the largest inSampleSize value that is a power of 2 and// keeps both height and width larger than the requested height and// width.while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {inSampleSize *= 2;}}Log.d(TAG, "inSampleSize=" + inSampleSize);return inSampleSize;}
}

Activity类,在滑动时取消所有的任务,没有滑动时自动加载可见范围内的所有图片,以避免加载时滑动产生卡顿的问题。

public class LruAcy extends AppCompatActivity {private static final String TAG = "debug";private BitmapCache mBitmapCache;private List<BitmapDownloadTask> mBitmapDownloadTasks;private GridView mImageWall;private BaseAdapter mAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.acy_lru);mBitmapCache = new BitmapCache();mBitmapDownloadTasks = new ArrayList<>();mImageWall = (GridView) findViewById(R.id.image_wall);mAdapter = new BaseAdapter(this);mImageWall.setOnScrollListener(mOnScrollListener);mImageWall.setAdapter(mAdapter);}@Overrideprotected void onDestroy() {super.onDestroy();cancelAll();}private void setImageView(String url, ImageView imgView) {Bitmap bitmap = mBitmapCache.get(url);if (bitmap == null) {imgView.setImageResource(R.mipmap.ic_launcher);} else {imgView.setImageBitmap(bitmap);}}private void cancelAll() {for (BitmapDownloadTask task : mBitmapDownloadTasks) {task.cancel(true);}mBitmapDownloadTasks.clear();}private void loadBitmaps(int firstVisibleItem, int visibleItemCount) {try {for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {String imageUrl = ImageUrls.IMAGE_URLS[i];Bitmap bitmap = mBitmapCache.get(imageUrl);ImageView imageView = (ImageView) mImageWall.findViewWithTag(imageUrl);if (imageView == null)continue;// Log.d(TAG, "bitmap=" + bitmap + ", imageView=" + imageView);if (bitmap == null) {BitmapDownloadTask task = new BitmapDownloadTask(mBitmapCache, mBitmapDownloadTasks, imageView,imageUrl);mBitmapDownloadTasks.add(task);task.execute();} else {imageView.setImageBitmap(bitmap);}}} catch (Exception e) {e.printStackTrace();}}private AbsListView.OnScrollListener mOnScrollListener = new AbsListView.OnScrollListener() {private boolean mIsFirstRun = true;private int firstVisibleItem;private int visibleItemCount;@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if (scrollState == SCROLL_STATE_IDLE) {loadBitmaps(firstVisibleItem, visibleItemCount);} else {cancelAll();}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {this.firstVisibleItem = firstVisibleItem;this.visibleItemCount = visibleItemCount;if (mIsFirstRun && totalItemCount > 0) {mIsFirstRun = false;loadBitmaps(firstVisibleItem, visibleItemCount);}}};private class BaseAdapter extends android.widget.BaseAdapter {private LayoutInflater mInflater;public BaseAdapter(Context context) {mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);}@Overridepublic int getCount() {return ImageUrls.IMAGE_URLS.length;}@Overridepublic String getItem(int position) {return ImageUrls.IMAGE_URLS[position];}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = mInflater.inflate(R.layout.image_layout, parent, false);}String url = getItem(position);ImageView img = (ImageView) convertView.findViewById(R.id.img);img.setTag(url);setImageView(url, img);return convertView;}}
}

界面布局 acy_lru.xml image_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.john.webapp.LruAcy"><GridViewandroid:id="@+id/image_wall"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:horizontalSpacing="5dp"android:numColumns="4"android:verticalSpacing="5dp"/></RelativeLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/img"android:layout_width="100dp"android:layout_height="100dp"android:scaleType="fitXY"/></LinearLayout>

测试使用的Url

public class ImageUrls {public final static String[] IMAGE_URLS = new String[]{"https://img-my.csdn.net/uploads/201309/01/1378037235_3453.jpg","https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg","https://img-my.csdn.net/uploads/201309/01/1378037235_9280.jpg","https://img-my.csdn.net/uploads/201309/01/1378037234_3539.jpg","https://img-my.csdn.net/uploads/201309/01/1378037234_6318.jpg","https://img-my.csdn.net/uploads/201309/01/1378037194_2965.jpg","https://img-my.csdn.net/uploads/201309/01/1378037193_1687.jpg","https://img-my.csdn.net/uploads/201309/01/1378037193_1286.jpg","https://img-my.csdn.net/uploads/201309/01/1378037192_8379.jpg","https://img-my.csdn.net/uploads/201309/01/1378037178_9374.jpg","https://img-my.csdn.net/uploads/201309/01/1378037177_1254.jpg","https://img-my.csdn.net/uploads/201309/01/1378037177_6203.jpg","https://img-my.csdn.net/uploads/201309/01/1378037152_6352.jpg","https://img-my.csdn.net/uploads/201309/01/1378037151_9565.jpg","https://img-my.csdn.net/uploads/201309/01/1378037151_7904.jpg","https://img-my.csdn.net/uploads/201309/01/1378037148_7104.jpg","https://img-my.csdn.net/uploads/201309/01/1378037129_8825.jpg","https://img-my.csdn.net/uploads/201309/01/1378037128_5291.jpg","https://img-my.csdn.net/uploads/201309/01/1378037128_3531.jpg","https://img-my.csdn.net/uploads/201309/01/1378037127_1085.jpg","https://img-my.csdn.net/uploads/201309/01/1378037095_7515.jpg","https://img-my.csdn.net/uploads/201309/01/1378037094_8001.jpg","https://img-my.csdn.net/uploads/201309/01/1378037093_7168.jpg","https://img-my.csdn.net/uploads/201309/01/1378037091_4950.jpg","https://img-my.csdn.net/uploads/201308/31/1377949643_6410.jpg","https://img-my.csdn.net/uploads/201308/31/1377949642_6939.jpg","https://img-my.csdn.net/uploads/201308/31/1377949630_4505.jpg","https://img-my.csdn.net/uploads/201308/31/1377949630_4593.jpg","https://img-my.csdn.net/uploads/201308/31/1377949629_7309.jpg","https://img-my.csdn.net/uploads/201308/31/1377949629_8247.jpg","https://img-my.csdn.net/uploads/201308/31/1377949615_1986.jpg","https://img-my.csdn.net/uploads/201308/31/1377949614_8482.jpg","https://img-my.csdn.net/uploads/201308/31/1377949614_3743.jpg","https://img-my.csdn.net/uploads/201308/31/1377949614_4199.jpg","https://img-my.csdn.net/uploads/201308/31/1377949599_3416.jpg","https://img-my.csdn.net/uploads/201308/31/1377949599_5269.jpg","https://img-my.csdn.net/uploads/201308/31/1377949598_7858.jpg","https://img-my.csdn.net/uploads/201308/31/1377949598_9982.jpg","https://img-my.csdn.net/uploads/201308/31/1377949578_2770.jpg","https://img-my.csdn.net/uploads/201308/31/1377949578_8744.jpg","https://img-my.csdn.net/uploads/201308/31/1377949577_5210.jpg","https://img-my.csdn.net/uploads/201308/31/1377949577_1998.jpg","https://img-my.csdn.net/uploads/201308/31/1377949482_8813.jpg","https://img-my.csdn.net/uploads/201308/31/1377949481_6577.jpg","https://img-my.csdn.net/uploads/201308/31/1377949480_4490.jpg","https://img-my.csdn.net/uploads/201308/31/1377949455_6792.jpg","https://img-my.csdn.net/uploads/201308/31/1377949455_6345.jpg","https://img-my.csdn.net/uploads/201308/31/1377949442_4553.jpg","https://img-my.csdn.net/uploads/201308/31/1377949441_8987.jpg","https://img-my.csdn.net/uploads/201308/31/1377949441_5454.jpg","https://img-my.csdn.net/uploads/201308/31/1377949454_6367.jpg","https://img-my.csdn.net/uploads/201308/31/1377949442_4562.jpg"};
}

转载于:https://www.cnblogs.com/diysoul/p/5597346.html

LruCache:从网络加载图片缓存实例相关推荐

  1. iOS网络加载图片缓存策略之ASIDownloadCache缓存优化

    iOS网络加载图片缓存策略之ASIDownloadCache缓存优化 在我们实际工程中,很多情况需要从网络上加载图片,然后将图片在imageview中显示出来,但每次都要从网络上请求,会严重影响用户体 ...

  2. Android:ViewPager详解(异步网络加载图片,带图片缓存,并带导航小圆点)

    android 应用中,如欢迎指引页面, 和图片轮播功能, 或者更多的内容在一页显示不了,要分成多个页面,这时候viewpager是很好用的. 首先看下效果: 下面是一个例子,带异步网络加载图片,并带 ...

  3. Flutter Image从网络加载图片刷新、强制重新渲染

    Flutter自带的Image.network()从网络加载图片后,如果服务器上的图片改变了,但是url没变,就算使用setState进行rebuild,图片也不会跟着更新.这是因为Image自带了c ...

  4. Android的轮播图Banner之本地加载和网络加载图片(含demo)

    前言 关于轮播图 我个人是比较喜欢 闲来无事的时候 可以整理自己的照片 做一个demo 看看动态的效果 挺不错的! 每个App也基本都有一些广告位置 只要打开这个页面就会无限轮播广告图片 看多了我们也 ...

  5. Android实现异步从网络加载图片列表

     博文出处:http://blog.csdn.net/carterjin/article/details/7995935 有时会有在加载ListView的时候,包含用户头像或其他需要到网络获取的图 ...

  6. Android简易实战教程--第三十二话《使用Lrucache和NetworkImageView加载图片》

    转载本专栏每一篇博客请注明转载出处地址,尊重原创.此博客转载链接地址:小杨的博客    http://blog.csdn.net/qq_32059827/article/details/5279131 ...

  7. Android循环滚动广告条的完美实现,封装方便,平滑过渡,从网络加载图片,点击广告进入对应网址

    关注finddreams,一起分享,一起进步: http://blog.csdn.net/finddreams/article/details/44619589 今天给大家带来一点干货,就是横向循环滚 ...

  8. 登录圆形头像之网络加载与缓存到本地

    Android开发中常常有用户头像显示,似乎大多数都是圆形显示,如果每次加载网络头像,会频繁的请求网络,所以本文主要说的是登录时的头像网络加载和缓存到本地,以便于下次加载时直接从本地获取即可. 效果图 ...

  9. 使用自定义的item、Adapter和AsyncTask、第三方开源框架PullToRefresh联合使用实现自定义的下拉列表(从网络加载图片显示在item中的ImageView)...

    AsyncTask使用方法详情:http://www.cnblogs.com/zzw1994/p/4959949.html 下拉开源框架PullToRefresh使用方法和下载详情:http://ww ...

最新文章

  1. [云炬学英语]每日一句2020.8.26
  2. python二级多少分过_python二级操作题与分析(2)
  3. 【Libevent】Libevent学习笔记(一):简介和安装
  4. VM虚拟机里怎么安装ubuntu-16.04.5-desktop-amd64.iso
  5. c语言数组如何把一串数字存入数组_C语言 指针 (三)指针数组与数组指针
  6. Python 数据结构与算法——图(Graph)
  7. python是什么类型的编程语言-python是什么编程语言
  8. java 获取本机ip地址吗_java 获取本机ip地址
  9. 1999-2019,互联网失落者
  10. NR小区搜索(一)SSB
  11. 基于Spine动画的AVATAR换装系统优化
  12. 怎么删除TEMP文件夹
  13. mezzanine安装(python2.7+nginx+mysql+supervisor)
  14. 视频号拍摄技巧和制作方法有哪些?
  15. 在Photoshop中设计Web 2.0标签/徽章
  16. python非技术面试题宝典
  17. C# 线程的挂起与唤醒 (AutoResetEvent,ManualResetEvent)
  18. 【Matlab仿真模型】短时交通流量预测模型
  19. 利用Python进行数据分析笔记-pandas建模(Patsy篇)
  20. 【微信小程序】判断手机号是否合法

热门文章

  1. 行波iq调制器_低功率IQ调制器的基带设计实例—电路精选(1)
  2. 23 年后来自生命溪流的回响 — FF7 Remake 音乐深度解析
  3. 有关UNLIMITED TABLESPACE权限
  4. css : 使用浮动实现左右各放一个元素时很容易犯的错误
  5. Android_(菜单)选项菜单
  6. 命令行方法查看和设置环境变量
  7. CSS 空中飘动的云动画
  8. CentOS7搭建hadoop2.6.4+HBase1.1.6
  9. 从网页(WEB)登录SAP
  10. JS中的HTML片段