ClipboardManager OnPrimaryClipChangedListener is called twice for each copy

When I copy text to the clipboard, the onPrimaryClipChanged method is called twice. Any ideas why?

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
    final ClipboardManager cliboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);

    cliboardManager
            .addPrimaryClipChangedListener(new OnPrimaryClipChangedListener() {

                @Override
                public void onPrimaryClipChanged() {
                    ClipData clipData = cliboardManager.getPrimaryClip();
                    System.out
                            .println("********** clip changed, clipData: "
                                    + clipData.getItemAt(0));
                }
            });
    return true;
}

      

Test case: Copying the text "continue" from the BBC website produces the following output:

proceed

proceed

But if I debug the program I can see that the clipData object has a value:

ClipData {text / plain {T: continue}}

the first time onPrimaryClipChanged () is called and

ClipData {text / plain "BBC - Homepage" {T: continue}}

next time onPrimaryClipChanged () is called.

So the first time ClipDescription is {text / plain} and the second is ClipDescription {text / plain "BBC - Homepage"} (ie including the webpage title)

+2


source to share


4 answers


I'm assuming you haven't registered multiple listeners, I can't say this is a bug, you can still work around it. Try something like this:



   String mPreviousText = "";

   cliboardManager
                .addPrimaryClipChangedListener(new OnPrimaryClipChangedListener() {

                    @Override
                    public void onPrimaryClipChanged() {
                        ClipData clipData = cliboardManager.getPrimaryClip();
                        System.out
                                .println("********** clip changed, clipData: "
                                        + clipData.getItemAt(0));
                         ClipData.Item item = clipData.getItemAt(0);
                         if(mPreviousText.equals(item.getText().toString())) return;
                         else{
                            /// do something
                            mPrevousText = item.getText().toString();
                         }
                    }
                });

      

+8


source


I face this problem too, finally I know why it will call many times !!!

Usually we are addPrimaryClipChangedListener()

, but we are not removePrimaryClipChangedListener()

.

See: http://developer.android.com/reference/android/content/Context.html#CLIPBOARD_SERVICE

Use with getSystemService (String) to retrieve the ClipboardManager to access and modify the contents of the global clipboard.



This means we have to removePrimaryClipChangedListener()

manually!

My solution code:

ClipboardManager myClipBoard ;
static boolean bHasClipChangedListener = false;

ClipboardManager.OnPrimaryClipChangedListener mPrimaryClipChangedListener = new ClipboardManager.OnPrimaryClipChangedListener() {
    public void onPrimaryClipChanged() {
        ClipData clipData = myClipBoard.getPrimaryClip();
        Log.d("henrytest", "********** clip changed, clipData: " + clipData.getItemAt(0));
    }
};

private void RegPrimaryClipChanged(){
    if(!bHasClipChangedListener){
        myClipBoard.addPrimaryClipChangedListener(mPrimaryClipChangedListener);
        bHasClipChangedListener = true;
    }
}
private void UnRegPrimaryClipChanged(){
    if(bHasClipChangedListener){
        myClipBoard.removePrimaryClipChangedListener(mPrimaryClipChangedListener);
        bHasClipChangedListener = false;
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    myClipBoard = (ClipboardManager) Clipboard.this.getSystemService(android.content.Context.CLIPBOARD_SERVICE);
}

@Override
protected void onResume() {
    super.onResume();
    RegPrimaryClipChanged();
}

@Override
protected void onPause() {
    super.onPause();
    UnRegPrimaryClipChanged();
}

@Override
protected void onStop() {
    super.onStop();
    //UnRegPrimaryClipChanged();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    //UnRegPrimaryClipChanged();
}

      

+4


source


// Prevent duplication of action OnPrimaryClipChangedListener.

private ExecutorService mThreadPool = Executors.newSingleThreadExecutor();
static boolean isExpireData = true;

class hasExpireData implements Runnable {

    @Override
    public void run() {
        // TODO Auto-generated method stub

        isExpireData = true;
    }

}

private ClipboardManager.OnPrimaryClipChangedListener mOnPrimaryClipChangedListener =
        new ClipboardManager.OnPrimaryClipChangedListener() {
    @Override
    public void onPrimaryClipChanged() {
        Log.d(TAG, "onPrimaryClipChanged");
        ClipData clip = mClipboardManager.getPrimaryClip();

        Thread expireData = new Thread(new hasExpireData());
        new Handler().postDelayed(expireData, 500); // 0.5 seconds wait...

        if(isExpireData) {
            isExpireData = false;
            mThreadPool.execute(new TextRunnable(
                    clip.getItemAt(0).getText()));
        }

    }
};

private class TextRunnable implements Runnable {
    public TextRunnable(CharSequence text) {
        // text store to this class
    }

    @Override
    public void run() {
        // text other process
    }
}

      

0


source


This is my workaround for preventing the ClipboardManager OnPrimaryClipChangedListener from being called twice for each copy.

long lastCopiedTime = 0;
ClipboardManager.OnPrimaryClipChangedListener onPrimaryClipChangedListener = new ClipboardManager.OnPrimaryClipChangedListener() {
    @Override
    public void onPrimaryClipChanged() {
                ClipboardManager clipBoard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
                String pasteData = "";
                ClipData.Item item = clipBoard.getPrimaryClip().getItemAt(0);
                if (System.currentTimeMillis() - lastCopiedTime > TimeUnit.SECONDS.toMillis(1)) {
                    if (StringUtils.isNotBlank(item.getText())) {
                        String s = item.getText().toString();
                        if (StringUtils.isNotBlank(s)) {
                            pasteData = s.trim();
                            if (StringUtils.isNotBlank(pasteData)) {
                                  /// do something here
                            }
                        }
                    }
                }
                lastCopiedTime = System.currentTimeMillis();
            }
        }
    }
};

      

0


source







All Articles