2016년 10월 10일 월요일

[안드로이드] 클립보드 프레임워크 기초

Clipboard 프레임워크

안드로이드는 앱간의 데이터 이동을 위해 OS 차원에서 클립보드를 지원하고 있다. 클립보드를 이용해 공유할 수 있는 데이터 포멧은 다음과 같다.
  • 텍스트 : 단순 문자열.
  • URI : 데이터의 위치를 가리키는 URI. 실제 데이터를 제공하려면 ContentProvider를 구현해야 한다.
  • Intent : 앱 실행 명령과 관련된 데이터.
  • HTML 텍스트 : HTML 형태의 서식있는 문자열. 4.1(API 16)부터 추가되었다.
각 데이터 타입에 따라 MIME 타입을 지정함으로써, 클립보드로부터 데이터를 받는 애플리케이션은 이 MIME 타입을 읽어서 데이터가 무슨 타입인지 판별할 수 있다. 클립보드는 저장 공간이 한개 뿐이므로, 한번에 하나의 데이터만 교환할 수 있다. 클립보드에 새로운 데이터가 들어오면, 기존에 있던 데이터는 삭제된다.(즉, 시스템 차원에서는 히스토리를 제공하지 않는다.)
Clipboard Framework

주요 클래스

ClipboardManager

안드로이드에서 클립보드는 시스템이 관리하는 자원이므로, 애플리케이션이 마음대로 생성, 삭제할 수 없다. 대신, getSystemService(CLIPBOARD)SERVICE) 메서드를 이용해 객체를 얻을 수 있다. 이 객체를 이용해 클립보드에 데이터(ClipData)를 저장하거나, 저장된 데이터(ClipData)를 읽을 수 있다. ClipboardManager는 가장 최근의 ClipData 한개만 가지고 있다.

ClipData

실제로 클립보드에 저장되는 주체로, 한 개 이상의 실제 데이터(ClipData.Item)와, 이 데이터의 메타데이터(ClipDescription)을 포함한다.

ClipDescription

클립보드에 저장될 데이터의 메타데이터를 나타내는 클래스이다. 메타데이터 중에는 원본 데이터의 타입을 가리키는 MIME 타입의 배열을 지정할 수 있는데, 클립보드를 읽는 애플리케이션에서는 이 MIME타입을 읽어서, 처리할 수 있는 데이터를 식별한다.

ClipData.Item

클립보드에 저장되는 실제 데이터. 텍스트, URI, Intent, HTML 텍스트를 저장할 수 있다. ClipData객체에 한개 이상의 Item 객체를 추가할 수 있는데, 이는 다중 선택을 하나의 클립으로 취급하기 때문이다. 단, 여러 item을 ClipData에 추가하려면 item의 데이터 타입이 동일해야 한다.

Copy & Paste

Copy 구현

1.URI 형태로 임의의 데이터를 클립보드에 저장하려면, 해당 URI에 접근했을 때 실제 데이터를 얻을 수 있도록 ContentProvider를 제공한다.
2.ClipboardManager 객체를 얻는다.
3.ClipData 객체를 생성한다.
4.클립보드에 추가한다.
...
// 임의의 메서드
public void copy() {
    // 클립보드 객체 얻기
    ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    // 클립데이터 생성
    ClipData clipData = ClipData.newPlainText("Test Clipboard", "Test");
    // 클립보드에 추가
    clipboardManager.setPrimaryClip(clipData);
    ...
}
...

Paste 구현

1.ClipboardManager 객체를 얻는다.
2.ClipDescription 객체를 얻어서 원하는 MIME 타입인지 조사한다.
3.MIME 타입에 맞게 처리한다.
...
// 임의의 메서드
public void paste() {
    // 클립보드 객체 얻기
    ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    if(!(clipboard.hasPrimaryClip())) {
        // 클립보드 데이터가 있을 때 처리
        ClipData data = clipboard.getPrimaryClip();
        ...
        if(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN)) {
            // MIME 타입이 텍스트일 때 처리
            ...
        }
    }
    ...
}
...

Clipboard 변경시점 알기

ClipboardManager객체에 ClipboardManager.OnPrimaryClipChangedListener 리스너를 등록하면, onPrimaryClipChanged() 메서드를 구현하여 클립보드가 변경되었을 때 콜백을 받을 수 있다.
public class ClipboardService extends Service implements ClipboardManager.OnPrimaryClipChangedListener {
    ClipboardManager mManager;

    @Override
    public void onCreate() {
        super.onCreate();
        mManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
        // 리스너 등록
        mManager.addPrimaryClipChangedListener(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 리스너 해제
        mManager.removePrimaryClipChangedListener(this);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onPrimaryClipChanged() {
        if (mManager != null && mManager.getPrimaryClip() != null) {
            ClipData data = mManager.getPrimaryClip();
            
            // 한번의 복사로 복수 데이터를 넣었을 수 있으므로, 모든 데이터를 가져온다.
            int dataCount = data.getItemCount();
            for (int i = 0 ; i < dataCount ; i++) {
                Log.e("Test", "clip data - item : "+data.getItemAt(i).coerceToText(this));
            }
        } else {
            Log.e("Test", "No Manager or No Clip data");
        }
    }
}

댓글 2개:

  1. 선생님의 글은 언제나 반갑군요.
    이 페이지도 한참 공부할 거리를 주어서 ...
    감사합니다.

    답글삭제
    답글
    1. 부족한 글인데도 반갑게 읽어주시니 감사합니다!!
      저도 아직 배워나가는 중이라서...
      읽다가 아닌 부분 있으면 바로 알려주세요~^^

      삭제