万人のためのモバイル: Overheard Word アプリでの単語とジェスチャー

サード・パーティーのコードをプログラムによって Android UI に統合する

大喜びで、GitHub や他のリポジトリーからサード・パーティーのコードを手に入れたとしても、そのコードを Android UI に統合するには、いくつかのコツがあります。今回の記事では、Andrew Glover が JSON ベースの単語エンジンと既製のスワイプ・ジェスチャー機能を使用して、Overheard Word デモ・アプリを機能強化する方法を説明します。この記事を読むとわかるように、Android にサード・パーティーのコードを取り込むのは簡単ですが、アプリの UI にサード・パーティーのコードをスムーズに実行させようと思ったら、ロジックを慎重に作成する必要があります。

Andrew Glover, Author and developer, App47

Andrew GloverAndrew Glover は開発者であり、モバイル・テクノロジーにはまっています。現在 App47 の CTO を務める彼は、easyb BDD (Behavior-Driven Development) フレームワークの作成者でもあり、『継続的インテグレーション入門 開発プロセスを自動化する 47 の作法』、『Groovyイン・アクション』、『Java Testing Patterns』の 3 冊の本の共著者でもあります。彼の最新情報を追うには、ブログを読むか、Twitter でフォローしてください。



2013年 7月 25日

皆さんがこの連載のこれまでの記事を読んでデモに従っているとしたら、基本的な Android 開発スキルは身に付いているはずです。前回までの記事で、Android 開発環境をセットアップして最初の Hello World アプリを作成しただけでなく、ボタンのタップをスワイプ・ジェスチャーに置き換えて、カスタム・モバイル・アプリにメニュー (またはアクション・バー) とアイコンを実装する方法も説明しました。今回の記事では引き続きこれまでの流れに従い、サード・パーティー・ライブラリーを使用してアプリの機能を追加または強化する方法を説明します。記事ではまず、いくつかのオープンソース・ライブラリーをインストールして、これらのファイルを読み込んだ後、その新しい機能をプログラムによってデモ・アプリの UI に統合します。

これまでの記事と同様に、デモ・アプリとして Overheard Word を使用します。このアプリがお手元にない場合は、Overheard Word の GitHub リポジトリーを複製して、手順に従えるようにしてください。

この連載について

モバイル・アプリの配布が急増するなか、モバイル開発のスキルを要する市場が急成長しています。この developerWorks の連載では、プログラミングの経験は積んでいても、モバイルの世界でのプログラミングには馴染みのない開発者を対象に、モバイルの世界でのプログラミングをわかりやすく紹介します。まず Java コードでネイティブ・アプリを作成することから始め、JVM 言語、スクリプティング・フレームワーク、HTML5/CSS/JavaScript、サード・パーティー・ツールなどを使いこなせるようにモバイル開発のスキルを磨いていきます。ステップ・バイ・ステップで、ほとんどどのようなモバイル開発シナリオにも対応できるだけのスキルをマスターしてください。

Thingamajig: プラガブルな単語エンジン

Overheard Word は、ユーザーが簡単に新しい単語を学んでボキャブラリーを増やしていくための英語のアプリです。これまでの記事で、基本的なアプリを開発した後、ナビゲートしやすくするためのスワイプ・ジェスチャーと、UI に磨きをかけるためのアイコンを追加しました。ここまでは順調に進んでいますが、ある特定の構成要素がなければ、Overheard Word は使えないアプリになってしまいます。そうです、Overheard Word には単語が必要なのです!

Overheard Word を、単語を扱う真のアプリにするために、単語の概念とそれに対応する定義をカプセル化する Thingamajig という小さな単語エンジンを作成しました。Thingamajig は、JSON 文書を使用して単語とその定義を作成するという処理を行い、Android には一切依存しません。Overheard Word アプリと同じく、この単語エンジンは GitHub でホストされています。該当するリポジトリーを複製するか、ソースをダウンロードしてから、ant を実行してください。

すると、8KB の軽量な JAR ファイルが生成されるので、このファイルを libs ディレクトリーにコピーしてください。Android プロジェクトが正しくセットアップされていれば、IDE が libs ディレクトリー内のファイルを依存関係として自動的に認識するはずです。

差し当たり、単語エンジン内のコードは JSON 文書インスタンスを介して初期化されるようになっています。この JSON 文書として使用できるのは、端末上のファイルシステムに置かれたファイル、HTTP リクエストへのレスポンス、さらにはデータベース・クエリーに対するレスポンスなどですが、現時点では、それは重要ではありません。何が重要かと言えば、Word オブジェクトを扱えるようにするための賢いライブラリーを用意することです。各 Word オブジェクトには、Definition オブジェクトのコレクションと、対応する品詞が格納されます。単語とその定義に関係するものは、これだけではありませんが、現段階ではこれで十分です。後から例文、同義語、反義語などを追加することができます。


Android でのサード・パーティー・ライブラリー

サード・パーティー・ライブラリーを Android プロジェクトに統合するのは至って簡単です。実際、Android プロジェクトを新規に作成すると、サード・パーティーの JAR を配置できる libs という特別なディレクトリーがプロジェクトに組み込まれます。Android ビルド・プロセスでは、通常の JVM ファイルとサード・パーティーの JAR の両方が、Android に特化された Dalvik という VM に対応するように変換されます。

環境に関する制約

アプリには考えられる限りのあらゆるサード・パーティー・ライブラリーを追加できるはずですが、モバイル環境に伴う制約を決して忘れないでください。結局のところ、アプリを実行する端末は、強力な処理能力を持つ Web サーバーではありません。処理能力を浪費しないようにして、サード・パーティー・アドオンのダウンロード・サイズを最小限にすれば、ユーザーにとってはありがたいはずです。

デモ・アプリには単語エンジン・ライブラリーを組み込む他、Gesticulate という名前の別のサード・パーティー・アプリも追加しようと思います。単語エンジン・ライブラリーと同様に、Gesticulate を取得するには、GitHub からそのソース・コードを複製するか、ダウンロードしてください。その後、ant を実行すると、アプリの libs ディレクトリーにコピーできる JAR ファイルが生成されます。


UI を更新する

いよいよ、記事の核心に入ります。それは、UI を更新して、無料で手に入れたサード・パーティー・コードをすべて統合することです。幸い Overheard Word アプリでは、このことをあらかじめ計画してあります。アプリを最初にひととおり作成したときに、図 1 に示すように、単語、単語の品詞、および単語の定義からなる単純なレイアウトを定義しました。

図 1. Overheard Word のデフォルト・ビュー
Overheard Word アプリの画面に表示されたデフォルト・ビュー

レイアウトの定義には、プレースホルダー・テキストが使用されています。これから、このプレースホルダー・テキストを、プラガブルな単語エンジンから取得される実際の単語に置き換えます。そのためには、一連の単語を初期化してから 1 つの単語を取得し、その単語の値を使用して UI を更新します。

UI を更新するには、個々のビュー要素のハンドルを取得して、これらの要素に値を提供しなければなりません。例えば、表示対象の Pedestrian (歩行者) という単語は、リスト 1 に示されているように、ID が word_study_word に設定された TextView として定義されます。

リスト 1. レイアウトに定義された TextView
 <TextView
        android:id="@+id/word_study_word"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="10dp"
        android:layout_marginTop="60dp"
        android:textColor="@color/black"
        android:textSize="30sp" 
        android:text="Word"/>

よく見てみると、テキストは XML で “Word” に設定されていますが、TextView インスタンスへの参照を取得して setText を呼び出すことで、テキストの値をプログラムによって設定することができます。

作業を進める前に、単語のリストを作成する必要があります。前にも説明しましたが、私の単語エンジンは JSON 文書を介して Word インスタンスを作成することができるので、これらのカスタム・ファイルを組み込んで読み込むように Android アプリをセットアップするだけで、単語のリストを作成することができます。

ファイルを扱う: res および raw ディレクトリー

Android アプリには、デフォルトで、端末のファイルシステムへの読み取りアクセス権が与えられますが、アクセスできるのは、アプリの配下にあるローカル・ファイルシステムのみです。したがって、必要なファイルをアプリに組み込むことで、それらのファイルを参照することができます (つまり、アプリのローカルにあるファイルを読み書きできるということです。アプリの外部にあるファイルシステム (SD カードなど) に書き込むには、特別なパーミッションが必要になります)。私が作成した単語エンジンは、JSON 文書を取得して単語のリストを初期化することができるため、アプリが実行時に読み込む JSON 文書を組み込まない理由は何もありません。

前回の記事で紹介したアイコン・アセットと同じく、ファイルは res ディレクトリーに格納することができます。カスタム・ファイルが必要なことがわかったら、それらのファイルは raw というディレクトリーに追加したいと思います。そのディレクトリーに格納するファイルは、Overheard Word でこれまでに何度か使用した、生成される R ファイルを介して参照することができます。基本的に、Android プラットフォームは res ディレクトリーからアセットを取得して R というクラスを作成し、このクラスからアセットへのハンドルを提供します。アセットがファイルの場合、R ファイルが提供する参照によって、そのファイルがオープンされてファイルの中身が取得されます。

res ディレクトリー構造内に raw ディレクトリーを作成して、その中に JSON 文書を格納します (図 2 を参照)。

図 2. 新しい単語を格納する raw ディレクトリー
単語を示す raw ディレクトリーの表示

続いて Eclipse がプロジェクトを再ビルドすると、R ファイルには、新規ファイルへの便利な参照が取得されます (図 3 を参照)。

図 3. 更新された R ファイルe
更新された R ファイルの表示

ファイルへのハンドルを取得した後は、ファイルをオープンして読み取り、最終的に単語のリストを生成するためのベースとして機能する JSON 文書を作成することができます。

単語のリストを作成する

未加工の JSON 文書を読み込んで単語のリストを作成する一連のステップは、アプリの起動時に開始されるようにします。このプロセスを処理するために、buildWordList というメソッドを作成します (リスト 2 を参照)。

リスト 2. ファイルの中身を Android 内で読み込む
private List<Word> buildWordList() {
  InputStream resource = 
    getApplicationContext().getResources().openRawResource(R.raw.words);
  List<Word> words = new ArrayList<Word>();
  try {
    StringBuilder sb = new StringBuilder();
    BufferedReader br = new BufferedReader(new InputStreamReader(resource));
    String read = br.readLine();
    while (read != null) {
        sb.append(read);
        read = br.readLine();
    }
    JSONObject document = new JSONObject(sb.toString());
    JSONArray allWords = document.getJSONArray("words");
    for (int i = 0; i < allWords.length(); i++) {
        words.add(Word.manufacture(allWords.getJSONObject(i)));
    }
  } catch (Exception e) {
    Log.e(APP, "Exception in buildWordList: " + e.getLocalizedMessage());
  }
  return words;
}

見てのとおり、buildWordList メソッドの中ではいくつかの処理が行われます。始めに、raw ディレクトリー内の words.json ファイルを最終的に参照する、Android プラットフォームが提供する呼び出しを使用して InputStream を作成する方法に注目してください。パスを表す String はどこにも使用していません。そのため、このコードは広範な端末に移植することができます。次に注目すべき点は、Android プラットフォームに組み込まれた単純な JSON ライブラリーを使用して、(Stringで表現された) ファイルの中身を一連の JSON 文書に変換していることです。Word の静的メソッド manufacture は、単語を表す JSON 文書を 1 つだけ引数に取ります。

リスト 3 に、単語の JSON フォーマットを記載します。

リスト 3. 単語を表す JSON
{
  "spelling":"sagacious",
  "definitions": [
     {
      "part_of_speech":"adjective",
      "definition":"having or showing acute mental discernment
        and keen practical sense; shrewd"
     }
    ]
}

Thingamajig のメイン・ファサードは、WordStudyEngine クラスです。このクラスは Word インスタンスのリストから単語と関数をランダムに生成します。そこで次のステップとなるのが、新しく作成された WordList で単語エンジンを初期化することです (リスト 4 を参照)。

リスト 4. WordStudyEngine を初期化する
List<Word> words = buildWordList();
WordStudyEngine engine = WordStudyEngine.getInstance(words);

単語エンジン・インスタンスを初期化した後は、エンジンに単語を要求して (単語は自動的に、ランダムに選択されます)、返された単語に応じて UI の 3 つの要素を更新することができます。例えば、レイアウトの定義に含まれる単語の部分は、リスト 5 に示すように更新することができます。

リスト 5. UI 要素をプログラムによって更新する
Word aWord = engine.getWord();
TextView wordView = (TextView) findViewById(R.id.word_study_word);
wordView.setText(aWord.getSpelling());

リスト 5findViewById は Android プラットフォームが提供する呼び出しです。この呼び出しが引数に取る整数の ID は、アプリの R クラスから取得することができます。TextView のテキストは、プログラムによって設定することができます。また、フォント・タイプ、フォントの色、あるいはテキスト表示のサイズも、wordView.setTextColor(Color.RED) の形で設定することができます。

リスト 6 では、基本的に上記と同じプロセスに従って、アプリの UI の要素のうち、品詞と定義の部分を更新します。

リスト 6. プログラムによる他の要素の更新
Definition firstDef = aWord.getDefinitions().get(0);
TextView wordPartOfSpeechView = (TextView) findViewById(R.id.word_study_part_of_speech);
wordPartOfSpeechView.setText(firstDef.getPartOfSpeech());

TextView defView = (TextView) findViewById(R.id.word_study_definition);
defView.setText(formatDefinition(aWord));

リスト 5リスト 6 で、名前でレイアウト要素を参照する際に、R ファイルがいかに役立つかに注目してください。Activity クラスの formatDefinition メソッドは、フォーマットを定義する対象のストリングを引数に取り、その先頭文字を大文字にします。このメソッドはさらに、ストリングの文の最後にピリオドがない場合には、文末にピリオドがあるフォーマットにします。(Thingamajig は、フォーマット設定についての処理を一切行わないことに注意してください。Thingamajig は、単なる単語エンジンに過ぎません!)

UI 要素の更新を完了したので、次はアプリを起動して、更新結果を確認します。ご覧ください!学習する正式な単語が表示されるようになっています。

図 4. Overheard Word に単語が表示されています!
「sagacious」という単語が表示されている、更新後の Overheard Word の表示画面

ジェスチャーの追加: スワイプ・ジェスチャーを単語に結び付ける

単語を表示できるようになったところで、今度は単語エンジンのすべての単語をユーザーが簡単にスワイプできるようにしたいと思います。作業を楽にするために、ここでは Gesticulate を使用します。Gesticulate は、私が独自に作成したサード・パーティー・ライブラリーで、スワイプの速度と方向を計算します。また、スワイプ・ロジックを initializeGestures と名付けたメソッドに組み込みます。

スワイプ・ジェスチャーを初期化した後の最初のステップは、1 つの単語を表示するためのロジックを新しいメソッドの中に移すことです。こうすれば、ユーザーがスワイプしたときに、そのメソッドを呼び出すことで新しい単語を表示することができます。リスト 7 に、更新後の onCreate メソッドを記載します (このメソッドは、Android がアプリのインスタンスを作成する際に最初に呼び出されます)。

リスト 7. ジェスチャーの初期化時に単語を表示するようになった onCreate
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  Log.d(APP, "onCreated Invoked");
  setContentView(R.layout.activity_overheard_word);
  
  initializeGestures();
  
  List<Word> words = buildWordList();
  
  if (engine == null) {
    engine = WordStudyEngine.getInstance(words);
  }
  Word firstWord = engine.getWord();
  displayWord(firstWord);
}

engine 変数は、OverheardWord Activity 自体の private static メンバー変数として定義してあることに注意してください。そのようにした理由は、追って説明します。

次に、initGestureDetector メソッドに取り掛かります。複製したコードを見ながら記事を読み進めているのであれば、このメソッドが initializeGestures メソッドの中で参照されているのがわかるはずです。記憶にあるかもしれませんが、initGestureDetector メソッドのロジックは、ユーザーが端末の画面を上下左右のいずれかにスワイプした時点でアクションを実行するというものです。Overheard Word では、ユーザーが右から左へスワイプしたときに (つまり、左スワイプ)、新しい単語を表示するようにします。そのためにはまず、スワイプ・ジェスチャー用コードのプレースホルダーとなっている Toast メッセージを取り除き、その代わりとして displayWord の呼び出しを配置します (リスト 8 を参照)。

リスト 8. 左スワイプ時に単語を表示するようになった initGestureDetector
private GestureDetector initGestureDetector() {
  return new GestureDetector(new SimpleOnGestureListener() {
    public boolean onFling(MotionEvent e1, MotionEvent e2, 
      float velocityX, float velocityY) {
      try {
       final SwipeDetector detector = new SwipeDetector(e1, e2, velocityX, velocityY);
       if (detector.isDownSwipe()) {
         return false;
       } else if (detector.isUpSwipe()) {
         return false;
       } else if (detector.isLeftSwipe()) {
         displayWord(engine.getWord());
       } else if (detector.isRightSwipe()) {
         Toast.makeText(getApplicationContext(), 
           "Right Swipe", Toast.LENGTH_SHORT).show();
       }
      } catch (Exception e) {}
     return false;
    }
  });
}

engine 変数によって表される単語エンジンは、Activity 全体を通してアクセスできなければなりません。そのために、この変数をメンバー変数として定義し、左スワイプが行われるたびに新しい単語が表示されるようにしたわけです。


前および次の単語が表示されるようにスワイプする

アプリを開いてスワイプを開始すると、左にスワイプしたときには、新しい単語と定義が表示されるようになりました。けれども、反対方向にスワイプすると、スワイプしたことを通知する短いメッセージしか表示されません。右スワイプによって前の単語が表示されるようにしたほうが望ましいと思いませんか?

前の単語が表示されるようにするのは、難しいことではないように思えます。その方法としては、スタックを使用して、前の左スワイプによってスタックに入れられた最上位の要素を取り出すことが考えられます。けれども、そのアイデアは、ユーザーが右スワイプによって前の単語を表示した後で左スワイプした場合に破綻します。右スワイプによってスタックから最上位の要素がポップされるとしたら、左スワイプによって表示されるのはユーザーが前に見た単語ではなく、新しい単語になるからです。そのことを十分に考慮し、ユーザーが前の単語を表示するようにスワイプした後、次の単語を表示するようにスワイプしたときに、前に表示していた単語が選択されて表示されるようにするために、リンク・リストの手法を適用したいと思います。

まず、これまでに表示されたすべての単語からなる LinkedList を作成するところから始めます (リスト 9 を参照)。次に、そのリストに含まれる要素のインデックスへのポインターを保持し、ポインターを使って、表示済みの単語を取得できるようにします。当然、これらの要素は static メンバー変数にします。さらに、ポインターを -1 に初期化して、新しい単語を LinkedList インスタンスに追加するたびにポインターをインクリメントします。プログラミング言語では、配列のようなもので構成されるコレクションのほとんどがインデックス 0 から始まるのと同じく、LinkedList のインデックスは 0 から始まります。

リスト 9. 新規メンバー変数
private static LinkedList<Word> wordsViewed;
private static int viewPosition = -1;

リスト 10 では、アプリの onCreate メソッドの中で LinkedList を初期化します。

リスト 10. LinkedList を初期化する
if (wordsViewed == null) {
  wordsViewed = new LinkedList<Word>();
}

最初の単語を表示するときには、その単語を LinkedList インスタンス (wordsViewed) に追加して、ポインター変数 viewPosition をインクリメントする必要があります (リスト 11 を参照)。

リスト 11. ビューの位置のインクリメントを忘れないこと
Word firstWord = engine.getWord();
wordsViewed.add(firstWord);
viewPosition++;
displayWord(firstWord);

スワイプのロジック

これからロジックに取り掛かりますが、スワイプのロジックについてはよく考える必要があります。ユーザーが左にスワイプしたときには次の単語を表示させ、右にスワイプしたときには前の単語を表示させるようにします。その後ユーザーがもう一度右にスワイプした場合には、さらに前の単語を表示させるようにします。この動作は、ユーザーが最初に表示した単語にたどり着くまで続くことになります。ユーザーが最初に表示した単語まで戻ってから再び左スワイプを開始した場合には、一連の単語が前と同じ順序で表示されるようにする必要もあります。WordStudyEngine のデフォルト実装は単語をランダムな順序で返すことから、この最後の部分には注意が必要です。

リスト 12 では、私が実現したいロジックを確実に実装していると思います。listSizeAndPositionEql というメソッドの中にカプセル化された最初のブール値の評価は、wordsViewed.size() == (viewPosition + 1) という単純なものです。

listSizeAndPositionEql が true に評価されると、アプリは displayWord メソッドによって新しい単語を表示します。その一方、listSizeAndPositionEql が false の場合には、ユーザーは前の単語の方へスワイプしたことになるため、viewPosition ポインターを使用してリストから該当する単語を取得します。

リスト 12. 前および次の単語が表示されるようにスクロールするための LinkedList
public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
 try {
  final SwipeDetector detector = new SwipeDetector(e1, e2, velX, velY);
  if (detector.isDownSwipe()) {
   return false;
  } else if (detector.isUpSwipe()) {
   return false;
  } else if (detector.isLeftSwipe()) {
    if (listSizeAndPositionEql()) {
     viewPosition++;
     Word wrd = engine.getWord();
     wordsViewed.add(wrd);
     displayWord(wrd);
    } else if (wordsViewed.size() > (viewPosition + 1)) {
       if (viewPosition == -1) {
        viewPosition++;
       } 
      displayWord(wordsViewed.get(++viewPosition));
    } else {
      return false;
   }
  } else if (detector.isRightSwipe()) {
    if (wordsViewed.size() > 0 && (listSizeAndPositionEql() || (viewPosition >= 0))) {
      displayWord(wordsViewed.get(--viewPosition));
    } else {
      return false;
    }
  }
 } catch (Exception e) {}
 return false;
}

viewPosition-1 であれば、ユーザーが前の単語の方へのスワイプを繰り返して最初の単語まで戻ったことを意味します。この場合、リストへのポインターはインクリメントされて 0 に戻ります。なぜなら、Java ベースの LinkedList 実装には -1 の要素は存在しないためです (他の言語では、位置を示す値が、リストの末尾を表す負の値から始まる場合もあります。その場合、-1 は末尾の要素となります)。

左スワイプでの仕組みを把握すれば、右スワイプのロジックに対処するのは極めて簡単です。基本的に、wordsViewed インスタンスに単語が含まれていれば、デクリメントしたポインターの値を使って、前に表示された単語にアクセスすることになります。

試しに、Overheard Word のインスタンスを起動して、単語の勉強をするために前および次の単語が表示されるようにスワイプしてみてください。スワイプするごとに、UI が適切に更新されるはずです。


まとめ

基本の Android シェルをベースに興味深い機能を追加し始めた今回、Overheard Word はなかなか素敵に仕上がってきています。もちろん他にも必要な作業はありますが、この機能するアプリは現時点で、スワイプ・ジェスチャーに対処し、アイコンとメニューを備え、さらにカスタムのサード・パーティー単語ファイルを読み込むこともできるようになりました。次回は、Overheard Word にさらにスタイル設定を追加してから、賢いクイズ機能を実装します。

参考文献

学ぶために

製品や技術を入手するために

  • Overheard Word: GitHub でホストされている、この連載で作成中の Android デモ・アプリです。
  • Thingamajig: Overheard Word に使用する単純な単語定義エンジンです。
  • Gesticulate: Android のスワイプ・ジェスチャーを検出するための計算を自動的に行います。
  • Android のダウンロード: Android SDK は、Android 向けアプリのビルド、テスト、デバッグに必要な API ライブラリーと開発者ツールを提供します。

議論するために

  • developerWorks コミュニティーに加わってください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者によるブログ、フォーラム、グループ、Wiki を調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology, Mobile development
ArticleID=938057
ArticleTitle=万人のためのモバイル: Overheard Word アプリでの単語とジェスチャー
publish-date=07252013