最近多了一个安卓端读写Excel的需求,移动端的处理能力有限,而且谷歌并没有对应的支持,所以在网上搜索了很多框架,最终将视线定格在了xxl-excel框架,在Idea中run了一下,非常完美。
感谢大神的框架:xxl-excel
安卓代码详见:点击下载
Java代码:点击下载
下面展示一下Java读写Excel的情况:
写Excel:
读取Excel:
主要使用的是:poi 和poi-ooxml
所以突发奇想,能不能将其应用到安卓中进行文件读写,可惜并没有相关支持。
转念一想,原作者使用的是maven托管我这边直接在android studio中进行引入应该可以,所以便开始了又一次的踩坑之旅:
首先创建项目,接着导入依赖:
总共三个依赖:
implementation 'com.xuxueli:xxl-excel:1.1.1'
implementation 'org.apache.poi:poi:3.17'
implementation 'org.apache.poi:poi-ooxml:3.17'
导入之后便可以进行代码测试了,我这里模拟器版本是安卓4.4,所以没有添加动态权限申请,设备版本比较高的同学请自行添加哈。
页面很简单:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnImport"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="读取"/>
<Button
android:id="@+id/btnExport"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="导出"/>
</LinearLayout>
<TextView
android:id="@+id/tvShow"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
下面就是逻辑测试了,这里只做简单的调用:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String path = Environment.getExternalStorageDirectory().getPath();
final List<ShopDTO> shopDTOS = new ArrayList<>();
for (int i = 0; i < 10; i++) {
ShopDTO shopDTO = new ShopDTO(i, "test" + i);
shopDTOS.add(shopDTO);
}
//导出
findViewById(R.id.btnExport).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ExcelExportUtil.exportToFile(path + "/test.xlsx", shopDTOS);
}
});
//导入
findViewById(R.id.btnImport).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
List<Object> shopDatas = ExcelImportUtil.importExcel(path + "/test.xlsx", ShopDTO.class);
if (shopDatas == null) {
Toast.makeText(MainActivity.this, "暂无数据,请先导出!", Toast.LENGTH_SHORT).show();
return;
}
List<ShopDTO> shopDTOs = (List<ShopDTO>) (List) shopDatas;
StringBuffer stringBuffer = new StringBuffer();
for (ShopDTO shopDTO : shopDTOs) {
stringBuffer.append(shopDTO.toString() + "\n");
}
((TextView) findViewById(R.id.tvShow)).setText(stringBuffer.toString());
}
});
}
}
但是问题来了,报错:
65536报错,这个报错相比大家只要接触过大型项目都遇到过吧!解决方式:
转自其他博主博客:
第一步:在项目的app目录下的grade文件里面的defaultConfig闭包下添加: multiDexEnabled true
第二步:在dependencies下添加依赖 compile 'com.android.support:multidex:1.0.0'
第三步:在你自定义继承于Application的类里(这步都不用解释吧,如果我没猜错,你的命名跟我一样MyApplication)重写protected void attachBaseContext(Context base)方法,调用 MultiDex.install(this)初始化
日常报错:
简单百度了一下,应该是因为awt支持的原因,安卓没有Java对应的awt包。
所以我这边拉取博主的Demo,注释掉了所有和awt相关的样式:
package com.marsjiang.myapplication.utils;
import com.xuxueli.poi.excel.annotation.ExcelField;
import com.xuxueli.poi.excel.annotation.ExcelSheet;
import com.xuxueli.poi.excel.util.FieldReflectionUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
/**
* Excel导出工具
*
* @author xuxueli 2017-09-08 22:27:20
*/
public class ExcelExportUtil {
private static Logger logger = LoggerFactory.getLogger(ExcelExportUtil.class);
/**
* 导出Excel对象
*
* @param sheetDataListArr Excel数据
* @return
*/
public static Workbook exportWorkbook(List<?>... sheetDataListArr){
// data array valid
if (sheetDataListArr==null || sheetDataListArr.length==0) {
throw new RuntimeException(">>>>>>>>>>> xxl-excel error, data array can not be empty.");
}
// book (HSSFWorkbook=2003/xls、XSSFWorkbook=2007/xlsx)
Workbook workbook = new HSSFWorkbook();
// sheet
for (List<?> dataList: sheetDataListArr) {
makeSheet(workbook, dataList);
}
return workbook;
}
private static void makeSheet(Workbook workbook, List<?> sheetDataList){
// data
if (sheetDataList==null || sheetDataList.size()==0) {
throw new RuntimeException(">>>>>>>>>>> xxl-excel error, data can not be empty.");
}
// sheet
Class<?> sheetClass = sheetDataList.get(0).getClass();
ExcelSheet excelSheet = sheetClass.getAnnotation(ExcelSheet.class);
String sheetName = sheetDataList.get(0).getClass().getSimpleName();
int headColorIndex = -1;
if (excelSheet != null) {
if (excelSheet.name()!=null && excelSheet.name().trim().length()>0) {
sheetName = excelSheet.name().trim();
}
// headColorIndex = excelSheet.headColor().getIndex();
}
Sheet existSheet = workbook.getSheet(sheetName);
if (existSheet != null) {
for (int i = 2; i <= 1000; i++) {
String newSheetName = sheetName.concat(String.valueOf(i)); // avoid sheetName repetition
existSheet = workbook.getSheet(newSheetName);
if (existSheet == null) {
sheetName = newSheetName;
break;
} else {
continue;
}
}
}
Sheet sheet = workbook.createSheet(sheetName);
// sheet field
List<Field> fields = new ArrayList<Field>();
if (sheetClass.getDeclaredFields()!=null && sheetClass.getDeclaredFields().length>0) {
for (Field field: sheetClass.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
fields.add(field);
}
}
if (fields==null || fields.size()==0) {
throw new RuntimeException(">>>>>>>>>>> xxl-excel error, data field can not be empty.");
}
// sheet header row
CellStyle[] fieldDataStyleArr = new CellStyle[fields.size()];
int[] fieldWidthArr = new int[fields.size()];
Row headRow = sheet.createRow(0);
for (int i = 0; i < fields.size(); i++) {
// field
Field field = fields.get(i);
ExcelField excelField = field.getAnnotation(ExcelField.class);
String fieldName = field.getName();
int fieldWidth = 0;
HorizontalAlignment align = null;
if (excelField != null) {
if (excelField.name()!=null && excelField.name().trim().length()>0) {
fieldName = excelField.name().trim();
}
fieldWidth = excelField.width();
align = excelField.align();
}
// field width
fieldWidthArr[i] = fieldWidth;
// head-style、field-data-style
// CellStyle fieldDataStyle = workbook.createCellStyle();
// if (align != null) {
// fieldDataStyle.setAlignment(align);
// }
// fieldDataStyleArr[i] = fieldDataStyle;
//
// CellStyle headStyle = workbook.createCellStyle();
// headStyle.cloneStyleFrom(fieldDataStyle);
// if (headColorIndex > -1) {
// headStyle.setFillForegroundColor((short) headColorIndex);
// headStyle.setFillBackgroundColor((short) headColorIndex);
// headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// }
// head-field data
Cell cellX = headRow.createCell(i, CellType.STRING);
// cellX.setCellStyle(headStyle);
cellX.setCellValue(String.valueOf(fieldName));
}
// sheet data rows
for (int dataIndex = 0; dataIndex < sheetDataList.size(); dataIndex++) {
int rowIndex = dataIndex+1;
Object rowData = sheetDataList.get(dataIndex);
Row rowX = sheet.createRow(rowIndex);
for (int i = 0; i < fields.size(); i++) {
Field field = fields.get(i);
try {
field.setAccessible(true);
Object fieldValue = field.get(rowData);
String fieldValueString = FieldReflectionUtil.formatValue(field, fieldValue);
Cell cellX = rowX.createCell(i, CellType.STRING);
cellX.setCellValue(fieldValueString);
cellX.setCellStyle(fieldDataStyleArr[i]);
} catch (IllegalAccessException e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
}
// sheet finally
for (int i = 0; i < fields.size(); i++) {
int fieldWidth = fieldWidthArr[i];
if (fieldWidth > 0) {
sheet.setColumnWidth(i, fieldWidth);
} else {
// sheet.autoSizeColumn((short)i);
}
}
}
/**
* 导出Excel文件到磁盘
*
* @param filePath
* @param sheetDataListArr 数据,可变参数,如多个参数则代表导出多张Sheet
*/
public static void exportToFile(String filePath, List<?>... sheetDataListArr){
// workbook
Workbook workbook = exportWorkbook(sheetDataListArr);
FileOutputStream fileOutputStream = null;
try {
// workbook 2 FileOutputStream
fileOutputStream = new FileOutputStream(filePath);
workbook.write(fileOutputStream);
// flush
fileOutputStream.flush();
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
} finally {
try {
if (fileOutputStream!=null) {
fileOutputStream.close();
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
}
/**
* 导出Excel字节数据
*
* @param sheetDataListArr
* @return
*/
public static byte[] exportToBytes(List<?>... sheetDataListArr){
// workbook
Workbook workbook = exportWorkbook(sheetDataListArr);
ByteArrayOutputStream byteArrayOutputStream = null;
byte[] result = null;
try {
// workbook 2 ByteArrayOutputStream
byteArrayOutputStream = new ByteArrayOutputStream();
workbook.write(byteArrayOutputStream);
// flush
byteArrayOutputStream.flush();
result = byteArrayOutputStream.toByteArray();
return result;
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
} finally {
try {
if (byteArrayOutputStream != null) {
byteArrayOutputStream.close();
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
}
}
接着引用我们重写的类:
import com.marsjiang.myapplication.utils.ExcelExportUtil;
import com.marsjiang.myapplication.utils.ExcelImportUtil;
然后运行一下:
成功生成了xlsx文件,再来读取一下: