基於Android系統OTG功能下將U盤作為資料來源的解決方案
一、問題來源
目前市面上多數APP都是基於網際網路來讀取資料,展示介面,但若在無網路環境,如展廳、政府機構中大多都不連線外網,那麼APP的資料只能以靜態或內建的方式儲存,這些資料(圖片、Excel等文件、音視訊等)無法重新整理和更改,非常不方便後期維護更新;
典型案例:某展廳有一臺觸控式螢幕(Android系統),提供該單位所管轄範圍下的客戶資訊,一旦客戶資訊變更,那麼就需要修改APP中的資料,問題來了,該資料是靜態寫入程式的,觸控式螢幕是不聯網的,只能重新提供APP安裝包,非常不方便。
二、分析原因
資料來源:
1 內建資料,就是所謂的單機版,靜態,不易修改,無法滿足後期更新維護的要求,無法滿足如上案例更新資料的要求;
2 伺服器提供,通過介面獲取伺服器儲存的資料,前提是需要一臺伺服器,在聯網的情況下通過介面把資料提供給APP,達到更新資料的目的,這種也無法滿足如上案例無網的情況;
案例分析:本案例在日常生活中經常遇到,如展廳的觸控式螢幕,內容資料更新頻率不高,裝置不聯網,只用來做簡單的查詢展示作用;
束手無策:怎麼辦,無法滿足案例需求?還好,可採用第三種解決方案,通過中介軟體提供資料,即無需裝置聯網,也無需一臺伺服器提供資料,也可實現更新資料的目的,那就是通過OTG技術。
什麼是OTG ?
OTG是一種USB傳輸技術,通過OTG轉接線,可以讓手機直接訪問U盤或數碼相機等裝置中的檔案,還可以連線到鍵盤、滑鼠等外接裝置;
三、解決方案
非常產品,就需非常手段,筆者已經解釋了OTG技術,那麼解決方案應該已經清楚了,簡單描述就是支援OTG的裝置(一般觸控式螢幕和部分手機都支援OTG技術),通過U盤提供資料來源給APP程式;
方案描述:首先將修改後的資料來源按照一定格式或檔案目錄存入U盤,APP啟動後從U盤讀取資料並存入裝置內建SD卡,拔掉U盤後,App從SD卡中讀取對應資料展示;
資料流向:U盤——SD卡——App程式——使用者介面。
附錄一張筆者在專案技術方案中的流程圖:
四、程式碼流程
基本思路已如上圖很清晰了,下面就是通過程式碼來一步一步實現了,核心程式碼如下:
1 許可權檢測和開源庫
涉及許可權,注意6.0的動態許可權
<!-- 開機啟動 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <!-- SD卡寫許可權 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- SD卡讀許可權 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <!-- 在SDCard中建立與刪除檔案許可權 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
U盤插入拔出檢測
private void registerReceiver() {
//監聽otg插入 拔出
IntentFilter usbDeviceStateFilter = new IntentFilter();
usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(mUsbReceiver, usbDeviceStateFilter);
//註冊監聽自定義廣播
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
}
private BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case ACTION_USB_PERMISSION://接受到自定義廣播
setMsg("接收到自定義廣播");
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { //允許許可權申請
if (usbDevice != null) { //Do something
setMsg("使用者已授權,可以進行讀取操作");
readDevice(getUsbMass(usbDevice));
} else {
setMsg("未獲取到裝置資訊");
}
} else {
setMsg("使用者未授權,讀取失敗");
}
break;
case UsbManager.ACTION_USB_DEVICE_ATTACHED://接收到儲存裝置插入廣播
UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device_add != null) {
setMsg("接收到儲存裝置插入廣播,嘗試讀取");
redDeviceList();
}
break;
case UsbManager.ACTION_USB_DEVICE_DETACHED://接收到儲存裝置拔出廣播
UsbDevice device_remove = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device_remove != null) {
setMsg("接收到儲存裝置拔出廣播");
usbFiles.clear();//清除
cFolder = null;
}
break;
}
}
};
2 讀取U盤資料
這裡用到開源庫:
//Excel解析庫
implementation 'com.hynnet:jxl:2.6.12.1'
//U盤
implementation 'com.github.mjdev:libaums:0.5.5'
private void readDevice(UsbMassStorageDevice device) {
// before interacting with a device you need to call init()!
try {
device.init();//初始化
// Only uses the first partition on the device
Partition partition = device.getPartitions().get(0);
FileSystem currentFs = partition.getFileSystem();
// fileSystem.getVolumeLabel()可以獲取到裝置的標識
// 通過FileSystem可以獲取當前U盤的一些儲存資訊,包括剩餘空間大小,容量等等
// Log.d(TAG, "Capacity: " + currentFs.getCapacity());
// Log.d(TAG, "Occupied Space: " + currentFs.getOccupiedSpace());
// Log.d(TAG, "Free Space: " + currentFs.getFreeSpace());
// Log.d(TAG, "Chunk size: " + currentFs.getChunkSize());
UsbFile root = currentFs.getRootDirectory();//獲取根目錄
String deviceName = currentFs.getVolumeLabel();//獲取裝置標籤
setMsg("正在讀取U盤" + deviceName);
cFolder = root;//設定當前檔案物件
addFile2SD();
} catch (Exception e) {
e.printStackTrace();
setMsg("讀取失敗,異常:" + e.getMessage());
}
}
3 寫資料到SD卡
private void addFile2SD() {
try {
for (UsbFile file : cFolder.listFiles()) {
//找到資料夾
if (file.isDirectory() && file.getName().equals(SD_DIR_NAME)) {
for (UsbFile subfile : file.listFiles()) {
if (subfile.isDirectory()) {//image 資料夾
for (UsbFile imgfile : subfile.listFiles()) {
usbFiles_img_list.add(imgfile);
readFile(imgfile,FileUtil.getSavePath(SD_DIR_NAME+File.separator+SD_DIR_IMAGE_NAME));
}
} else { //em.xls info.png
usbFiles_xls_list.add(subfile);
readFile(subfile,FileUtil.getSavePath(SD_DIR_NAME));
}
}
break;
}
}
} catch (IOException e) {
e.printStackTrace();
setMsg("讀取出錯IO異常:" + e.getMessage());
}
}
4 App讀取資料
根據路徑從SD卡中取出所需檔案,示例
private void loadExcelData() {
if (!SDUtils.checkSDcard()) {
Toast.makeText(getBaseContext(), "該裝置沒有SD卡,請檢查!", Toast.LENGTH_LONG).show();
return;
}
String filePath = SDUtils.getSDPath() + File.separator + SDUtils.SD_DIR_NAME +
File.separator + SDUtils.SD_FILE_NAME;
Log.w("TAG", "filePath:" + filePath);
//解析xls
ExcelDataLoader excelDataLoader = new ExcelDataLoader();
excelDataLoader.execute(filePath);
}
//在非同步方法中 呼叫
private class ExcelDataLoader extends AsyncTask<String, Integer, ArrayList<ExcelBean>> {
//執行子主執行緒,執行耗時操作,防止主執行緒阻塞,出現ANR
@Override
protected ArrayList<ExcelBean> doInBackground(String... strings) {
return ExcelUtils.parseXlsDataFromSD(strings[0], 0, getBaseContext());
}
//運行於主執行緒,更新進度
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
//運行於主執行緒,耗時操作結束後執行該方法
@Override
protected void onPostExecute(ArrayList<ExcelBean> excelBeans) {
super.onPostExecute(excelBeans);
initData(excelBeans);
}
}
private void initData(ArrayList<ExcelBean> list) {
Gson gson = new Gson();
String jsonStr = gson.toJson(list);
Log.i("TAG", "JSON_INFO:" + jsonStr);
}
可能有朋友需要看下Excel表格解析成資料模型的程式碼,程式碼如下:
public static ArrayList<ExcelBean> parseXlsDataFromSD(String xlsPath, int index, Context
context) {
ArrayList<ExcelBean> excelBeanArrayList = new ArrayList<>();
File file = new File(xlsPath);
try {
InputStream is = new FileInputStream(file);
Workbook workbook = Workbook.getWorkbook(is);
int sheetNum = workbook.getNumberOfSheets();
Log.d(TAG, "the num of sheets is " + sheetNum);
for (int i = 0; i < sheetNum; i++) {
Sheet sheet = workbook.getSheet(i);
int sheetRows = sheet.getRows();
int sheetColumns = sheet.getColumns();
Log.d(TAG, "the name of sheet is " + sheet.getName());
Log.d(TAG, "total rows is 行=" + sheetRows);
Log.d(TAG, "total cols is 列=" + sheetColumns);
for (int j = 1; j < sheetRows; j++) {
ExcelBean excelBean = new ExcelBean();
excelBean.setNum(Integer.valueOf(sheet.getCell(0, j).getContents()));
excelBean.setType(Integer.valueOf(sheet.getCell(1, j).getContents()));
excelBean.setName(sheet.getCell(2,j).getContents());
/*
* 如果是日期型別,可以使用DateCell物件提供的方法:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Cell cell = sheet.getCell(j, i);
DateCell dateCell = (DateCell) cell;
String date = sdf.format(dateCell.getDate());
如果是數值型別,可以使用NumberCell物件提供的方法:
Cell cell = sheet.getCell(j, i);
NumberCell numberCell = (NumberCell)cell;
Double numberValue = numberCell.getValue();
String number = numberValue.toString();
* */
Cell cell_lon = sheet.getCell(3, j);
NumberCell numberCell_lon = (NumberCell)cell_lon;
Double numberValue_lon = numberCell_lon.getValue();
excelBean.setLatitude(numberValue_lon);
Cell cell_lat = sheet.getCell(4, j);
NumberCell numberCell_lat = (NumberCell)cell_lat;
Double numberValue_lat = numberCell_lat.getValue();
excelBean.setLongitude(numberValue_lat);
excelBean.setContent(sheet.getCell(5,j).getContents());
excelBean.setImgPath(sheet.getCell(6,j).getContents());
Log.d(TAG, "setLongitude=" + sheet.getCell(3,j).getContents());
excelBeanArrayList.add(excelBean);
}
}
workbook.close();
} catch (Exception e) {
Log.e(TAG, "read error=" + e, e);
}
return excelBeanArrayList;
}
5 使用者介面展示
將獲取到的資料做進一步處理,展示到使用者介面。
五、方案總結
至此案例需求完美解決,通過Android系統的OTG功能,採用U盤作為資料來源提供者,實現了無網路、無伺服器來定期更新維護App的特殊要求,目前該解決方案已通過真實專案測試,筆者可提供專案原始碼或技術協助,注意提供技術或原始碼均不免費,聯絡方式:[email protected],其他問題可直接留言,感謝大家的支援以及前輩同行們總結的寶貴經驗。
附:筆者推薦優質APP:IT面試寶典 。相關推薦
基於Android系統OTG功能下將U盤作為資料來源的解決方案
一、問題來源目前市面上多數APP都是基於網際網路來讀取資料,展示介面,但若在無網路環境,如展廳、政府機構中大多都不連線外網,那麼APP的資料只能以靜態或內建的方式儲存,這些資料(圖片、Excel等文件、音視訊等)無法重新整理和更改,非常不方便後期維護更新;典型案例:某展廳有一
android系統分享功能,將自己的APK加入可分分享的應用列表
android系統分享功能 第一步:在Manifest.xml進行配置,比普通的activity中多增加一個Intent過濾器 <application android:allowBackup="true" android:icon="@d
Jacoco在Android系統應用測試中覆蓋率一直為0的解決方案
問題 普通應用Gradle配置Jacoco,執行createDebugAndroidTestCoverageReport,能夠正常輸出覆蓋率報告,報告路徑為: build/reports/coverage/debug/index.html。檢視build/out
linux嵌入式系統下實現U盤、SD卡自動掛載功能
在 Linux的嵌入式系統中我們經常用到U盤、SD卡的掛載,而每次都手動掛載或解除安裝非常麻煩,我們可以採取以下方法實現自動掛載或解除安裝U盤、SD卡 這就要用到mdev了 其具體操作如下: 1、首先在/etc/init.d/rsC中加入以下語句 echo /sbin/mdev > /proc/sys
基於Android系統的多點觸控式螢幕(MultiTouchScreen)驅動
理論: 輸入子系統由來 在Linux中, 應用層對於輸入裝置(滑鼠、鍵盤、觸控式螢幕等)的操作無非都是open、read、write、ioctl,然後呼叫驅動層的xxx_open、xxx_read、xxx_write、xxx_ioctl去操作具體的硬體輸入裝置。如果按照傳統的思路,每
呼叫android系統相機拍照並將圖片傳指定路徑並獲取相片
public void onClick(View v) { if (v.getId() == R.id.btn_take) { // 調系統相機 if (Environment.getExterna
ubuntu/centos環境下玩android系統(二): linux下的android模擬器執行!
上一篇完成了Android的編譯,想必一定心裡癢癢了!這一篇將開始玩轉android模擬器! 如果不喜歡在linux下執行 emulator ,可直接看第三篇,第三篇講述windows下的模擬器,相對linux下,要簡單很多! 一.下載Andoird SDK,
如何在不重灌win10系統的情況下將intel主機板的RAID設定改為ACHI設定
剛裝電腦的時候,為了資料的安全性,安裝了兩塊3T機械硬碟,並且在intel主機板中將磁碟設定為了raid0模式 結果用著發現raid問題很多 1.非正常關機後,重啟完畢需要同步資料,非常耗時 2.無法準確看到硬碟smart資訊,硬碟有報警了都不知道 3.噪音大,一塊硬碟沒什麼感覺,兩塊硬碟一塊動,就能
Linux下實現U盤、SD卡自動掛載功能 .
在 Linux中我們經常用到U盤、SD卡的掛載問題,每次都手動掛載或解除安裝非常麻煩,我們可以採取以下方法實現自動掛載或解除安裝U盤、SD卡 1、首先在/etc/init.d/rsC中加入以下語句 echo /sbin/mdev > /proc/sys/kernel/
使用adb命令刪除Android系統data目錄下檔案及資料夾
使用命令刪除data目錄下的資料夾,和刪除一般檔案不同。 data目錄下的檔案需要777許可權,所以需要的命令不同 data目錄: C:\Users\aw>adb shell roo
基於Android系統的平板電腦電子地圖系統開發
http://www.sbsm.gov.cn/article/gzdt/201204/20120400100590.shtml 4月1日上午,陝西省測繪地理資訊局組織陝西省發展和改革委員會相關專家對“基於android系統的平板電腦電子地圖系統開發”、“陝西省測繪成果目錄匯
Android獲取可用記憶體(系統,sd卡,u盤)
/** *通過反射獲取不同儲存卡的路徑,主要是用來獲取外掛sd卡路徑,內建sd卡路徑可通過Environment類的方法獲得 */ public static boolean hasEnoughStor
linux下製作U盤系統啟動盤
我們都知道 Windows 下我們可以使用 UltraISO(中文版叫軟碟通)製作U盤系統啟動盤,使用方法可能N多人都會,但是本文主要想簡單介紹下 Linux 製作U盤啟動盤的方法,所以不贅述了,如果有不會的請百度/谷歌去,但是如果你仔細看了本文,估計以後你也不想用
在Linux系統下製作U盤啟動盤
我的當前的系統是Linux(版本Xubuntu),之前是通過軟通牒(UltraISO)在Windows系統下製作了這個Linux系統的U盤啟動盤,然而在Linux系統下通過系統本身整合的DD命令,來實現在Linux系統下製作Linux系統的ISO系統U盤啟動盤,一行簡單的程式
檢視基於Android 系統單個程序記憶體和CPU使用情況的幾種方法
Total PSS by OOM adjustment: 16839 kB: System 16839 kB: system (pid 791) 9279 kB: Persistent 9279 kB: com.android.s
android USB OTG功能實現
一、檢查HW原理圖,確認是否支援OTG功能(vbus是否供上電,IDDIG pin連線是否正確)二、若HW確認支援OTG功能,則按照以下方法分別開啟USB OTG功能及實現掛載:如何開啟USB OTG功能:1).在alps/mediatek/config/[project]/a
基於Android系統Api封裝常用工具類
專案地址 https://github.com/h4de5ing/AndroidCommon/blob/master/README-cn.md gradle使用方式 compile 'com.code19.library:library:0.1.2' 常用工具類 使用示
Linux下掛載u盤
成功 掛載 消失 linux下 spa 一個 fat 執行 class 1.先進入/mnt/目錄新建一個usb目錄 cd /mnt/ mkidr usb 2.先fdisk -l,然後插上U盤,fdisk -l 查看是否有新的硬盤添加上來了 3.執行掛載 mo
怎麽將U盤格式化的文件恢復
備份文件,我們第一時間就會想到用U盤來將文件備份,如果我們將U盤裏的文件不小心格式化了怎麽辦呢?怎麽將U盤格式化的文件恢復 如果我們想要恢復U盤誤刪的文件,那麽我們可以使用互盾數據恢復軟件進行恢復,這款軟件是一款專業的數據恢復軟件,利用這款軟件我們可以輕松的將我們U盤裏刪除的文件恢復,這款軟件操作簡
Ubuntu下使用U盤安裝Ubuntu
ubuntu制作U盤啟動1. 安裝U盤制作工具sudo apt-get install unetbootin使用 sudo df -l 命令查看U盤盤符,這裏假設為/dev/sdb12. 格式化U盤使用 sudo umount /dev/sdb1 命令卸載U盤使用 sudo mkfs.vfat /dev/sd