在使用 Android 应用程序的过程中,各应用之间难免会有数据交互。Android 应用框架的开发者也考虑到了这些,他们在 Android 中内置三种数据传输的方式:Intent,Content Provider,NFC。
上面的三种数据传输方式分别对应了不同场景下的数据交互:
Intent
应用程序内部或者应用程序之间文本类数据
Content Provider
应用程序之间大文件
NFC
不同设备之间大文件
一、Intent 使用详解
1.创建 Intent(发送端):
Intent intent = new Intent();
2.设置 Intent(发送端):
intent.setAction(Intent.SEND);
intent.setType("text/plain");(非必需)
intent.putExtra("KEY", "MSG");
3.发送 Intent(发送端):
startActivity(intent);
或 startActivityForResult(intent);
4.接受 Intent(接收端):
Intent intent = getIntent();
5.处理 Intent(接收端):
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent); // Handle text being sent
} else if (type.startsWith("image/")) {
handleSendImage(intent); // Handle single image being sent
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
if (type.startsWith("image/")) {
handleSendMultipleImages(intent); // Handle multiple images being sent
}
} else {
// Handle other intents, such as being started from the home screen
}
6.返回 Intent(如果需要)(接收端):
Intent intent = new Intent();
intent.putXXX();
setResult(Activity.RESULT_OK, intent);
finish();
7.处理接收端返回的数据(如果需要)(发送端):
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK){
switch(requestCode){
case CommonConstant.REQUEST_CODE_1:
// parse the feedback data--intent
break;
}
}
}
二、Content Provider 使用详解
此处主要涉及到应用程序之间文件类数据分享,因此,此处主要讲解的是 Content Provider 的子类——File Provider。
1.配置要分享服务端清单文件(服务端):
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.deep_practice.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
2.配置目标分享文件的路径(服务端):
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_texts" path="texts/"/>
<files-path name="my_images" path="images/"/>
<files-path name="my_des_dir" path="des_dir/"/>
<external-path name="my_capturing_photos" path="Android/data/com.smart.develop/files/Pictures" />
</paths>
3.接受客户端请求(服务端):
<activity
android:name=".content_sharing.sharing_files.FileSelectActivity"
android:label="@string/file_select">
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="text/plain" />
<data android:mimeType="image/*" />
<data android:mimeType="smart/*" />
</intent-filter>
</activity>
---
public class FileSelectActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
private ListView mLV;
private File mPrivateRootDir;
private File mDesDir;
private File mDesTextFile, mDesImageFile;
private String[] mDesFilesName;
private File[] mDesFiles;
private ArrayAdapter<String> mAdapter;
private Uri mFileUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initView() {
mLV = (ListView) findViewById(R.id.lv);
mLV.setOnItemClickListener(this);
}
private void initData() {
mPrivateRootDir = getFilesDir();
mDesDir = new File(mPrivateRootDir, "des_dir");
if (!mDesDir.exists()) {
mDesDir.mkdir();
}
mDesTextFile = new File(mDesDir, "des_text.txt");
mDesImageFile = new File(mDesDir, "des_image.png");
try {
if (!mDesTextFile.exists()) {
mDesTextFile.createNewFile();
mDesImageFile.createNewFile();
}
AssetManager am = getAssets();
InputStream is = am.open("des_text_file");
FileOutputStream textFOS = new FileOutputStream(mDesTextFile);
byte[] bytes = new byte[1024];
int temp = 0;
while ((temp = is.read(bytes)) != -1) {
textFOS.write(bytes, 0, temp);
}
textFOS.flush();
textFOS.close();
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dancing);
FileOutputStream imageFOS = new FileOutputStream(mDesImageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, imageFOS);
imageFOS.flush();
imageFOS.close();
} catch (Exception e) {
e.printStackTrace();
}
mDesFilesName = mDesDir.list();
mDesFiles = mDesDir.listFiles();
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDesFilesName);
mLV.setAdapter(mAdapter);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
try {
mFileUri = FileProvider.getUriForFile(this, "com.example.deep_practice.fileprovider", mDesFiles[position]);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
if (mFileUri != null) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(mFileUri, getContentResolver().getType(mFileUri));
// Set the result
this.setResult(Activity.RESULT_OK, intent);
this.finish();
}
}
}
4.返回数据(服务段):
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(mFileUri, getContentResolver().getType(mFileUri));
// set the result
this.setResult(Activity.RESULT_OK, intent);
this.finish();
5.发送请求(客户端):
Intent requestFileIntent = new Intent(Intent.ACTION_PICK);
// requestFileIntent.setType("text/plain");
// requestFileIntent.setType("image/*");
//此处的 Type 是可以自定义的,只要在目标组建的 <data android:mimeType="smart/*"/> 声明相同的类型即可
//既然 Type 可以自定义,那么其他的可以自定吗?例如 Action
requestFileIntent.setType("smart/*");
startActivityForResult(requestFileIntent, CommonConstant.REQUEST_CODE_1);
6.处理返回结果(客户端):
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent returnIntent) {
super.onActivityResult(requestCode, resultCode, returnIntent);
if (CommonConstant.REQUEST_CODE_1 == requestCode){
if (RESULT_OK == resultCode){
Uri returnUri = returnIntent.getData();
ContentResolver contentResolver = getContentResolver();
Cursor returnCursor = contentResolver.query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
mDesName.setText(returnCursor.getString(nameIndex));
mDesSize.setText((Float.toString(returnCursor.getLong(sizeIndex)/1024/1024f)) + "M");
String mimeType = contentResolver.getType(returnUri);
mDesType.setText(mimeType);
try {
ParcelFileDescriptor inputPFD = contentResolver.openFileDescriptor(returnUri, "r");
FileDescriptor fd = inputPFD.getFileDescriptor();
if(mimeType.equals("text/plain")){
FileInputStream fis = new FileInputStream(fd);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
fis.close();
mDesContent.setText(sb.toString());
}else if (mimeType.equals("image/png")){
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd);
mDesIV.setImageBitmap(bitmap);
}
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
}
三、NFC 使用详解
完成上面两个之后,我相信很多都大致明白怎么做了,首先搞清楚哪个是客户端,哪个是服务端,当你搞清楚了二者,你也就知道怎么做了。由于我的机子不支持 NFC 功能,所以只是测试了下当前设备是否支持 NFC,虽然没做,但是大致的流程是不变的:
1.配置权限并检查当前设备是否支持 NFC(发送端 & 服务端):
//所需权限
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
//所需特性
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
//检查当前设备是否支持 NFC
PackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)
2.检查当前设备的 Android 版本是否大于 16(发送端 & 服务端):
Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1
3.发送文件(发送端):
//send file
4.接收文件(接收端):
//receive file