Android App 與 U 盤通信示例詳解
前言
對于 U 盤的了解,相信大多數(shù)人應(yīng)該只停留在跟 U 盤跟電腦通信的階段,其實現(xiàn)在通過OTG 線就可以實現(xiàn)手機(jī)跟 U 盤之間的數(shù)據(jù)操作,不僅可以將 U 盤中的文件讀取到手機(jī)中來,還能將手機(jī)中的文件導(dǎo)出到 U 盤中,從而實現(xiàn)手機(jī)與 U 盤之間的通信。本文將從 Android App 入手,通過相關(guān)的代碼,帶大家一步步了解手機(jī)與 U 盤之間的通信。代碼我已經(jīng)放上 Github 了,有需要的點擊這里 。
一、自定義廣播接收器接收 U 盤相關(guān)的信息
在 U 盤插入或插出的時候,系統(tǒng)都會發(fā)出一條相關(guān)的廣播,所以我們需要自定義廣播接收器,接收這兩條廣播,然后進(jìn)行相應(yīng)的處理。
public class OtgReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
// 接收到 U 盤插入廣播
case UsbManager.ACTION_USB_DEVICE_ATTACHED:
showToast(context, "U 盤已插入");
// 獲取相關(guān)的 Usb 設(shè)備
UsbDevice attachUsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (attachUsbDevice != null) {
// 進(jìn)行權(quán)限申請
permissionRequest();
}
break;
// 接收到 U 盤拔出廣播
case UsbManager.ACTION_USB_DEVICE_DETACHED:
showToast(context, "U 盤已拔出");
break;
default:
break;
}
}
}
因為 Usb 相關(guān)的設(shè)備操作,需要申請相關(guān)的權(quán)限,所以在接收到 U 盤插入的廣播之后,我們需要進(jìn)行權(quán)限申請。
private void permissionRequest() {
// 設(shè)備管理器
UsbManager usbManager = (UsbManager) MainActivity.getContext().get().getSystemService(Context.USB_SERVICE);
// 獲取 U 盤存儲設(shè)備
UsbMassStorageDevice[] storageDevices = UsbMassStorageDevice.getMassStorageDevices(OtgApplication.getContext());
PendingIntent pendingIntent = PendingIntent.getBroadcast(OtgApplication.getContext(), 0, new Intent(ACTION_USB_PERMISSION), 0);
// 進(jìn)行權(quán)限申請
usbManager.requestPermission(device.getUsbDevice(), pendingIntent);
}
可以看到我們在申請權(quán)限的時候,傳入了一個 PendingIntent,PendingIntent 里面?zhèn)魅胛覀冏远x的廣播 ACTION_USB_PERMISSION,等到權(quán)限申請完成,便會發(fā)出這條廣播,然后我們可以在廣播接收器中接收并處理,從而進(jìn)行后續(xù)的操作。
case ACTION_USB_PERMISSION:
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (usbDevice != null) {
// 讀取 U 盤相關(guān)的信息
readDevice(getUsbMass(usbDevice));
} else {
showToast(context, "沒有插入 U 盤");
}
} else {
showToast(context, "未獲取到 U 盤權(quán)限");
}
break;
為了簡化相關(guān)的代碼,我導(dǎo)入 Github 上開源的 libaums ,所以需要在 build.gradle 里面加上
compile 'com.github.mjdev:libaums:0.5.5'
通過接收我們自定義的廣播,便可以從 Intent 里面獲取相應(yīng)的包含 U 盤信息的 UsbDevice
private void readDevice(UsbMassStorageDevice device) {
device.init();
// 設(shè)備分區(qū)
Partition partition = device.getPartitions().get(0);
// 文件系統(tǒng)
FileSystem currentFs = partition.getFileSystem();
// 獲取 U 盤的根目錄
mRootFolder = currentFs.getRootDirectory();
// 獲取 U 盤的容量
long capacity = currentFs.getCapacity();
// 獲取 U 盤的剩余容量
long freeSpace = currentFs.getFreeSpace();
// 獲取 U 盤的標(biāo)識
String volumeLabel = currentFs.getVolumeLabel();
}
二、將文件導(dǎo)入到 U 盤中
通常我們將手機(jī)跟 U 盤通過 OTG 線進(jìn)行連接,都是為了將手機(jī)里面的文件導(dǎo)入到 U 盤中,我們就以圖片為例子,看看怎樣將圖片導(dǎo)出到 U 盤中。
將圖片導(dǎo)出到 U 盤中,我們可以通過流來實現(xiàn),先在 U 盤對應(yīng)的目錄,創(chuàng)建新的 jpg/png 格式的文件,然后通過 BitmapFactory 將圖片轉(zhuǎn)換成 Bitmap,再進(jìn)一步拿到對應(yīng)圖片的 ByteArrayOutputStream,最后將對應(yīng)的字節(jié)寫入文件中。
public static void savePictureToUsb(String picturePath, UsbFile root) {
UsbFile newDir = root.createDirectory("Haoz" + System.currentTimeMillis());
UsbFile file = newDir.createFile("Haoz" + System.currentTimeMillis() + ".jpg");
Bitmap bitmap = BitmapFactory.decodeFile(picturePath);
OutputStream outputStream = new UsbFileOutputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
outputStream.write(out.toByteArray());
outputStream.flush();
outputStream.close();
file.flush();
file.close();
}
可以看到我們傳入圖片的路徑以及 U 盤的根目錄,便可以將圖片寫入到 U 盤中,在上一節(jié)中,我們已經(jīng)通過廣播拿到 U 盤的根目錄,所以直接用就行了。將文件從 U 盤中導(dǎo)入到手機(jī)中,其實思路也是一樣的。畢竟當(dāng) U 盤插入手機(jī)的那一刻,將 U 盤當(dāng)成手機(jī)的一個普通的目錄來處理就行了。
三、該注意的地方
雖然說,U 盤跟手機(jī)之間的通信相對來說不是很難,但其實也有很多需要注意的地方,也是筆者在開發(fā)過程中踩過的坑,這里都記錄出來,供大家參考。
3.1 獲取圖片的路徑
我們通過圖片選擇庫或者照相機(jī)回調(diào)出來的,很多時候都是圖片的 Uri,而要得到圖片對應(yīng)的 Bitmap 需要的是圖片的真實路徑,我們可以通過以下方法進(jìn)行轉(zhuǎn)換。
public static String getPath(ContentResolver resolver, Uri uri) {
if (uri == null) {
return null;
}
if (SCHEME_CONTENT.equals(uri.getScheme())) {
Cursor cursor = null;
try {
cursor = resolver.query(uri, new String[]{MediaStore.Images.ImageColumns.DATA},
null, null, null);
if (cursor == null || !cursor.moveToFirst()) {
return null;
}
return cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA));
} finally {
if (cursor != null) {
cursor.close();
}
}
}
return uri.getPath();
}
3.2 文件相關(guān)的讀寫操作
文件相關(guān)的讀寫操作都是比較耗時的,特別是當(dāng)文件比較大的時候。所以我們不能在主線程中進(jìn)行文件的讀寫,必須將其放在子線程中,等 I/O 操作完成了,再轉(zhuǎn)換到主線程中進(jìn)行操作。
3.3 廣播的注冊與移除
因為我們是自定義廣播接收器來接收相應(yīng)的廣播,所以需要在 Activity 中進(jìn)行廣播的動態(tài)注冊,將對應(yīng) Action 進(jìn)行過濾。最后不要忘記了在 onDestroy() 中移除廣播,防止內(nèi)存泄露。
private void registerUDiskReceiver() {
IntentFilter usbDeviceFileter = new IntentFilter();
usbDeviceFileter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
usbDeviceFileter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
usbDeviceFileter.addAction(Intent.ACTION_MEDIA_MOUNTED);
registerReceiver(mOtgReceiver, usbDeviceFileter);
// 注冊監(jiān)聽自定義廣播
IntentFilter filter = new IntentFilter(OtgReceiver.ACTION_USB_PERMISSION);
registerReceiver(mOtgReceiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mOtgReceiver);
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解如何在Flutter中集成華為認(rèn)證服務(wù)
這篇文章主要介紹了詳解如何在Flutter中集成華為認(rèn)證服務(wù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Android系統(tǒng)進(jìn)程間通信(IPC)機(jī)制Binder中的Server和Client獲得Service Manager接
本文主要介紹Android IPC通信Binder中的Server和Client獲得Service Manager接口,這里詳細(xì)的說明了如何實現(xiàn)Service Manager接口,對研究Android源碼的朋友提供幫助,有需要的小伙伴可以參考下2016-08-08
Android實現(xiàn)設(shè)置APP灰白模式效果
大家好,本篇文章主要講的是Android實現(xiàn)設(shè)置APP灰白模式效果,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12
android使用ViewPager實現(xiàn)輪播效果
這篇文章主要為大家詳細(xì)介紹了android使用ViewPager實現(xiàn)輪播效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
Android實現(xiàn)動態(tài)切換組件背景的方法
這篇文章主要介紹了Android實現(xiàn)動態(tài)切換組件背景的方法,需要的朋友可以參考下2014-07-07
Android實現(xiàn)藍(lán)牙(BlueTooth)設(shè)備檢測連接
這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)藍(lán)牙(BlueTooth)設(shè)備檢測連接,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-11-11

