安卓开发-物理按键监听事件+POI和EasyExcel
本次项目需要对物理按键进行监听,并且要读取和写入数据到csv文件中,学习的过程中做一点记录,内容包含了安卓中物理按键的监听事件和阿帕奇的POI对excel的操作代码,以及阿里巴巴的EasyExcel对excel的操作代码。相对来说POI较为复杂,但是比较基础,easyExcel一行代码就能搞定文件的读取和写入,但是较为难理解。
监听返回键(🔙)
第一种方法:通过重写onBackPressed方法实现
/**super.onBackPressed()会自动调用finish()方法,关闭当前Activity。
*/
@Override
public void onBackPressed(){
super.onBackPressed();
Toast.makeText(this,TAG,Toast.LENGTH_SHORT).show();
}
//onBackPressed()提供的功能优先,它这是再退出之前通知onBackPressed()方法,并布恩那个改变用户原来的行为。
back键
Android的程序无需刻意的去退出,当你一按下手机的back键的时候,系统会默认调用程序栈中最上层Activity的Destroy()方法来, 销毁当前Activity。当此Activity又被其它Activity启动起来的时候,会重新调用OnCreate()方法进行创建,当栈中所有 Activity都弹出结束后,应用也就随之结束了.如果说程序中存在service之类的,则可以在恰当的位置监听处理下也就可以了。
Back按键默认把当前Activity给finish掉,Home按键只是把Activity给onStop掉(destory)。
利用onKeyDown()方法,实现
@Override
public boolean onKeyDown(){
if(keyCode == keyEvent.KEYCODE_BACK){
Toast.makeText(this,TAG,Toast.LENGTH_SHORT()).show();
return false;
}else{
return super.onKeyDown(keyCode,event);
}
}
//onKeyDown方法返回true表示退出,返回false便不退出。
通过跳转来实现退出
@Overide
public boolean onKeyDown(int keyCode,KeyEvent event){
if(keyCode == KetEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}
return supper.onKeyDown(keyCode,event);
}
通过onKeyDown实现“再按一次返回退出程序的功能”
private long exitTime = 0;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){
if((System.currentTimeMillis()-exitTime) > 2000){
Toast.makeText(getApplicationContext(), "再按一次退出程序", Toast.LENGTH_SHORT).show();
exitTime = System.currentTimeMillis();
} else {
finish();
System.exit(0);
}
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* 重写onKeyDown方法可以拦截系统默认的处理
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if (keyCode == KeyEvent.KEYCODE_BACK) {
Toast.makeText(this, "后退键", Toast.LENGTH_SHORT).show();
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
Toast.makeText(this, "声音+", Toast.LENGTH_SHORT).show();
return false;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
Toast.makeText(this, "声音-", Toast.LENGTH_SHORT).show();
return false;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
Toast.makeText(this, "静音", Toast.LENGTH_SHORT).show();
return false;
} else if (keyCode == KeyEvent.KEYCODE_HOME) {
Toast.makeText(this, "Home", Toast.LENGTH_SHORT).show();
return true;
}
return super.onKeyDown(keyCode, event);
}
注意返回值:如果是true,就会屏蔽掉系统物理按键原来的功能,如果为false,系统原来的功能不会被屏蔽。
implementation ‘joda-time:joda-time:2.11.2’ 日期格式化工具,方便日期的调试
POI和POI-Excel
读跟写:IO相关的知识。使用原生IO进行读写也是可以,但是比较麻烦。
POI:开放式源码函数库,POI提供API给java程序员对Office格式档案读和写的功能。
基本功能:
- HSSF:提供读写Excel格式档案的功能 03版 65535行
- XSSF:提供读写Excel OOXML格式档案的功能。 07版 不限制行数
- HWPF:提供读写Word格式档案的功能。
- HSLF:提供PPT读写的功能。
- HDGF:提供Viso格式档案的功能。
POI相对有点麻烦。量比较大的时候可能会出现异常。
内存:POI会一次性先加载到内存,再写入到文件。如果数据较大,就会产生内存溢出。
java:万物皆对象
excel中的对象:
- 工作簿:
- 工作表:
- 行:
- 列:
public void testWrite03(){
//创建一个工作簿
Workbook workbook = new HSSFWorkbook();
//创建一个工作表
Sheet sheet = workbook.creatSheet("狂神观众统计表");
//创建一行
Row row = sheet.creatRow(0);
//创建单元格(列)
Cell cell = row.createCell(0);
cell.setCellValue("今日新增观众");
Cell cell1 = row.createCell(1);
cell1.setCellValue(666);
//构建流生成一张表 03版本就是使用xls结尾
FileOutptStream fileOutputStream = new FileOutputStream(PATH + "狂神观众统计表.xls");
workbook.write(fileOutputStream);
fileOutputStream.close();
System.out.println("EXCEL生成完毕!");
}
public void testWrite07(){
//创建一个工作簿
Workbook workbook = new XSSFWorkbook();
//创建一个工作表
Sheet sheet = workbook.creatSheet("狂神观众统计表");
//创建一行
Row row = sheet.creatRow(0);
//创建单元格(列)
Cell cell = row.createCell(0);
cell.setCellValue("今日新增观众");
Cell cell1 = row.createCell(1);
cell1.setCellValue(666);
//构建流生成一张表 07版本就是使用xlsx结尾
FileOutptStream fileOutputStream = new FileOutputStream(PATH + "狂神观众统计表.xlsx");
workbook.write(fileOutputStream);
fileOutputStream.close();
System.out.println("EXCEL生成完毕!");
}
大文件写入HSSF
使用03版的只能处理65535行。HSSF
使用07版的能处理的数据量不限,但是如果数据过大就会影响性能,所以需要使用加速的功能。XSSF
测试07版大文件写入代码如下(包含加速处理功能)
public void testWrite03BigData(){
Long begin = System.currentTimeMills();
//创建一个工作簿
Workbook workbook = new HSSFWorkbok();
//创建一张表
Sheet sheet = woorkbook.createSheet();
//写入数据
for(int rowNum = 0; i < 65536; i ++){
Row row = sheet.createRow(rowNum);
for(int cellNum = 0 ; cellNum < 10; cellNum++){
Cell cell = row.createCell(cellNum);
cell.setCellVlaue(cellNum);
}
}
System.out.println("done!");
FileOutputStream fileOutStream = new FilOutputStream(PATH + testWrite03BigData.xls);
workbook.write(fileOutputStream);
fileOutputStream.close();
Long end = System.currentTimeMills();
System.out.println((double)(end - begin) / 1000);
}
如果超过65535行就会报错!
07版本的就可以处理超过65535行的数据,但是效率比较底下
public void testWrite7BigData(){
Long begin = System.currentTimeMills();
//创建一个工作簿
Workbook workbook = new XSSFWorkbok();
//创建一张表
Sheet sheet = woorkbook.createSheet();
//写入数据
for(int rowNum = 0; i < 65536; i ++){
Row row = sheet.createRow(rowNum);
for(int cellNum = 0 ; cellNum < 10; cellNum++){
Cell cell = row.createCell(cellNum);
cell.setCellVlaue(cellNum);
}
}
System.out.println("done!");
FileOutputStream fileOutStream = new FilOutputStream(PATH + testWrite07BigData.xlsx);
workbook.write(fileOutputStream);
fileOutputStream.close();
Long end = System.currentTimeMills();
System.out.println((double)(end - begin) / 1000);
}
通过计算03的输出65535行数据耗时1.35s,07版耗时7.65s;
大文件写SXXSSF:可以写非常大的数据量,如100万条甚至更多条,写数据速度快,占用更少内存。
注意中间会产生临时文件,需要清理临时文件。
默认由100条记录被保存在内存中,如果超过这个数量,则最前面的数据被写入临时文件。
如果像自定义内存中的数据的数量,可以使用new SXSSFWorlbool(数量);
public void testWrite7BigDataS(){
Long begin = System.currentTimeMills();
//创建一个工作簿
Workbook workbook = new SXSSFWorkbok();
//创建一张表
Sheet sheet = woorkbook.createSheet();
//写入数据
for(int rowNum = 0; i < 65536; i ++){
Row row = sheet.createRow(rowNum);
for(int cellNum = 0 ; cellNum < 10; cellNum++){
Cell cell = row.createCell(cellNum);
cell.setCellVlaue(cellNum);
}
}
System.out.println("done!");
FileOutputStream fileOutStream = new FilOutputStream(PATH + testWrite07BigDataS.xlsx);
workbook.write(fileOutputStream);
//清除临时文件
((SXSSFWorkbook)workbook).dispose();
fileOutputStream.close();
Long end = System.currentTimeMills();
System.out.println((double)(end - begin) / 1000);
}
需要注意内存消耗情况。
POI-读数据-03版
//读测试
public void testRead03() throws Exception{
//1,创建一个工作簿,使用EXCEL能操作的这边都可以操作
//获取文件流
FileInputStream fileInputStream - new FileInputStream(PATH + "狂神观众统计表.xls");
Workbook workbook = new HSSFWorkbok(fileInputStream);
//通过下标或者表名获取表格
workbook.getSheetAt(0);
//得到一列
Row row = sheetgetRow(0);
//得到一个单元格
Cell cell = row.getCell(0);
//cell.getValue():获取的是一个字符串
System.out.println(cell.getValue());
//获取的是一个数字
System.out.println(cell.getNumericCellValue());
fileInputStream.close();
//读取值的时候一定要注意类型。
}
POI-读数据-07版
//读测试
public void testRead07() throws Exception{
//1,创建一个工作簿,使用EXCEL能操作的这边都可以操作
//获取文件流
FileInputStream fileInputStream - new FileInputStream(PATH + "狂神观众统计表.xlsx");
Workbook workbook = new XSSFWorkbok(fileInputStream);
//通过下标或者表名获取表格
workbook.getSheetAt(0);
//得到一列
Row row = sheetgetRow(0);
//得到一个单元格
Cell cell = row.getCell(0);
//cell.getValue():获取的是一个字符串
System.out.println(cell.getValue());
//获取的是一个数字
System.out.println(cell.getNumericCellValue());
fileInputStream.close();
//读取值的时候一定要注意类型。
}
如何获取不同的数据类型**(最麻烦的地方!)**
public void testCellType() throws Exception{
//获取文件流
FileInputStream inputStream = new FileInputStream(Path + "wenjianming.xls");
//创建一个工作簿。:如果是07的版本记得换成相应的类
Workbook workbook = new HSSFWorkbook(inputStream);
Sheet sheet = workbook.getSheetAt(0);
//获取标题内容
Row rowTitle = sheet.getRow(0);
if(rowTitle != null){
int cellCount = rowTtile.getPhysicalNumberOfCells();
for(int cellNum = 0; cellNum < cellCount; cellNum++){
Cell cell = rowTitle.getCell(cellNum);
if(cell != null){
int cellType = cell.getCellType();
String cellValue = cell.getStringCellVlaue();
System.out.print(cellValue + "|");
}
}
System.ut.println();
}
//获取表中的内容
int rowCount = sheet.getPhysicalNumberOfRows();
for(int rowNum = 1; rowNum < rowCount ;rowNum++){
Row rowData = sheet.getRow(rowNum);
if(rowData != null){
//读取列
int cellCount = rowTitle.getPhysicalNumberOfCells();
for(int cellNum = 0; cellNum < celloumt; cellNum ++){
System.out.print("["+(rowNum+1)+"-" + (cellNum+1)+"]");
Cell cell = rowData.getCell(cellNum);
//匹配列的数据类型
if(cell 1= null){
int cellType = cell.getCellType();
String cellValue = "";
switch(cellType){
case hssfcell.CELLTYPE_STRING: //字符串类型
System.out.pprintln("[String类型!]");
cellValue = cell.getStringCellValue();
bresk;
case: hssfcell.CELLTYPE_TYPE_BOOLEAN: //布尔类型
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case hssfcell.CELLTYPE_TYPE_BLANK:
break;
case hssfcell.CELLTYPE_TYPE_NUMEIC:
if(HSSFDataUtil.isCellDataFormatted(cell)){
//日期
Date date = cell.getDateCellValue();
cellValue = new DateTime(data).toString("yyyy-MM-dd");
}else{
//普通的数字,转换为字符串输出即可,不是日期格式,防止数字过长转换成字符串类型。
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cellValue = cell.toString();
}
break;
case HSSFCell.CELL_TYPE_ERROR:
break;
}
System.out.println("done");
}
}
}
}
inputStream.close();
}
计算公式
读取公式并计算
public void testFunction(){
FileInputStream inputStream = new FileInputStream(PATH + "文件名");
HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
Sheet sheet = workbook.getSheetAt(0);
Row row = sheet.getRow(4);
Cell cell = row.getCell(0);
//拿到计算公式
FormulaEvaluator forMulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook)workbook);
//输出单元格的内容
cell.getType = cell.getCellType();
switch(cellType){
case Cell.CELL_TYPE_FORMULA: //公式
String formula = cell.getCellFormula();
System.out.println(formula);
//计算
CellValue evaluate = FormulaEvaluator.evaluate(cell);
String cellValue = evaluate.formatAsString();
//输出结果
System.out.println(cellVlaue);
}
}
EasyExcel
阿里巴巴开源的系统,做了优化,所以比较方便简洁。
public static void CsvToXlsx(String oripath, String despath, String sheet)
{
ExcelWriter excelWriter = null;
File destFile = new File(despath);
File oriFile = new File(oripath);
File transFile = new File(destFile.getParent(),"trans.xlsx");
try {
if (destFile.exists())
{
//创建中转文件
//追加数据,中转文件与目标文件不能是同一个文件名
//withTemplate()指定模板文件,即复制一份; file() 中间文件名; autoCloseStream() 必须为True,自动关闭输入流
excelWriter = EasyExcel.write().withTemplate(destFile)
//.file() 指定目标文件,不能与模板文件是同一个文件
.file(transFile).autoCloseStream(true).build(); //
}
else
{
excelWriter = EasyExcel.write(destFile).build();
}
WriteSheet writeSheet = EasyExcel.writerSheet(sheet).needHead(false).build();
List<Map<Integer,Object>> list = importdata(oriFile); //返回的数据全部都是String类型的
//将列表中值为数字的字符串转化为Double型
Pattern pattern = Pattern.compile("-?[0-9]+.?[0-9]*");
for(int i=0;i<list.size();i++)
{
Map<Integer, Object> map = list.get(i);
for(int j=0;j<map.size();j++)
{
if(map.get(j)==null)continue;
String value = map.get(j).toString();
if(pattern.matcher(value).matches())
{
map.put(j, Double.parseDouble(value));
}
else
{
map.put(j, value);
}
}
list.set(i, map);
}
excelWriter.write(list, writeSheet);
}
finally
{
if (excelWriter != null)
{
excelWriter.finish();
}
}
if (transFile.exists())
{
//删除原文件
destFile.delete();
boolean result = transFile.renameTo(destFile);
if(result)System.out.println("改名成功");
else System.out.println("改名失败");
}
}
//导入数据
public static List<Map<Integer,Object>> importdata(File file)
{
List<Map<Integer,Object>> list = new LinkedList<>();
EasyExcel.read(file)
.excelType(ExcelTypeEnum.CSV) //如果原始为.xlsx文件则改成.XLSX
.sheet()
.registerReadListener(new AnalysisEventListener<Map<Integer,Object>>() {
@Override
public void invoke(Map<Integer, Object> integerStringMap, AnalysisContext analysisContext) {
// TODO Auto-generated method stub
list.add(integerStringMap);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// TODO Auto-generated method stub
System.out.println("数据读取完毕");
}
}).headRowNumber(0).doRead();
return list;
}
小结-学习方式
了解面向对象的思想,学会面向接口编程。理解使用测试API。