GAE/Jとつなげてみたり 江川 崇 さいしょに 「Google Android プログラミング入門」 でましたー 648ページ 3,800円(税別) アスキーメディアワークス 「Androidあぷぷ」より抜粋 • 狩猟系と農耕系のどっちって言われたら、これは狩猟系・・・と見せかけて農耕系かも。 ・・・ 実際どうよ? ・・・ • • • ここ数ヶ月でAndroid関連の書籍も充実してきており、他の書籍で扱っているトピックか大体 被ってしまっている状況が続いていますが、この本はページ数が多いこともあり他の書籍で 扱ってないトピックが多いです。特に第4部以降で顕著であり、日本以外でも自作アプリを 使ってもらうためのリソースと国際化、最近のJava開発では必須になりつつあるテスティング フレームワーク、日本語変換など入力値を推測・加工することで入力補助を行うInput Method Framework、最近NDKが出たことで一気に注目されつつあるJNI(Java Native Interface)などは、Webを含めてもきちんとまとまっている情報が少ないので、大変助かりま す。 各トピックの始まり、または言葉では説明しにくい動作を扱う場合など、全体を通してフロー チャートや状態遷移図などが随所にちりばめられており、すごく理解しやすいです。特に Androidの場合、ActivityやIntentの扱いが独特なのですが、これがイメージとしてスッと理解 しやすくなっているのは大きいです。 何気にParcelable(JavaのSerializableのようなもの)の解説があるのも助かります。 • (個人的には)将来青本と呼ばれるぐ らい定番になる気がしています。 将来青本と呼ば れるぐらい定番に なる気がしていま す。 きっかけ • 端末一台でもいろいろできるが、端末間がつ ながった方が面白い – 端末同士が直接やり取りするのはムズい、なんら かのサーバーを介する方法が楽 – Android Hackathonで、GAE(Google App Engine) を使ってたグループがあった 簡単そうだし、ちょっと試してみようか GAEは何が嬉しそう? • とりあえず無料でURLを得られる – http://アプリ名.appspot.com/ – 固定のURLは色んなAPIの口として使える – Waveとの連携とか • デプロイメントが楽 • MTBFが長そうなGoogleインフラ – 有料サービスもしてる • Javaも使える(GAE/J) – 有料でもJavaが使えるホスティングはなかなか無いよね? くらいかなあ・・・? GAEの詳しそうな資料発見! スティルハウス佐藤さん http://tinyurl.com/kaz279 Simpleなチャット なんちゃってlatitude 通信(1) • とうぜんアンドロからHTTPを投げる(簡単) HttpClient client = new DefaultHttpClient(); HttpGet request = new HttpGet(url); // new HttpPost(uri); request.setHeader("User-Agent", userAgent); try { HttpResponse response = client.execute(request); StatusLine status = response.getStatusLine(); if (status.getStatusCode() != HTTP_STATUS_OK) { // えらー } HttpEntity entity = response.getEntity(); InputStream inputStream = entity.getContent(); ・・・ } catch (IOException e) { // えらー } 通信(2) • UIスレッドが止まらないよう別スレッドでHTTP – 戻ってきたらHandlerでUIスレッドに紛れ込ませる final Handler handler = new Handler(); final Runnable uiRunnable = new Runnable() { @Override public void run() { ・・・UI部品の書き換えとか } }; final Thread requestThread = new Thread() { @Override public void run() { ・・・HTTPの要求、応答の処理 handler.post(uiRunnable); } }; ・・・ requestThread.start(); 通信(3) • 応答がJSONなら (簡単) String responseBody = ・・・・InputStreamからStringに変えて・・・・ JSONObject response = new JSONObject(responseBody); JSONObject value1 = response.getJSONObject("key1"); ・・・・ 正直これだけでできちゃうんだけど、、、、 違う方法も試してみよう Protocol Buffers • オブジェクトをマーシャル、アンマーシャルする仕 組 + RPCをするラッパー(Service) http://code.google.com/p/protobuf/ • 通常のシリアライズとどう違う? – サイズが小さくなるらしい – 後から項目を拡張しても大丈夫らしい – 複数の言語で使えるらしい(Java、C++、Python) • 詳しくは、白石さんの記事をご覧下さい http://journal.mycom.co.jp/articles/2008/07/18/protocolbuffer/ Protocol Buffers 独自のデータ項目定義 (protoファイル) message Person { required int32 id = 1; required string name = 2; optional int32 age = 3; } ・・・ protoツールで 生成 Javaのソース Pythonのソース Cppのソース $ protoc --java_out=src --cpp_out=src --python_out=src ./Persons.proto 試す • オブジェクトをSDカードに出力 Person.Builder builder = Person.newBuilder(); Person p = builder.setName("えがわ").setId(1).build(); OutputStream out = new FileOutputStream("/sdcard/hoge.txt"); p.writeTo(out); out.close(); • SDカードから復元 InputStream in = new FileInputStream("/sdcard/hoge.txt"); Person p = Person.parseFrom(in); in.close(); HTTPにのせる • サービスをprotoファイルに記述 ・・・ service MyRpcService { rpc doSomething(Request) returns (Response); } ・・・・ – MyRpcServiceにはdoSomethingというメソッドがある – doSomethingメソッドのパラメータの型はRequestクラス、 戻り値の型はResponseクラス というかんじの定義になる サービス呼び出し部分 • こんなかんじ HttpRpcChannel channel = new HttRpcChannel(uri); RpcController controller = ※ 何か指定する MyRpcService service = MyRpcService.newStub(channel); service.doSomething(controller, request, new RpcCallback<Response>() { public void run(Response response) { ・・・応答を受け取ったときの処理 } }); HttpRpcChannel側 • こんなかんじ public class HttpRpcChannel implements RpcChannel { private final URI uri; public HttpRpcChannel(URI uri) { this.uri = uri; } private ResponseHandler<Response> handler = new ResponseHandler<Response>() { @Override public Response handleResponse(HttpResponse response) throws ClientProtocolException, IOException { HttpEntity entity = response.getEntity(); int length = (int) entity.getContentLength(); byte[] buffer = new byte[length]; entity.getContent().read(buffer, 0, length); return Response.parseFrom(buffer); } }; ・・・・・次のページ HttpRpcChannelの続き ・・・前のページから public void callMethod(MethodDescriptor method, RpcController controller, Message request, Message prototype, RpcCallback<Message> done) { try { ・・・ほんとはメソッド名で分岐 HttpPost post = new HttpPost(uri); HttpClient client = new DefaultHttpClient(); byte[] data = request.toByteArray(); HttpEntity entity = new InputStreamEntity(new ByteArrayInputStream(data), data.length); post.setEntity(entity); Response response = client.execute(post, handler); done.run(response ); } catch (Exception e) { // エラー処理 } } } • こんなかんじ サーバー側は? • サーブレットならこんな感じ(簡単) public class MyServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Request request = Request.parseFrom(req.getInputStream()); いれもの = request.げっとほげほげ ・・・ Builder builder = Response.newBuilder(); builder.せっとほげほげ ・・・ builder.build().writeTo(resp.getOutputStream()); } } GAE/Jを使ってて気づいた点 • 箱庭環境なので色々と制限がある • http://code.google.com/intl/ja/appengine/docs/java/runtim e.html 以下、僕がハマったいくつかの点 (網羅してないので詳しくはWEBや佐藤さんの資 料などをご覧下さい。) • ソケットつなげない – 他のURLに飛ばせない – URL Fetch APIというものを使えば可能らしい GAE/Jを使ってて気づいた点 • スレッド作れない – 他にも、待ちたいのにThread.sleepが怒られた。。 気がするが気のせいかも。。currentThreadだとい けるのかも。少なくともObject#waitを使えば大丈 夫だった。 Object obj = new Object(); synchronized (obj) { try { obj.wait(3000); } catch (InterruptedException e) { } } GAE/Jを使ってて気づいた点 • エンティティにソートをかけるときに色々とあっ た。。けど忘れました。。。 • アプリに状態を持てない – クラスタなので(くわしくはこれを) http://dl.google.com/io/2009/pres/W_1115_From_ Spark_Plug_To_Drive_Train_Life_of_an_App_Engi ne_Request.pdf GAE/Jを使ってて気づいた点 • JNDI – javax/naming/NamingException – このせいでSpring MVCはアノテーション周りがうまく 動かなかった。。らしい。 • システムコール使えない • 各種サイズの制限あり – – – – – リクエストのサイズ アプリのファイル数 ファイルサイズ Datastoreのエンティティのサイズ メール送信サイズ などいろいろ GAE/Jを使ってて気づいた点 • レスポンス返すまでの制限時間は30秒。 – つまり、張りっぱなしは無理 – レスポンスを返さないと DeadlineExceededExceptionがでる ・・・・・・が、まだ最後のチャンスが一瞬(1秒以内) 残されているので、その間に直ちに返すとOK。 try { ・・・ レスポンスを返さずにだらだらする ・・・ } catch(DeadlineExceededException e) { 急いでレスポンスを返す!!! } GAEじゃないとダメ? • 勿論、自分でサーバー書いてもいい ServerSocket serverSocket = new ServerSocket(9001); while (true) { Socket socket = serverSocket.accept(); DataInputStream in = new DataInputStream(socket.getInputStream()); DataOutputStream out = new DataOutputStream(socket.getOutputStream()); int length = in.readInt(); byte[] buffer = new byte[length]; in.read(buffer, 0, length); Request request = Request.parseFrom(buffer); ・・・処理 Response response = Response.newBuilder().setほげほげ.build(); byte[] data = response.toByteArray(); out.writeInt(data.length); response.writeTo(out); in.close(); out.close(); } GAEじゃないとダメ? • プロセス間通信をするプロダクトを使うのも可 ex) JADEなどのマルチエージェント環境 – JADE(Java Agent Development Framework) • LGPLのマルチエージェントのJava実装 • FIPA(http://fipa.org)で定めているマルチエージェント の仕様を実装したもの • Android用アドオン(JADE leap for Android)あり PIAX for Android!? 忘れていたこと • あ!電波は切れるんだった!!! – ConnectivityManagerを使うといい • ネットワークの状態が変わると、アクションに ConnectivityManager.CONNECTIVITY_ACTIONが設定され たインテントが飛んでくる • このアクションに反応するBroadcastReceiverを定義する • onReceiveでネットワークの状態変化に対応する処理を 記述 – 切れてる時は無駄に電池食わないようにお行儀よく – 繋がったらそのことを検知してがんばる 所感 • Android – Androidでの通信は簡単かつ楽だなあ • シングルスレッドってところだけ気をつける – でも電波は切れるんだったなあ • ConnectivityManagerで • Protocol Buffers – JSONよりも少し面倒だなあ。 – けどメソッド名の間違いが防げる点は嬉しいかなあ。RPC部分 が付いているのが嬉しいなあ。 – Protocol BuffersのメッセージをJDOのエンティティに詰め替えず に永続化したいなあ アノテーションを付ければできそうだけど • @PersistenceCapable(identityType = IdentityType.APPLICATION) • @Persistentとか 所感 • GAE – 色々制限あるなあ、Java版は特に厳しい? – 特にレスポンスの待ち時間を長くしてほしいなあ • プッシュが欲しいのです。。ないのでしょうかプッシュ。 – でも、AndroidからHTTPで動く何かを使うのならお 手軽かなあ • ADC2にサーバーのプログラムを一緒に出しても審査 員が使い方をわからなかったら。。。という不安を防げ る。 • インフラ落ちにくいんじゃね?
© Copyright 2024 ExpyDoc