最近開發(fā)過程中有使用到復制/粘帖功能侣诵,也在其中遇到了一些問題,就順勢學習一下復制粘貼相關的知識峦筒。
一氏义、前言
Android提供了一個強大的剪切板框架(以至于在復制某些內容粘帖到我的項目中的時候出現(xiàn)的格式問題的BUG)用于復制和粘帖锄列。同時支持簡單和復雜的數(shù)據(jù)類型,簡單的文本數(shù)據(jù)直接存儲在剪貼板中惯悠,而復雜的數(shù)據(jù)存儲為一個引用邻邮,即粘貼應用程序解析為內容提供者(這里涉及到ContentProvider)。
二克婶、框架&使用
要復制數(shù)據(jù)筒严,應用程序將
ClipData
對象放在ClipboardManager
全局剪貼板上。它ClipData
包含一個或多個ClipData.Item
對象和一個ClipDescription
對象情萤。要粘貼數(shù)據(jù)鸭蛙,應用程序會從中ClipData
獲取其MIME類型ClipDescription
,并從ClipData.Item
或從內容提供者 獲取數(shù)據(jù)ClipData.Item
筋岛。
可以看出Android
剪貼板框架主要涉及到ClipboardManager
娶视、ClipData
、ClipData.Item
睁宰、ClipDescription
這四個類歇万,下面詳細說明
-
ClipboardManager
是系統(tǒng)全局的剪貼板對象,通過context.getSystemService(CLIPBOARD_SERVICE)
獲取勋陪。 -
ClipData
贪磺,即clip
(剪切)對象,在系統(tǒng)剪貼板里只存在一個诅愚,當另一個clip
對象進來時寒锚,前一個clip
對象會消失。 -
ClipData.Item
违孝,即 data item刹前,它包含了文本、Uri
或者Intent
數(shù)據(jù)雌桑,一個clip
對象可以包含一個或多個Item
對象喇喉。通過addItem(ClipData.Item item)
可以實現(xiàn)往clip
對象中添加Item
。- 文本:文本是直接放在
clip
對象中校坑,然后放在剪貼板里拣技;粘貼這個字符串的時候直接從剪貼板拿到這個對象,把字符串放入你的應用存儲中耍目。 - Uri:對于復雜數(shù)據(jù)的剪貼拷貝并不是直接將數(shù)據(jù)放入內存膏斤,而是通過
Uri
來實現(xiàn),畢竟Uri
的中文名叫:統(tǒng)一資源標識符邪驮。通過Uri
能定位手機上所有資源莫辨,這當然能實現(xiàn)拷貝了,只不過需要做一些額外的處理工作。(對于Uri
不是很理解沮榜,如有誤盘榨,望指正~) -
Intent
:復制的時候Intent
會被直接放入clip
對象,這相當于拷貝了一個快捷方式蟆融。
- 文本:文本是直接放在
-
ClipDescription
草巡,即clip metadata
,它包含了ClipData
對象的metadata
信息振愿〗萦蹋可以通過getMimeType(int index)
獲取(一般index = 0
冕末,有興趣的可以去看下ClipData
的源碼)萍歉。MimeType
一般有以下四種類型:
// 對應 ClipData.newHtmlText(label, text, htmlText) 的 MimeType
public static final String MIMETYPE_TEXT_HTML = "text/html";
// 對應 ClipData.newIntent(label, intent) 的 MimeType
public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";
// 對應 ClipData newPlainText(label, text) 的 MimeType
public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
// 對應 ClipData newPlainText(label, text) 的 MimeType
public static final String MIMETYPE_TEXT_URILIST = "text/uri-list";
接下來看看簡單的使用,以文本操作為例
public void putTextIntoClip(Context context){
ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
//創(chuàng)建ClipData對象
ClipData clipData = ClipData.newPlainText("simple text copy", "Clipboard test.");
//添加ClipData對象到剪切板中
clipboardManager.setPrimaryClip(clipData);
}
創(chuàng)建ClipData
的方法還有另外四個:
//創(chuàng)建一個包含 htmlText 的 ClipData
//一般在瀏覽器中對網(wǎng)頁進行拷貝的時候會調用此方法,其中 htmlText 是包含 HTML 標簽的字符串
public static ClipData newHtmlText(CharSequence label, CharSequence text, String htmlText)
//創(chuàng)建一個包含 Intent 的 ClipData
public static ClipData newIntent(CharSequence label, Intent intent)
//創(chuàng)建一個包含 Uri 的 ClipData档桃,MimeType 會根據(jù) Uri 進行修改
public static ClipData newUri(ContentResolver resolver, CharSequence label, Uri uri)
//與 newUri 相對應枪孩,但是并不會根據(jù) Uri 修改 MimeType
public static ClipData newRawUri(CharSequence label, Uri uri)
從剪切板中獲取數(shù)據(jù),同樣以文本操作為例
public void getTextFromClip(Context context){
ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
//判斷剪切版時候有內容
if(!clipboardManager.hasPrimaryClip())
return;
ClipData clipData = clipboardManager.getPrimaryClip();
//獲取 ClipDescription
ClipDescription clipDescription = clipboardManager.getPrimaryClipDescription();
//獲取 lable
String lable = clipDescription.getLabel().toString();
//獲取 text
String text = clipData.getItemAt(0).getText().toString();
}
順帶說一下之前遇到的問題藻肄,我boss直接從網(wǎng)易新聞復制了內容蔑舞,粘帖到我們自己的app中,之后文本的樣式都不對嘹屯,這是因為復制的內容是包含HTML標簽的字符串攻询,導致內容顯示有問題,
String text = clipData.getItemAt(0).coerceToText(context).toString();
最后使用coerceToText()
將剪貼板數(shù)據(jù)強制轉換為文本解決問題州弟。
三钧栖、官方建議
Designing Effective Copy/Paste Functionality
To design effective copy and paste functionality for your application, remember these points:
At any time, there is only one clip on the clipboard. A new copy operation by any application in the system overwrites the previous clip. Since the user may navigate away from your application and do a copy before returning, you can't assume that the clipboard contains the clip that the user previously copied in your application.
The intended purpose of multiple ClipData.Item objects per clip is to support copying and pasting of multiple selections rather than different forms of reference to a single selection. You usually want all of the ClipData.Item objects in a clip to have the same form, that is, they should all be simple text, content URI, or Intent, but not a mixture.
When you provide data, you can offer different MIME representations. Add the MIME types you support to the ClipDescription, and then implement the MIME types in your content provider.
When you get data from the clipboard, your application is responsible for checking the available MIME types and then deciding which one, if any, to use. Even if there is a clip on the clipboard and the user requests a paste, your application is not required to do the paste. You should do the paste if the MIME type is compatible. You may choose to coerce the data on the clipboard to text using coerceToText() if you choose. If your application supports more than one of the available MIME types, you can allow the user to choose which one to use.
為設計有效的復制和粘貼功能,請記住以下幾點:
- 任何時候婆翔,剪切板只有一個
clip
拯杠。系統(tǒng)中任何一個app的復制操作都會覆蓋上一次操作。用于用戶可以到導航你的app啃奴,在返回之前復制一次潭陪,你不能假設剪切板中包含用戶在你的app中復制剪切的數(shù)據(jù)。 -
clip
的多個ClipData.Item
對象是支持復制和粘貼多個選擇最蕾,而不是對單個選擇的不同形式的引用依溯。你通常希望ClipData.Item剪輯中的所有 對象具有相同的形式,即它們應該是簡單的文本揖膜,內容URI或者Intent混合誓沸。 - 當你提供數(shù)據(jù)是,你可以提供不同的MIME屬性壹粟,添加MIME類型到
ClipDescription
中,然后在內容提供者中事項MIME類型。 - 當你獲取剪切板的數(shù)據(jù)時趁仙,你的app檢查MIME類型的可用性然后確定使用的MIME類型洪添。即使用戶請求粘帖剪切板上的數(shù)據(jù),你的app也不是需要粘帖的雀费。如果MIME類型兼容你應該粘帖干奢。你也可以選擇用
coerceToText()
方法強制將數(shù)據(jù)轉化為文本。如果你的app支持多種MIME類型盏袄,你可能允許用戶選擇使用MIME類型
參考資料:
API Guides: Copy and Paste:
https://developer.android.com/guide/topics/text/copy-paste.html#Provider