近期專案中需要從一個應用中拷貝一份檔案(該檔案無法直接拿到),并且檔案放置的目錄是data下,外部應用無法直接訪問,所以考慮使用ContentProvider來實作,
ContentProvider,Android四大組件;ContentProvider 的作用是為不同的應用之間資料共享,提供統一的介面,本文就主要來說下實作樣例,
一. 新建專案,相信大家都會了,
新建了兩個專案,test01和test02,實體如下:


最終實作從test01的data目錄下拷貝檔案(data.xml)至test02中,
二.自定義實作ContentProvider,下面是代碼展示:
/**
* 檔案共享
*/
public class FileContentProvider extends ContentProvider {
final private static String TAG = "FileContentProvider";
//檔案名稱
private static String FILENAME = "data.xml";
@Override
public boolean onCreate() {
Log.d(TAG, "========= onCreate is called =========");
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
Log.d(TAG, "========= query is called selection =========> " + selection);
return null;
}
/**
* 獲取檔案的檔案名
*
* @param uri
* @return
*/
@Nullable
@Override
public String getType(@NonNull Uri uri) {
//判斷檔案是否存在
String fileName = "";
String path = MyApp.getContext().getFilesDir().getAbsolutePath();
if (TextUtils.isEmpty(path)) {
Log.i(TAG, "Data path must not be null!");
ToastUtils.s(MyApp.getContext(), "Data path must not be null! ");
fileName = "";
return fileName;
}
File datapathFile = new File(path);
if (!datapathFile.exists()) {
Log.i(TAG, "Data path does not exist!");
ToastUtils.s(MyApp.getContext(), "Data path does not exist! ");
fileName = "";
return fileName;
}
File datafile = new File(path + File.separator +
FILENAME);
if (!datafile.exists()) {
Log.i(TAG, "Data file not found at " + datafile);
ToastUtils.s(MyApp.getContext(), "Data file not found at " + datafile);
fileName = "";
return fileName;
}
fileName = FILENAME;
Log.i(TAG, "fileName:" + FILENAME);
Log.i(TAG, "uri.getPath():" + uri.getPath());
return fileName;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
/**
* 需要實作該方法,
*
* @param uri
* @param mode
* @return
* @throws FileNotFoundException
*/
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
String fileName = FILENAME;
String filePath = MyApp.getContext().getFilesDir().getAbsolutePath() + File.separator + fileName;
//如果存在檔案,則獲取檔案相關資訊,并回傳
File datafile = new File(filePath);
if (datafile.exists()) {
Log.i(TAG, " fileName: " + fileName);
Log.i(TAG, "filePath: " + filePath);
//計算檔案的md5
Log.i(TAG, "檔案 file2MD5 " + Md5CaculateUtil.file2MD5(datafile));
return ParcelFileDescriptor.open(datafile,
ParcelFileDescriptor.MODE_READ_ONLY);
} else {
Log.d(TAG, "file not found at" + filePath);
return null;
}
}
}
說明:
1.重寫了兩個方法;
2.getType()方法 回傳檔案名稱,openFile()方法回傳檔案流;
三. test01其他實作代碼,
private void goToTest02() {
if (AppUtil.checkAppInstalled(MainActivity.this, SLF_PACKAGE_NAME)) {
getFile();
} else {
ToastUtils.s(MainActivity.this, "應用未安裝");
}
}
/**
* 獲取檔案
*/
private void getFile() {
Intent intent = new Intent();
ComponentName componeneName = new ComponentName(SLF_PACKAGE_NAME, SLF_ACTIVITY_NAME);
intent.setComponent(componeneName);
String filePath = MyApp.getContext().getFilesDir().getAbsolutePath() + File.separator + FILENAME;
//如果存在檔案,則獲取檔案的相關資訊,并回傳
File datafile = new File(filePath);
if (datafile.exists()) {
Log.d(TAG, "檔案存在");
Log.i(TAG, " fileName: " + FILENAME);
Log.i(TAG, "filePath: " + filePath);
//計算檔案的md5
Log.i(TAG, "檔案 file2MD5 " + Md5CaculateUtil.file2MD5(datafile));
String fileSize = FileSizeUtil.getAutoFileOrFilesSize(filePath);
Log.d(TAG, "檔案的大小- fileSize is " + fileSize);
intent.putExtra("fileName", FILENAME);
startActivity(intent);
return;
}
Log.d(TAG, "檔案不存在");
ToastUtils.s(MyApp.getContext(), "file not found at " + FILENAME);
}
說明:
1. 先判斷是否安裝了test02應用;
2.判斷是否存在需要共享的檔案;
四. test02 部分實作代碼,
/**
*
*/
private void getFileFromOutside() {
Intent data = getIntent();
if (data != null) {
String fileName = data.getStringExtra("fileName");
if (!TextUtils.isEmpty(fileName)) {
Log.i(TAG, " fileName: " + fileName);
readFile(fileName);
} else {
Log.i(TAG, "檔案名未傳遞,請先核查是否有檔案");
}
} else {
Log.i(TAG, "getIntent() is null");
}
}
/**
* 通過getContentResolver 讀取檔案
*
* @param fileName
*/
private void readFile(String fileName) {
String filePath = getFilesDir().getAbsolutePath() + File.separator + fileName;
File datafile = new File(filePath);
//檔案是否已經存在;如果存在,則不用再獲取
if (datafile.exists()) {
Log.d(TAG, "file is exists");
String fileSize = FileSizeUtil.getAutoFileOrFilesSize(filePath);
Log.d(TAG, "檔案的大小- fileSize is " + fileSize);
//計算檔案的md5
Log.i(TAG, " 檔案 file2MD5 " + Md5CaculateUtil.file2MD5(new File(filePath)));
ToastUtils.s(MainActivity.this, "file is exists");
return;
}
try {
//通過contentprovide 獲取檔案名
fileName = getContentResolver().getType(mUrl);
if (TextUtils.isEmpty(fileName)) {
Log.i(TAG, "fileName is null");
return;
}
//通過contentprovide 獲取檔案
InputStream is = getContentResolver().openInputStream(mUrl);
// 獲取檔案路徑
filePath = getFilesDir().getAbsolutePath() + File.separator + fileName;
OutputStream os = new FileOutputStream(new File(filePath));
byte[] b = new byte[1024];
int len;
while ((len = is.read(b)) != -1) {
os.write(b, 0, len);
}
os.flush();
is.close();
os.close();
// 計算拷貝檔案大小
String fileSize = FileSizeUtil.getAutoFileOrFilesSize(filePath);
Log.d(TAG, "-匯入的 檔案的大小- fileSize is " + fileSize);
//計算檔案的md5
Log.i(TAG, "檔案 file2MD5 " + Md5CaculateUtil.file2MD5(new File(filePath)));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
說明:
1.先判斷檔案是否存在;
2.呼叫ContentProvider提供的方法,從檔案流中獲取需要共享的檔案,寫入test02應用中,
3.其他代碼詳見原始碼,
4.上傳檔案“data.xml”至目錄“/data/data/com.demo.test01/files”下,

5.運行后,日志,


test01和test02 原始碼和apk 下載地址,
五. 總結,
使用ContentProvider來達到應用見資料共享,需要自定義ContentProvider,重寫相關方法;然后在應用中呼叫ContentProvider提供的外部呼叫方法,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/301551.html
標籤:其他
