將APP加入系統分享+根據Uri獲取絕對路徑
1 需求分析
當前專案中需要將我司的APP加入系統分享中,然後接收外部分享過來的資料。單純看需求貌似是很簡單,然後認真整理了一下思路,呵呵。。。具體看下圖吧。
2 實現需求時的主要知識點
實現這個需求的時候,主要的知識點如下。
(1)將app加入系統分享
假設我們用一個EditActivity 來接收並展示分享過來的資料。
那麼為了能夠讓 EditActivity 響應系統分享事件,需要在清單檔案中給 該 Activity 配置 intent-filter , 通過 intent-filter 中配置的 action 節點指定該頁面能接受的分享型別----android.intent.action.SEND 或者 android.intent.action.SEND_MULTIPLE。通過配置 data 節點 指定頁面能接收的具體資料型別。
<!--CnPeng 從廣場建立分享 windowSoftInputMode 控制emoji與系統鍵盤同顯示或不顯示-->
<activity
android:name="com.zjelite.square.activity.CreateNewTopicActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<!--<data android:mimeType="application/*"/>-->
<!--<data android:mimeType="audio/*"/>-->
<data android:mimeType="image/*"/>
<data android:mimeType="text/plain"/>
<!--<data android:mimeType="video/*"/>-->
<!--<data android:mimeType="multipart/*"/>-->
</intent-filter>
</activity>
android.intent.action.SEND 表示單檔案分享android.intent.action.SEND_MULTIPLE 表示多檔案分享
(2)獲取系統分享過來的資料
系統在分享資料的時候,也是通過Intent來傳遞資料,所以我們在EditActivity 中通過 getIntent() 可以獲取系統分享過來的具體資料。
- getIntent().getAction( ) 可以獲取當前頁面所響應的 android.intent.action
- getIntent().getType( ) 可以獲取當前頁面所接收到資料的 MimeType 型別
- 如果 MimeType 型別是 text/plain 表示分享過來的是純文字或者網址。
- 可以通過如下方式獲取分享過來的網址標題/主題
CharSequence extraSubject=getIntent().getCharSequenceExtra(Intent.EXTRA_SUBJECT);- 可以通過如下方式獲取分享過來的內容或連結
CharSequence extraText=getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT);
A:
如果標題為空,表示分享過來的是純文字,也就是 extraText是純文字;如果標題不為空,則表示分享過來的是一個網址,也就是說extraText是一個網址連結
B:
之所以使用CharSquence來接收,是因為有些系統分享在組織資料時用的資料型別是CharSquence
- 如果 MimeType 型別是 以** image/ **開頭, 表示分享過來的是圖片資料,可能是單圖,也可能是多圖。
- 如果action 的型別是 ACTION_SEND ,則表示分享的單張圖片。可以通過如下方式獲取該圖片的Uri:
Uri shareUri = inIntent.getParcelableExtra(Intent.EXTRA_STREAM);- 如果action 的型別是 ACTION_SEND_MULTIPLE ,則表示分享的是多張圖片。可以通過如下方式獲取該組圖片的Uri集合:
-->
<data android:mimeType="image/"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
```
>android.intent.action.SEND 表示單檔案分享android.intent.action.SEND_MULTIPLE 表示多檔案分享
###(2)獲取系統分享過來的資料
系統在分享資料的時候,也是通過Intent來傳遞資料,所以我們在EditActivity 中通過 getIntent() 可以獲取系統分享過來的具體資料。
> getIntent().getAction( ) 可以獲取當前頁面所響應的 android.intent.action
* getIntent().getType( ) 可以獲取當前頁面所接收到資料的 MimeType 型別
* 如果 MimeType 型別是 text/plain 表示分享過來的是純文字或者網址。
>>* 可以通過如下方式獲取分享過來的網址標題/主題
CharSequence extraSubject=getIntent().getCharSequenceExtra(Intent.EXTRA_SUBJECT);
>> * 可以通過如下方式獲取分享過來的內容或連結
CharSequence extraText=getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT);
>>
A:
如果標題為空,表示分享過來的是純文字,也就是 extraText是純文字;如果標題不為空,則表示分享過來的是一個網址,也就是說extraText是一個網址連結
>>
B:
之所以使用CharSquence來接收,是因為有些系統分享在組織資料時用的資料型別是CharSquence
>* 如果 MimeType 型別是 以** image/ **開頭, 表示分享過來的是圖片資料,可能是單圖,也可能是多圖。
>> * 如果action 的型別是 ACTION_SEND ,則表示分享的單張圖片。可以通過如下方式獲取該圖片的Uri:
Uri shareUri = inIntent.getParcelableExtra(Intent.EXTRA_STREAM);
>> * 如果action 的型別是 ACTION_SEND_MULTIPLE ,則表示分享的是多張圖片。可以通過如下方式獲取該組圖片的Uri集合:
List<Uri> uris = inIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
在下面的示例程式碼中 SharedPreferenceSharedInHelper sharedInSPHelper;
是自己定義的用來儲存接收到的分享資料的SP。後面會有詳細的介紹 GetRealPathBasedOnUri.getPathByUri4kitkat()
是自定義的根據Uri獲取絕對路徑的工具類。後面會有詳細介紹
/**
* 170516
* 獲取外部分享到集結號的資料並儲存到本地
*/
private void getAndSavaSharedInDatas() {
String intentAction = inIntent.getAction(); //區分是SEND 還是 SEND_MULITPLE
String mimeType = inIntent.getType();
sharedInSPHelper.saveSharedInAction(intentAction);
sharedInSPHelper.saveSharedInMimeType(mimeType);
if (Intent.ACTION_SEND.equals(intentAction) && !TextUtils.isEmpty(mimeType)) { //如果是單一型別的普通分享
if (("text/plain").equals(mimeType)) { //文字型別
CharSequence extraText = inIntent.getCharSequenceExtra(Intent.EXTRA_TEXT); //內容或連結
CharSequence extraSubject = inIntent.getCharSequenceExtra(Intent.EXTRA_SUBJECT); //標題,主題
String subject = "";
String text = "";
if (!TextUtils.isEmpty(extraSubject)) {
subject = String.valueOf(extraSubject); //如果不做判斷,直接將extraSubject轉成字串的話,會將null轉成 "null"
}
if (!TextUtils.isEmpty(extraText)) {
text = String.valueOf(extraText);
}
sharedInSPHelper.saveSharedInText(subject, text);
} else if (mimeType.startsWith("image/")) { //單張圖片分享
Uri shareUri = inIntent.getParcelableExtra(Intent.EXTRA_STREAM);
ArrayList<String> realPaths = new ArrayList<>();
String realPath = GetRealPathBasedOnUri.getPathByUri4kitkat(this, shareUri);
realPaths.add(realPath);
sharedInSPHelper.saveSharedInImages(realPaths);
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(intentAction) && !TextUtils.isEmpty(mimeType)) {
//如果是複合型別的分享
if (mimeType.startsWith("image/")) { //多圖分享
ArrayList<String> realPaths = new ArrayList<>();
List<Uri> uris = inIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
if (uris != null && uris.size() > 0) {
if (uris.size() > 9) { //多於9張則擷取前9張
uris = uris.subList(0, 9);
}
for (Uri uri : uris) {
String realPath = GetRealPathBasedOnUri.getPathByUri4kitkat(this, uri);
realPaths.add(realPath);
}
}
sharedInSPHelper.saveSharedInImages(realPaths);
}
}
}
(3)根據Uri 獲取圖片在本地的絕對路徑
在我司的專案中,需要拿到圖片的絕對路徑,然後根據絕對路徑進行壓縮,並獲取一個壓縮後的圖以及路徑,最後再根據壓縮後的路徑將壓縮後的圖片上傳到伺服器。所以,這就需要根據Uri 獲取其絕對路徑。
關於如何根據Uri 獲取絕對路徑,主要程式碼如下:
public class GetRealPathBasedOnUri {
@SuppressLint( "NewApi" )
public static String getPathByUri4kitkat(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {// ExternalStorageProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {// DownloadsProvider
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) {// MediaProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {// MediaStore
// (and
// general)
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {// File
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
A:
** 注意:上面這段根據 Uri 獲取絕對地址的程式碼的原始出處是:http://ch-kexin.iteye.com/blog/2297846**
B:
上述程式碼我在 4.3 / 5.0 / 6.0 / 7.0 上都做過測試,均能正確的取到絕對路徑。
C:
另外,在http://www.jianshu.com/p/b168cbe50066 中也有提及如何根據 Uri 獲取絕對路徑,但是非常遺憾,我在測試的時候沒能調通
(4)將List 集合資料儲存到SP
為了避免資料在各個介面之間傳來傳去,我的思路是在 EditActivity 介面獲取到資料之後直接儲存到本地,如果使用者未登入就先跳轉到登入介面,登入成功之後再跳轉回來,然後直接從本地取出先前儲存的資料展示出來。
個人比較習慣用SP儲存資料,但是用SP儲存的時候只能儲存 基本資料型別和 Set ,然而,如果系統分享過來的是多張圖片的時候,獲取到的將是 List<Uri>。為了保證List 中資料的順序性,我們不能使用 putStringSet( ) , 因為set 是無序的。所以,需要考慮將 List 轉成基本資料型別。這裡需要藉助 Gson,程式碼如下:
/**
* 儲存外部分享進來的圖片uri
*/
public void saveSharedInImages(ArrayList<String> sharedInImages) {
Gson gson = new Gson();
String gsonString = gson.toJson(sharedInImages);
LogUtils.e("轉成Gson串的圖片集合:", gsonString);
Editor editor = sp.edit();
editor.putString("SharedInImages", gsonString);
editor.commit();
}
/**
* 獲取外部分享進來的圖片 URI,
*/
public ArrayList<String> getSharedInImages() {
String gsonString = sp.getString("SharedInImages", "");
Gson gson = new Gson();
ArrayList<String> realPaths = gson.fromJson(gsonString, new TypeToken<ArrayList<String>>() {
}.getType());
LogUtils.e("將Gson串轉成集合時的型別", new TypeToken<ArrayList<String>>() {
}.getType().toString());
return realPaths;
}
在上面的程式碼中
A:
將List 轉成json 字串時使用的是 Gson的 toJson(object) 方法,該方法可以將任意型別的物件轉成 json 串。
B:
將 json 串轉成 List 的時候,使用的是Gson 的 fromJson(String json, Type typeOfT) ,第一個引數是 源資料 json 串 ,第二個參數列示需要轉成什麼型別的資料,在獲取 這個type 的時候 使用 固定寫法 ** new TypeToken<T> **, 其中, T 是要轉換成的資料型別。
比如,在上面的程式碼中,我宣告瞭 realPaths 的型別是 ArrayList<String> , 那麼 T 就需要寫 ArrayList<String>
(5)List 集合的擷取
由於我司APP一次最多支援 9 張圖片的上傳,所以,獲取到系統分享過來的資料時需要作出判斷,如果圖片數量大於9張,那麼就擷取前9張。在擷取的時候使用了 List 的 subList(int start, int end) 方法。該方法的含義是,從 start 位置開始擷取集合的資料,擷取到end 位置,但不包含end位置的資料,也即是說,擷取list中的資料,含頭不含尾。擷取集合前9個資料的程式碼如下:
if (uris.size() > 9) { //多於9張則擷取前9張
uris = uris.subList(0, 9);
}
3 相關參考:
A:
將APP加到系統分享的參考:
http://www.jianshu.com/p/00464708f8c4
http://blog.csdn.net/xiaanming/article/details/9428613
http://www.imooc.com/article/9197
B:
根據URI 獲取 絕對路徑的參考:
http://ch-kexin.iteye.com/blog/2297846
相關文章
- JavaScript 獲取目錄絕對路徑JavaScript
- 獲取絕對路徑 【檔案找不到】
- uniapp獲取軟體的根路徑(安卓)APP安卓
- 檔案的相對路徑和絕對路徑以及根相對路徑
- javascript將相對路徑修改為絕對路徑JavaScript
- PHP取url絕對路徑PHP
- js獲取專案根路徑JS
- JavaScript中獲取當前專案的絕對路徑JavaScript
- python獲取指定目錄所有檔案絕對路徑Python
- linux下獲取程式當前目錄絕對路徑Linux
- 怎樣獲取Torque.properties檔案的絕對路徑?
- python如何將相對路徑轉換為絕對路徑?Python
- 使用Javascript將相對路徑地址轉換為絕對路徑JavaScript
- 根據ip獲取城市
- Linux Shell獲取正在執行指令碼的絕對路徑Linux指令碼
- Android 從手機相簿獲取圖片 uri 路徑 從相機獲取照片Android
- HTML絕對路徑與相對路徑HTML
- 根據聲音獲取物件物件
- 根據IP獲取國家
- javascript根據class獲取物件JavaScript物件
- Java中的獲取檔案的物理絕對路徑,和讀取檔案Java
- Create React app 引用中使用絕對路徑ReactAPP
- java獲取硬碟根目錄的本地路徑Java硬碟
- js獲取當前目錄的絕對路徑程式碼例項JS
- 獲取絕對路徑下的檔名和檔案字尾方法
- 好程式設計師分享html圖片絕對路徑改相對路徑程式設計師HTML
- 取系統路徑
- 檔案絕對路徑和相對路徑
- Jsp相對路徑和絕對路徑JS
- 根據 IP 獲取省市名稱
- 根據IP獲取國家省市
- 好程式設計師web前端分享絕對路徑與相對路徑的引用程式設計師Web前端
- Java中獲取URI最後一個路徑段的4種方法Java
- 深入解析Java絕對路徑與相對路徑Java
- 絕對路徑和相對路徑的區別,
- 絕對路徑和相對路徑的區別
- Qt的相對路徑轉為絕對路徑QT
- 智慧線上客服系統原始碼GOFLY開發日誌- 3. 獲取程式執行的絕對路徑原始碼Go