公司有需求,需要将listview的全部内容生成一组图片,于是有了以下代码
public class ListViewToBitmap {
private ListView mListView;
private ListAdapter mAdapter;
private int childCount;
// 每页的项目数, 默认情况下,只是一页,但是极有可能导致oom异常
private int countPerPage = Integer.MAX_VALUE;
// 默认情况下,只是保存在文件中,不保存在内存中
private boolean inMemory = false;
private InMemoryCallBack inMemoryCallBack;
private boolean inFile = true;
private InFileCallBack inFileCallBack;
private Handler uiThreadHandler;
private static final int MEMORY_HANDLED = 1;
private static final int FILE_HANDLED = 2;
private List<Bitmap> memoryDatas = new ArrayList<>();
private List<String> filePaths = new ArrayList<>();
// 图片文件目录
private File filesDir;
private ListViewToBitmap(ListView listView) {
this(listView, Integer.MAX_VALUE);
}
private ListViewToBitmap(ListView listView, int count_per_page) {
mListView = listView;
mAdapter = mListView.getAdapter();
childCount = mAdapter.getCount();
countPerPage = count_per_page;
Context context = listView.getContext();
filesDir = context.getExternalCacheDir();
if (filesDir == null) {
filesDir = context.getCacheDir();
}
}
protected void setInMemory(InMemoryCallBack callBack) {
inMemory = true;
inMemoryCallBack = callBack;
}
protected void setInFile(InFileCallBack callBack) {
inFile = true;
inFileCallBack = callBack;
}
public void start() {
if (uiThreadHandler == null) {
uiThreadHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MEMORY_HANDLED:{
if (inMemory && inMemoryCallBack!= null) {
inMemoryCallBack.onSuccess(memoryDatas);
}
break;
}
case FILE_HANDLED:{
if (inFile && inFileCallBack != null) {
inFileCallBack.onSuccess(filePaths);
}
break;
}
}
}
};
}
new Thread() {
@Override
public void run() {
// 计算有多少页
int page = childCount / countPerPage;
if (childCount % countPerPage > 0) {
page += 1;
}
for (int pageIndex = 0; pageIndex < page; ++pageIndex) {
Bitmap bitmap = getBitmap(pageIndex);
if (inFile) {
String filepath = bitmapToFile(bitmap);
filePaths.add(filepath);
}
// 需要保存在内存中(非常容易出现oom)
if (inMemory) {
memoryDatas.add(bitmap);
} else {
// 及时清理内存才是正途
bitmap.recycle();
}
}
if (inFile) {
uiThreadHandler.sendEmptyMessage(FILE_HANDLED);
}
if (inMemory) {
uiThreadHandler.sendEmptyMessage(MEMORY_HANDLED);
}
}
}.start();
}
private String bitmapToFile(Bitmap bitmap) {
try {
File file = getFile();
file.createNewFile();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 30, bos);
bos.flush();
bos.close();
return file.getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private File getFile() {
File file = new File(filesDir, System.currentTimeMillis() + ".jpg");
if (file.exists()) {
return getFile();
}
else {
return file;
}
}
/**
* 获取每一页的bitmap
* @param page
* @return
*/
private Bitmap getBitmap(int page) {
int pageStart = page * countPerPage;
int pageEnd = pageStart + countPerPage > childCount ? childCount : pageStart + countPerPage;
View child;
int everyChildWidthMeasureSpec = View.MeasureSpec.makeMeasureSpec(mListView.getWidth(), View.MeasureSpec.EXACTLY);
int childHeightMeasureSpec;
int itemsHeight = 0;
List<Bitmap> itemBitmaps = new ArrayList<>();
// 获取到一页中,每个item的bitmap
for (int i = pageStart; i < pageEnd; ++i) {
child = mAdapter.getView(i, null, mListView);
childHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
child.measure(everyChildWidthMeasureSpec, childHeightMeasureSpec);
child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
child.setDrawingCacheEnabled(true);
child.buildDrawingCache();
itemBitmaps.add(child.getDrawingCache());
itemsHeight += child.getMeasuredHeight();
}
// 创建一个大的空白的bitmap, 用来保存一页的内容
Bitmap pageBitmap = Bitmap.createBitmap(mListView.getWidth(), itemsHeight, Bitmap.Config.RGB_565);
Canvas pageCanvas = new Canvas(pageBitmap);
Paint pagePaint = new Paint();
int x = 0;
int y = 0;
Bitmap bitmap;
// 逐步将一页的内容画进大的bitmap中
for (int i = 0; i < itemBitmaps.size(); ++i) {
bitmap = itemBitmaps.get(i);
pageCanvas.drawBitmap(bitmap, x, y, pagePaint);
y += bitmap.getHeight();
// 及时回收每一个item的内存
bitmap.recycle();
}
return pageBitmap;
}
public static class Builder {
private ListView listView;
private int count_per_page = Integer.MAX_VALUE;
private boolean inMemory;
private boolean inFile;
private InMemoryCallBack inMemoryCallBack;
private InFileCallBack inFileCallBack;
public Builder(ListView list) {
listView = list;
}
public Builder countPerPage(int cpp) {
count_per_page = cpp;
return this;
}
public Builder inMemory(InMemoryCallBack callBack) {
inMemory = true;
inMemoryCallBack = callBack;
return this;
}
public Builder inFile(InFileCallBack callBack) {
inFile = true;
inFileCallBack = callBack;
return this;
}
public ListViewToBitmap build() {
ListViewToBitmap listViewToBitmap = new ListViewToBitmap(listView, count_per_page);
if (inMemory) {
listViewToBitmap.setInMemory(inMemoryCallBack);
}
if (inFile) {
listViewToBitmap.setInFile(inFileCallBack);
}
return listViewToBitmap;
}
}
public interface InMemoryCallBack {
void onSuccess(List<Bitmap> bitmaps);
}
public interface InFileCallBack {
void onSuccess(List<String> filePaths);
}
}
主要目的是在工作线程里面执行分页操作,及时释放内存,避免oom
使用方法:
ListViewToBitmap listViewToBitmap = new ListViewToBitmap.Builder(lv)
.countPerPage(30)
.inFile(inFileCallBack)
.build();
listViewToBitmap.start();