适用于所有 API 级别的 Android 剪贴板代码

Posted

技术标签:

【中文标题】适用于所有 API 级别的 Android 剪贴板代码【英文标题】:Android clipboard code that works on all API levels 【发布时间】:2012-02-20 02:35:16 【问题描述】:

适用于 API 级别 = 11 的设备上崩溃。

适用于 API 级别 >= 11 的剪贴板代码在 API 级别

我无法为这两个版本编译代码,因为它们有冲突的导入要求。

一个需求: 导入android.text.ClipboardManager;

而其他需要: 导入 android.content.ClipboardManager;

当然有一种方法可以编写一些适用于 API 级别 11 双方的代码。我就是想不通。

***已编辑(因为我无法回答自己的问题)*******

我发现了问题。异常消息说:“无法在未调用 Looper.prepare() 的线程内创建处理程序。”

显然,由于我是从异步任务执行此代码,因此我必须跳过更多的障碍。

【问题讨论】:

您应该只从主应用程序线程运行此代码,例如您的AsyncTaskonPostExecute() 【参考方案1】:

我最近遇到了类似的问题。 以下是我的处理方式。

int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB)
     android.content.ClipboardManager clipboard =  (android.content.ClipboardManager) getSystemService(CLIPBOARD_SERVICE); 
        ClipData clip = ClipData.newPlainText("label", "Text to Copy");
        clipboard.setPrimaryClip(clip); 
 else
    android.text.ClipboardManager clipboard = (android.text.ClipboardManager)getSystemService(CLIPBOARD_SERVICE); 
    clipboard.setText("Text to Copy");

Toast.makeText(getApplicationContext(), "Text copied to clipboard", Toast.LENGTH_SHORT).show();

我不完全确定第一个 if 块是否必要。但我宁愿不要冒险:)

【讨论】:

这里的label 是什么? @SrujanBarai - label 是剪辑数据的用户可见标签。这个label 字段主要由剪贴板管理器应用程序用作复制的剪辑数据的标题。更多信息请参考:developer.android.com/reference/android/content/…, java.lang.CharSequence)【参考方案2】:

避免异常

[FATAL EXCEPTION: GLThread 6132  java.lang.RuntimeException: 
Can't create handler inside thread that has not called Looper.prepare() ], 

-> 只需在启动时创建一次ClipboardManager,例如在您的onCreate() 方法中,然后随时在单独的函数中使用它

在 2.3.3 和 4.0.3 上测试过:

import android.text.ClipboardManager;
import android.content.ClipData;
..
public class myActivity extends Activity

  private static ClipboardManager m_ClipboardManager;

  @Override
  protected void onCreate(..)
  
    ...
   m_ClipboardManager = (ClipboardManager)     m_sInstance.getSystemService(Context.CLIPBOARD_SERVICE); 
  

  public static void myCopyToClipBoard(String sTxt)
  
    m_ClipboardManager.setText(sTxt);
  

【讨论】:

【参考方案3】:

适用于 API 级别 = 11 的设备上崩溃。

This sample project 在 11 前后的 API 级别上运行良好。我刚刚在 Android 2.3 (Nexus One) 和 Android 4.0 (Nexus S) 上重新测试了它。

适用于 API 级别 >= 11 的剪贴板代码在 API 级别

这并不奇怪。如果您指的是旧版本 Android 中不存在的类或方法,您将收到 VerifyError 或类似的崩溃。

我无法为这两个版本编译代码,因为它们有冲突的导入要求。

不是真的。

一个需求:导入android.text.ClipboardManager;

这适用于所有 API 级别。

而其他需要:import android.content.ClipboardManager;

这已添加到 API 级别 11。如果您的应用只能在 API 级别 11 或更高级别上运行,请使用此类(方法签名都是相同的 IIRC)。

【讨论】:

我在 4.0 模拟器上运行了几乎相同的代码。当我执行“ClipboardManager cm=(ClipboardManager)getSystemService(CLIPBOARD_SERVICE);”我得到:01-26 16:27:10.886: W/AsyncTask(725): java.lang.InterruptedException 好的,您的代码正在运行,但仍然显示不推荐使用的方法警告。以后会不会有问题???我的意思是该方法将来会被永远删除吗???【参考方案4】:

自己编写自己的剪贴板兼容类,例如:

import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.Context;
import android.net.Uri;


public class ClipboardCompat 
    private android.content.ClipboardManager currentCM=null;
    private android.text.ClipboardManager legacyCM=null;

    public ClipboardCompat() 
        if(android.os.Build.VERSION.SDK_INT >= 11 && currentCM == null) 
            currentCM = (android.content.ClipboardManager)
                    [getsomecontext].getSystemService(Context.CLIPBOARD_SERVICE);
        
        else if(legacyCM == null)
        
            legacyCM = (android.content.ClipboardManager)
                    [getsomecontext].getSystemService(Context.CLIPBOARD_SERVICE);
        
    

    @SuppressLint("NewApi")
    public String getText() 
        if(currentCM!=null) 
            try
                return currentCM.getPrimaryClip().getItemAt(0).getText().toString();
             catch (NullPointerException e) 
                return null;
            
        
        else
        
            try
                return legacyCM.getText().toString();
             catch (NullPointerException e) 
                return null;
            
        
    

    @SuppressLint("NewApi")
    public Uri getUri() 
        if(currentCM!=null) 
            try
                return currentCM.getPrimaryClip().getItemAt(0).getUri();
             catch (NullPointerException e) 
                return null;
            
        
        else
        
            return null;
        
    

    @SuppressLint("NewApi")
    public void set(String name, String s) 
        if(currentCM!=null) 
            ClipData clip = ClipData.newPlainText(name, s);
            currentCM.setPrimaryClip(clip);
        
        else
        
            legacyCM.setText(s);
        
    

    @SuppressLint("NewApi")
    public void set(String name, Uri u) 
        if(currentCM!=null) 
            ClipData clip = ClipData.newRawUri(name, u);
            currentCM.setPrimaryClip(clip);
        
        else
        
            legacyCM.setText(u.toString());
        
    

【讨论】:

以上是关于适用于所有 API 级别的 Android 剪贴板代码的主要内容,如果未能解决你的问题,请参考以下文章

如果我在 API 级别 21 (5.0) 上制作应用程序,它是不是适用于较新版本的 android?

在所有 android 设备中获取多个 imei 号码

@TargetApi 注释是不是仅适用于一个 Api 级别或更高级别?

android中的camera和camera2权限

如何允许较低 Android API 级别的用户下载较高 API 级别版本的应用程序?

适用于 Android 的 Google Places API 未显示