背景
有时候我们需要在app启动时去获取用户复制的内容,这时候需要进行剪切板相关操作,而Android Q开始只有系统默认的输入法应用或者应用处于焦点时才能获取到剪切板的数据,经测试只有targetSdkVersion和设备型号均为Android Q以上时此规则才会生效。

原来获取剪切板的操作如下:

ClipboardManager clipboardManager = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clipData = clipboardManager.getPrimaryClip();

现在Android Q的api说明如下

   /**
     * Returns the current primary clip on the clipboard.
     *
     * <em>If the application is not the default IME or does not have input focus this return
     * {@code null}.</em>
     *
     * @see #setPrimaryClip(ClipData)
     */
    public @Nullable ClipData getPrimaryClip() {
        try {
            return mService.getPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

网上的解决方法一般如下:

    @Override
    protected void onResume() {
        super.onResume();
        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                //剪切板相关操作
            }
        });
    }

这种解决方式有一些问题,如果该activity有跳转至其他应用的情况,可能当执行这段方法时正好处于未获取焦点状态导致获取失败,另外在有的情况,我们可能没法获取到activity的示例,在一些服务或者android sdk的开发中,并不能知道当前应用是否已经获取到焦点,此时我们可以采取如下做法:获取剪切板数据时采取重试的方式,获取失败后重试三次,第一次等待20ms,第二次等待40ms,第三次等待60ms,然后监听应用启动和从后台切换到前台的情况来执行上述获取剪切板的操作。

示例代码如下:

 registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            private int count = 0;
            @Override
            public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
            }

            @Override
            public void onActivityStarted(@NonNull Activity activity) {
                if (count++ == 0) {
                    // 应用首次启动或者是从后台切换到前台
                    ClipUtils.getClipData(getApplicationContext(), new ClipUtils.GetClipCallback() {
                        @Override
                        public void execute(String clipData) {
                        }
                    });
                }
            }

            @Override
            public void onActivityResumed(@NonNull final Activity activity) {
            }

            @Override
            public void onActivityPaused(@NonNull Activity activity) {

            }

            @Override
            public void onActivityStopped(@NonNull Activity activity) {
                count--;
            }

            @Override
            public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {

            }

            @Override
            public void onActivityDestroyed(@NonNull Activity activity) {

            }
        });
public class ClipUtils {
    private static final int MAX_RETRY_TIME = 3;
    private static final int FIRST_TIME_DELAY = 20;// 首次等待20ms
    private static final int DELAY_TIME_ADD = 20; // 每次增加20ms

    static class GetFormAndroidQTask implements Runnable {
        private int retryTime = 0;
        private Handler mHandler;
        private Context mContext;
        private GetClipCallback mGetClipCallback;
        GetFormAndroidQTask(Context context, Handler handler, GetClipCallback getClipCallback) {
            mHandler = handler;
            mContext = context;
            mGetClipCallback = getClipCallback;
        }

        public void run() {
          ClipboardManager clipboardManager = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData clipData = clipboardManager != null ? clipboardManager.getPrimaryClip() : null;
            if (clipData != null) {
                String data = getData(clipboardManager, clipData);
                mGetClipCallback.execute(data);
                return;
            }
            retryTime++;
            if (retryTime < MAX_RETRY_TIME) {
                mHandler.postDelayed(this, FIRST_TIME_DELAY  + retryTime * DELAY_TIME_ADD);
            }
        }
    }

    public static void getClipData(Context context, GetClipCallback clipCallback) {
        String data = null;
        try {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
                ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
                ClipData clipData = clipboardManager != null ? clipboardManager.getPrimaryClip() : null;
                // 如果是android Q执行重试逻辑
                if (clipData == null && android.os.Build.VERSION.SDK_INT >= 29) {
                    Handler handler = new Handler(context.getMainLooper());
                    handler.postDelayed(new GetFormAndroidQTask(context, handler, clipCallback), FIRST_TIME_DELAY);
                    return;
                }
                data = getData(clipboardManager, clipData);
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
        clipCallback.execute(data);
    }

    private static String getData(ClipboardManager clipboardManager, ClipData clipData) {
        CharSequence data = null;
        if (clipData!= null && clipData.getItemCount() > 0) {
            data = clipData.getItemAt(0).getText();
        }
        // 清空剪切板
         clipboardManager.setPrimaryClip(ClipData.newPlainText(null, ""));
        return data != null ? data.toString() : null;
    }

    public interface GetClipCallback {
        void execute(String clipData);
    }
}