前几天由于工作需要,需要写一个apk,安装在手机上,并且去读取驱动层的数据。其实驱动层的会给我一个路径类似于/diy/productName,这样的一个路径,我只需要根据这个路径读出来就好了,但是这个apk需求也没有光读出来就行这么简单,他还要每隔10秒把当前页的所有的数据都要保存到Excel表中,这就难倒我了,其实这两个需求都难倒我了,因为之前我都没有涉及过,做apk也是简单的上层的apk就好,哪有涉及过系统。
那没办法只能觉得,能学到很多知识的乐观心态开始做,废话不多说了,这就开始我的逻辑。
什么事情,都得一步一步来,不可能一步登天就能解决的。我就先从驱动读取数据的需求放一边了,我先把整体界面做好,然后有10个值,我就用LinearLayout里放了一个TextView,先给他们随便设置了,这就简单。然后我就是想,先把几面上的数据每隔10秒保存到Excel表中,这时就要用到一个第三方jar包:jxl.jar。而且也从晚上下载了一个类,那个类就是从数据库中把所有的数据都显示到Excel表中,也就是说:我先把界面上的数据全部都保存到数据库,然后每隔10秒,把数据库中的数据填充到Excel表中。这个类网上蛮多的。在这里就不列举了。
先用ContentValues把界面上的所有的值保存到数据库中,这个数据库的类也得自己写,SQlitedatabaseHelper。然后当数据库中的数据不为0的时候,就把数据从数据库中读出来填充到Excel表中:
file = new File(getSDPath() + "/ExcelRoad"); //Excel表存放的路径
makeDir(file); //创建这个路径(文件夹)
ExcelUtils.initExcel(file.toString() + "/ExcelName.xls", title); //title是Excel表每列的名字
ExcelUtils.writeObjListToExcel(getBillData(), getSDPath() + "/Electric/ElectricDetail.xls", this);
其中ExcelUtils就是从网上下载的那个类。
其中getBillData()就是从数据库中读出来的数据。
private ArrayList<ArrayList<String>>
getBillData() {
//electricList必须定义为局部变量,如果要是全局变量,他就会不断往里加重复的数据。
ArrayList<ArrayList<String>>
*electricList*=new ArrayList<ArrayList<String>>();;
Cursor mCrusor = mDbHelper.exeSql("select * from electric");
while (mCrusor.moveToNext()) {
ArrayList<String>
beanList=new ArrayList<String>();
beanList.add(mCrusor.getString(1));
beanList.add(mCrusor.getString(2));
beanList.add(mCrusor.getString(3));
beanList.add(mCrusor.getString(4));
beanList.add(mCrusor.getString(5));
beanList.add(mCrusor.getString(6));
beanList.add(mCrusor.getString(7));
beanList.add(mCrusor.getString(8));
beanList.add(mCrusor.getString(9));
beanList.add(mCrusor.getString(10));
electricList.add(beanList);
}
mCrusor.close();
return electricList;
}
这里面需要说一下的就是electricList这个变量了,当时遇到了一个很棘手的问题,但是等到解决了才发现自己还是很傻的。刚开始我把这个变量定义成了全局变量,然后每次填充到Excel表的时候,数据库里新添加一行数据,Excel表不会只继续添加这一行数据,而是数据库中有多少他就会再次添加所有的数据,倒是Excel重复叠加很多数据,到最后经过我男票的缜密观察,发现了这个问题,然后改成局部变量就解决了。
然后至于每隔1秒都要更新界面上的值,这个只能用Handler来实现了,然后每隔10秒就要保存到Excel表,这个就定义一个Timer,用TimerTask来实现就好了。我就不多说了。
然后下面就说说怎么去读取底层的数据,想要读取底层的数据,驱动那边就得给我加权限,不然他就会说Permission Denied。那么假权限的时候出现了一个麻烦,就是驱动的人不知道我这个apk运行在手机里额哪个进程里,然后就用一个adb 命令:adb shell top >d:\1.txt,把所有的运行的apk所在的进程都给列出来了,看了一下我的apk,他的UID的名字叫做:u0_r7,记得好像是这个名字,驱动的不知道这是哪个进程啊,想给他添加权限也添加不了啊,那没办法了,问了一下另一个同事,就知道怎么解决了:在我的代码中在AndroidManifest.xml文件中国,在项目的上面添加一行代码:android:sharedUserId="android.uid.system"
然后我这个apk就会运行在系统进程中,然后就好解决了,驱动的给这个系统的进程添加权限就ok了。
读数据的时候用了下面两行代码
BufferedInputStream buf_in = new BufferedInputStream(new FileInputStream(dev_fileName));
int value = buf_in.read(bInput);
其中dev_fileName就是驱动给我的路径/diy/productName。因为读出来的数据bInput是byte型的数据,但是我要把它显示为int型的,所以几句出现了下面这一行转换的方式:
valArry[0] = ((((int)bInput[3] << 24) & 0xff000000) |(((int)bInput[2] << 16) & 0xff0000) |(((int)bInput[1] << 8) & 0xff00) |((int)bInput[0] & 0xff));
下面的 valArry[1]、 valArry[2] 类似这么倒着来。
然后写入数据的时候,我也不能传int型数据,所以就比如我要传(1,0)那么就得把他转换成16进制的写法:
byte[] opendog = {0x1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(dev_fileName));
bos.write(opendog);
这就是写入数据了,还有写入一个数据3000,我不知道这个怎么写成16进制的byte型数据啊,好好模仿了一下别人的写法,就是先把3000转换成2进制,他就变成:0000 1011 1011 1000
然后把他转换成16进制,就变成了00 00 0b b8,然后也一样,把他倒过来就好了,
0xb8, 0x0b, 0x00, 0x00
好了,大概遇到的问题就是这么多了,今天暂时写到这里吧,如果哪里写的不周到,希望指导指导~