[公式]Evernote API徹底活用レシピ

第8回続・Androidのサンプルコードを実行する

今回は第6回で実行したサンプルコードの解説をします。Androidアプリケーションは、アクティビティという単位で動作します。通常は各アクティビティが各画面に相当します。アクティビティが生成されるとonCreateメソッドが呼ばれますので、画面の初期化処理などはonCreateメソッドをオーバーライドして行います。HelloEDAM.javaの113-122行目がonCreateメソッドの実装になります。

113:  public void onCreate(Bundle savedInstanceState) {
114:    super.onCreate(savedInstanceState);
115:    setContentView(R.layout.main);
116:    
117:    this.msgArea = (TextView)findViewById(R.id.message);
118:    this.btnSave = (Button)findViewById(R.id.save_button);
119:    this.btnSave.setEnabled(false);
120:    
121:    setupApi();
122:  }

114行目でスーパークラスのonCreateメソッドを呼んだ後に、サンプルコード固有の初期化をしています。115行目のsetContentViewが画面の初期化部分で、引数のR.layout.mainが特定の画面を指すIDになっています。

左のPackage ExplorerからHelloEDAM/res/layout/main.xmlを選択してください。このファイルがR.layout.mainに相当します。Graphical Layoutでボタンなどのコンポーネントを配置することで、簡単に画面を作成することができます。

main.xml Graphical Layout
main.xml Graphical Layout

Graphical Layoutで作成した画面は、実際にはXMLで定義されています。下側にあるmain.xmlタブをクリックすると、xmlの中身を確認することができます。もちろん直接xmlを編集することもできます。

main.xml
main.xml

各要素には、android:id="@+id/save_button"のようにandroid:id属性が振られています。この属性値が、アプリケーション側ではR.id.save_buttonというIDとして解釈されるようになっています。たとえば、onCreateメソッド内の(Button)findViewById(R.id.save_button);では、R.id.save_buttonを指定することで、ボタンのインスタンスを取り出しています。

初期化の最後に呼ばれるsetupApiメソッドを見てみましょう。ここではEvernote APIの初期設定をしますが、基本的な処理は第4回で解説した通りですので、そちらを参照してください。通常、通信の初期化の中ではTHttpClientクラスを使用しますが、Evernote APIにはそれをAndroid用に最適化したTAndroidHttpClientが用意されているので、このコードはそれを利用しています。UserStoreやNoteStoreは、以下のようにTAndroidHttpClientを通して作成します。

237:      TAndroidHttpClient userStoreTrans = 
238:        new TAndroidHttpClient(USERSTORE_URL, USER_AGENT, getTempDir());
239:      TBinaryProtocol userStoreProt = new TBinaryProtocol(userStoreTrans);
240:      setUserStore(new UserStore.Client(userStoreProt, userStoreProt));
272:      TAndroidHttpClient noteStoreTrans = 
273:        new TAndroidHttpClient(noteStoreUrl, USER_AGENT, getTempDir());
274:      TBinaryProtocol noteStoreProt = new TBinaryProtocol(noteStoreTrans);
275:      setNoteStore(new NoteStore.Client(noteStoreProt, noteStoreProt))

次は、ギャラリーから画像を選択する部分です。main.xmlに戻って、13-17行目を見てください。これが⁠Select Image...⁠ボタンの定義になります。android:onClick属性で、ボタンがクリックされたときに呼び出されるメソッドを指定します。ここではstartSelectImageメソッドになります。

13:    <Button android:id="@+id/select_button" 
14:         android:layout_height="wrap_content"
15:         android:layout_width="wrap_content"
16:         android:text="@string/label_select_button"
17:         android:onClick="startSelectImage" />

startSelectImageメソッドはHelloEDAM.javaの129-133行目にあります。AndroidではIntentという機能を通して別のアクティビティを起動することで、アクティビティ間の連携を行えます。ここでは画像選択の機能をIntentで呼び出しています。

129:  public void startSelectImage(View view) {
130:    Intent intent = new Intent(Intent.ACTION_PICK, 
131:                               MediaStore.Images.Media.INTERNAL_CONTENT_URI);
132:    startActivityForResult(intent, SELECT_IMAGE);
133:  }

呼び出したアクティビティから制御が戻ると、onActivityResultメソッドが呼ばれます。ここでstartSelectImageから戻ってきた場合かどうかを判断して、endSelectImageメソッドを呼び出しています。

139:  public void onActivityResult(int requestCode, int resultCode, Intent data) {
140:    super.onActivityResult(requestCode, resultCode, data);
150:    if (requestCode == SELECT_IMAGE)
151:      // 我々の'startSelectImage'アクションからのコールバック
152:      if (resultCode == Activity.RESULT_OK) {
153:        endSelectImage(data);
154:      } 
155:  }

endSelectImageメソッドでは、画像選択で指定した画像データを取り出しています。

154:  private void endSelectImage(Intent data) {
155:    // ギャラリーからのコールバックはテーブルへのポインタを含んでいる。
156:    // 適切なレコードをルックアップして必要な情報を引き出す。
157:    // 以下の場合はディスク上のファイルのパスとファイル名、MIMEタイプになる。
158:    Uri selectedImage = data.getData();
159:    String[] queryColumns = { MediaStore.Images.Media.DATA, 
160:                              MediaStore.Images.Media.MIME_TYPE, 
161:                              MediaStore.Images.Media.DISPLAY_NAME };
162:    Cursor cursor = getContentResolver().query(selectedImage, queryColumns, null, null, null);
163:    cursor.moveToFirst();
164:    this.filePath = cursor.getString(cursor.getColumnIndex(queryColumns[0]));
165:    this.mimeType = cursor.getString(cursor.getColumnIndex(queryColumns[1]));
166:    this.fileName = cursor.getString(cursor.getColumnIndex(queryColumns[2]));
167:    cursor.close();
168:
169:    if (getNoteStore() != null) {
170:      this.msgArea.setText(this.fileName);
171:      this.btnSave.setEnabled(true);
172:    }
173:  }

選択した画像をEvernoteに保存するには、⁠Save Image⁠ボタンを押します。⁠Save Image⁠ボタンのonClickに設定されているのはsaveImageメソッドですので、saveImageメソッドの中身を見ましょう。重要なのは191行目です。画像ファイルをEvernoteのFileDataとするときに、ファイルのmd5ハッシュ値を算出しています。このハッシュ値は後でen-mediaから参照するときに使います。Evernoteにメディアデータを保存するときには、この作業が必須になります。

190:        InputStream in = new BufferedInputStream(new FileInputStream(f)); 
191:        FileData data = new FileData(EDAMUtil.hash(in), new File(f));
192:        in.close();

Resourceを作成して、先ほどのFileDataとMIMEタイプとセットで登録します。

195:        Resource resource = new Resource();
196:        resource.setData(data);
197:        resource.setMime(this.mimeType);

次にノートを作成して、ノートにタイトルとResourceを加えます。

200:        Note note = new Note();
201:        note.setTitle("Android test note");
202:        note.addToResources(resource);

ノートの内容はENMLで記述する必要があります。ENML内で画像を置きたい場所に、en-media要素を追加します。en-mediaの属性として、先ほど作成したリソースと同じMIMEタイプとハッシュ値を設定します。もしリソースに対応するen-media要素がENML内に存在しないと、画像がノートに載りませんので注意してください。

207:        String content = 
208:          NOTE_PREFIX +
209:          "<p>This note was uploaded from Android. It contains an image.</p>" +
210:          "<en-media type=\"" + this.mimeType + "\" hash=\"" +
211:          EDAMUtil.bytesToHex(resource.getData().getBodyHash()) + "\"/>" +
212:          NOTE_SUFFIX;
213:        note.setContent(content);

最後にNoteStoreのcreateNoteメソッドを呼び出せば、Evernoteのサーバにノートが保存されます。

218:        Note createdNote = getNoteStore().createNote(getAuthToken(), note);

Androidサンプルコードの解説は以上です。次回はこのコードをベースに、機能追加をしてみたいと思います。

おすすめ記事

記事・ニュース一覧