« 2011年1月 | トップページ | 2011年3月 »

2011年2月

2011年2月28日 (月)

春はあけぼの

いや、春はブランデー

そろそろ酒が切れたので買出しに行きました。私の場合、季節によって飲む酒が変わるのですが、春はこれ、という決まりはありません。ちなみに、夏は泡盛&ラム、秋はシェリー&スコッチ、冬はアイラ&ジンが基本となっています。つまりは、季節に合わせて産地が南から北へ移動しているわけです。

とはいうものの、春はコニャックになることが最近は多いです。ちょっと値の張るマールとか。なんですが、残念なことにお目当てのコニャックは無かったので、久しぶりにレミー・マルタンを買ってきました。何年ぶりでしょうか。バブルのころ、スナックやらなにやらで高級な酒というと出てきた記憶があります。そのころから飲んでいませんね。多少粗さはあるものの、香りはやっぱりいいです。花咲く春に香り豊かなブランデー、いかがですか?

バックグラウンドでの実行

今日はとても寒かったです。

寒い日は早く寝るに限ります。じゃぁ、これで。というわけにも行かないので小ネタを出します。

サーバとの通信とか、それに伴うファイルアクセスとかをやるとそれなりに待ちが発生します。UIを担当しているスレッドでこれをやると、UIが止まります。つまり、通信中はスクロールさせたりもできなくなるわけです。

これは、使いにくい、というか、使用者を不安にさせるのでやぱり、そういったことはバックグラウンドで処理することが求められます。そこで登場するのがAsyncTaskです。

Developerサイトにも例があるのですが、それを見ながら私も作ってみました。お題としては、ディレクトリをスキャンして、その中のファイルをXMLparserに掛けて、titleを取り出す。ということにしたかったのですが、長くなるので後半ははしょりました。

ディレクトリをバックグラウンドでスキャンして、ListViewに突っ込むプログラムです。File.listFilesをやって、そのリストの項目ごとにArrayAdapter.add()を呼んでいます。だた入れたのではつまらないのでpublishProgressを経由して一件づつ処理しています。その後に入っている500msのsleepは動作がよく分かるように入れたダミーのウェイトです。ぽこ、ぽこ、という感じでリストされますが、その間も普通にスクロールしたりできます。
あと、onProgressUpdateの中で呼び出しているnotifyDatasetChangedですが、とりあえず、ここでやる分にはおこられませんでした。が、doInBackgroundで呼び出すと別スレッドからViewにさわるんじゃねぇ、といって怒られるかもしれません。たぶん、そのためのハンドラでしょうから。

public class asyncTaskSample extends ListActivity{

    static final String TAG = "AsyncTaskSample";
    static final String SDCard = "/sdcard";

    private Context mContext ;

    private String[] mList = new String[] {""};
    private ArrayAdapter mAdapter ;
   
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
        setContentView(R.layout.asyncsample);
   
       mContext = getApplicationContext();
       mInflater =LayoutInflater.from(mContext);
      
       mAdapter = new ArrayAdapter<String>(mContext, android.R.layout.simple_list_item_1);

        setListAdapter(mAdapter);
    }

    private class DirScan extends AsyncTask<String, String, Void>{
            @Override
            protected Void doInBackground(String... dir) {
                  File sdir = new File(dir[0]);
                  File[] filelist = sdir.listFiles();
                  for (File file : filelist){
                        publishProgress(file.getName());
                        SystemClock.sleep(500);
                  }
                  return null;
            }
            protected void onProgressUpdate(String... foundDir){
                  mAdapter.add(foundDir[0]);
                  mAdapter.notifyDataSetChanged();
            }
            protected void onPostExecute(Void nil){
                  Toast.makeText(mContext, "onPostExecute", Toast.LENGTH_SHORT);
            }
    }
    public void refresh(View v){
      new DirScan().execute(SDCard);
    }
}

2011年2月26日 (土)

開発真っ盛り

ひたすら開発しています。

なので、あまりネタがありません。とりあえず、xmlpullparser使ってEvernoteのノートデータを作ったり読んだりしています。

そっちは大体形になったので、Todo一覧をクラスに突っ込んで、ArrayAdapterでListViewに表示するというお決まりのパターンになってきました。最近はAdapter作るのにも慣れました。

あとはUIですね。EvernoteはGUIDというものでノートを管理していて、サーバからノートを持ってくるにはGUIDが必要です。GUIDはノート作る時にサーバが指定するのですが、作った時に不揮発メモリに保存しておくか、ノート一覧をもらってその中から選ぶしか目的のノートのGUIDを知る方法はありません。でもねぇ、ノートを毎回サーバから持ってくるのは不便なのでノートのデータはSDカードに保存しています。

ここが問題なんですよね。SDカードのデータはいつもあるとは限らない(キャッシュなので、SDカード取替えたりしても動くようにしたい)のでGUIDが分かっていて、キャッシュは無いとか、そもそもノートが存在していない、とか状態によってサーバにログインしたりしなかったり。

さらには、ノートブックにノートを収納するわけですが、このノートブックもGUIDで管理されていて、これも、同様に作った時にGUIDを保管するか一覧から選ぶ必要があります。Spinnerなんかも作ってみたりしたのですが、Spinnerのリストを作るにはサーバにつながなければいけないので、使うかどうかは未定です。接続が安定していればたいした問題ではないんですが、そうでない場合も想定しなければいけないですからね。

極力オフラインでも使えるようにしたいのでログインするのはできるだけ避けたいのですが、条件分けにてこずっていたりします。ログインすると、どうしてもエラー処理が増えるし。

まぁ、そんなこんなで後はロジックとエラー処理が残りました。アートワークもぜんぜんやってないし、あと一月くらいは掛かりそうです。

そういえば、開発用にと買った中華Padですが、かなり調子いいです。エミュレータと違って立ち上がるのを待たなくていいし、動作も速いです。そして、7インチタブレットだとディスプレイの脇に立てかけておけば見やすいし、ボタンを押すのもXperiaに比べて楽です。Eclipseの画面を広く使えるのも効率向上に役立っています。これで2万しないならよい買い物でしょう。

2011年2月22日 (火)

中華Padの謎

昨日の記事の訂正です

なぜか、今日になったら、普通にマーケットからのインストールも、adbのインストールもできるようになりました。

原因はまったく不明です。

2.1なのでFlushは見ることができないのですが、それを気にしないなら非常によくできている。というのが現状の感想です。一部の人にはflushが大切かもしれないですが、私はまったく気にしません。

まぁ、Launcherを含む一部アプリが横画面でしか動かないとか、細かな不満はあるのですが、開発機としては十二分な性能と精度だと思ってます。格安ですし、電話と違って気楽に初期化できるし、SDカードを簡単に取り外すことができるのもメリットの一つです。(テストがしやすいので)

2011年2月21日 (月)

中華Padがやってきた

突然ですが、今日、自宅へ帰ったら不在連絡票がポストに入っていました。

どうやらaPadが来たようです。日本では郵政が提携しているようです。

で、再度配達をお願いしたら、すぐに持ってきてくれました。

思ったより小さく、画面はXperiaより2周り程度大きいくらいです。前面はシンプルな黒。側面はアルミっぽいシルバー。後ろはメタリックな黒で安っぽい感じはありません。でも、後ろはプラスチックなので持ち歩けばすぐに傷がつくでしょう。

OSを立ち上げると、画面はなかなかメリハリのある色です。が、表示が読めません。ええと、字は見えるのですが、読めません。つまり、日本語はおろか英語でもなく、どうやらスペイン語らしいのです。(疑問文に?がさかさまになった記号がついてるからスペイン語?という程度の知識です)
スペイン語を覚えるのも楽しそうなのですが、なんとか日本語に切り替えて次へ進みます。視野角はあまり広くないですが、色はきれいです。そして、動きもまぁきびきびしていてこれで1万6千円程度なら十分お買い得でしょう。タッチパネルの精度は悪くないです。

さて、さっそくUSBをつないで、...デバイスのインストールに失敗しました。デバイスマネージャから再インストールしたらこんどはAndroid Phoneを認識しました。adbからも見えているようなので、早速適当なアプリをインストールして、...起動しません。
もう一度ややってみます。すでにアプリはインストール済みと出るのですが、やはり起動しません。設定からアプリケーションの管理を見ると確かに入っています。

試しに、最初からインストールされているExplorerというアプリを使ってファイルを選んでインテントを発行すると、ちゃんと指定されたアプリが動きます。

つまり、ホーム画面が、自分が知っているアプリしか表示せず、実行もしないようにできているようです。うーん、これでは開発環境としては使えません。まず、このカスタマイズされた(見かけはまったく同じですが)ホーム画面を制約のないものと取り替える必要があるようです。
ちなみに、マーケットのアプリもついているのですが、ダウンロードは終わりません。なんのためにこれついてるの?という感じです。

adbからならインストールはできるし、インテント経由でなら起動もできるので、なんとか代替のホーム画面を送り込んで設定を変える方法を考えないといけないでしょう。が、今それをやっている時間はありません。当面、メディアプレーヤーですね。SDカードは本体の外にスロットがあるので、電話機のようにバッテリを外さなくても取り替えられるのが救いです。

2011年2月20日 (日)

手抜きなFileViewer

さっきネタがないと書いておきながら、まだ出してないネタがあったのを思い出しました。

Evernoteのアプリを作るにあたって、何でもかんでもEvernoteに処理させると時間がかかるので、代わりのアプリを作ってみました。お手軽なファイルビューワです。もっと高機能なものもあるのしょうが、いちいち開発環境に持っていくのは面倒なので。

中を見ていただければ分かるのですが、ファイルを読んで、TextViewに貼るだけのプログラムです。とりあえず、Javaネイティブなコードは書いたことがないのでこうやって入出力するのがお作法にあっているのか知らないのですが、ファイルから行単位に読んで、Stringにつなげていって、最後にTextViewに貼るのはあまりに冗長に感じたので読み込んだバッファからTextViewに突っ込みました。ただ、あまったバッファのデータを捨てないと改行が後ろについてしまうので、ファイルの長さでバッファをコピーしています。

なお、最初の8096バイト以降は読んでいません。どうせあんな小さい画面で何Kバイトもあるファイル読む気しないし。

おまけとして、最初の行に自分が呼ばれたIntentのactionを表示するようにしてあります。Intentを発行した側がACTION_EDITを出したのか、ACTION_VIEWで呼んだのか分かります。

当然ですが、他のアプリからIntentで呼ぶためのものなので、このアプリをランチャから呼んでもなにも起きません。ManufestのActivityにIntentFilterを指定してご利用ください。

public class fileView extends Activity {
      private final String TAG = "fileView" ;
      private FileInputStream fs ;
      
      /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView ah = (TextView) findViewById(R.id.action_header);
        TextView vw = (TextView) findViewById(R.id.textView1);
        Intent intent = getIntent();
        ah.setText(intent.getAction());   // set action in intent to view
      
        Uri fUri = intent.getData();
       if (fUri == null) return;         // no Uri. so, exit with do nothing
        String fname = fUri.getPath();
        File f = new File(fname);         // get filename from data in intent
      
       // setup buffer and view
       byte[] input = null ;
       int d = 0;
        String t = null;
            try {
                  fs = new FileInputStream(f);
                  BufferedInputStream bf = new BufferedInputStream(fs);
                  input = new byte[8096];
                  
            d = bf.read(input,0,8096);    // fill stream buffer (read first block only)
                  Log.d(TAG,"read returns "+String.valueOf(d));
                  byte[] tb = new byte[d];
                  for (int i=0;i<d ;i++) tb[i] = input[i] ;
                  t = new String(tb,"UTF-8");
              vw.setText(t);
            } catch (FileNotFoundException e) {
                  Log.e(TAG,"FileNotFound");
                  vw.setText("File Not Found");
//                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                  vw.setText("Unsupported Encoding");
//                e.printStackTrace();
            } catch (IOException e) {
                  Log.e(TAG,"IOException");
                  vw.setText("IO Error");
//                e.printStackTrace();
            }
    }
}

アプリ第2弾開発中

結局、センサーはあきらめました。

何がしたかったかというと、カメラで写真を撮る際の水準器の代わりに、本体(のx軸)が水平または垂直になったらLEDがチカっと点くと便利なんじゃない?という発想だったわけですが、NotificateManager経由で通知すると即座に点滅というのはできないようです。

/dev/ledとか直接触れば即時点滅できるのかもしれませんが、今動いてもこの先どうなるか分からないし、シャープの機械にはLEDAPIもあるようですが、機種依存のものは作りたくないし、何より機械がありません。

なので、これは放置して次のタマの仕込みに入りました。簡単にいうと、TodoをEvernoteに保存することができるアプリです。

そんなこんなでEDAMやらで遊んでいた、というより、EDAMを組み込んだプロジェクトを作るためにEclipseと格闘していたらなんとなく週末になってしまいました。

ここのところ、体調が悪く、医者へ行ったり検査へ行ったりしていたこともあってほとんどすすんでませんが。

現状、Todoのクラスと骨組みとPreferenceぐらいしかありません。よって、小ネタさえありません。

あと、シンセンからこちらに向かっているはずの中華Padですが、16日にようやく追跡できる状態になったのですが、17日に広州の税関を出たところで消息を絶ちました。単純に日本の税関が月曜日にならないと通関できないだけのような気もしますが、東シナ海に沈んだという可能性も捨て切れません。保険はかけてないので、沈んだらさようならですね。

まぁ、来週(もう今週)のうちには分かるでしょう。

2011年2月15日 (火)

android:onClick

EvernoteのAPIキーが送られてきました

どうやら、日本で受け付けて、米国に回送して届けられるようです。中1日でやってきたのでアメリカとの時差を考えれば即日発行されたと思っていいでしょう。

早速、ログインだけでも試すかと思って、sandboxへidを作って、サンプルをコピーしたのですが、そのHelloAndroidというサンプルは意図したものとはちょっと違っていました。
HelloAndroidはIntentを発行してEvernoteクライアントに処理してもらうサンプルで、APIキーは使いません。でも、せっかく開いたのだから、中を見てみました。それが、そのプログラム、動かすとボタンが何個かあって、それを押すとEvernoteクライアントが動くのですが、中身が何か変なのです。つまり、onCreateのほかは各種Intentを発行するメソッドの処理が延々書いてあるだけで、Buttonを実体化させたり、リスナーを登録したりといった処理がまったく無いのです。

ここで、タイトルのものが登場します。つまり、layoutのxmlのButtonの属性としてandroid:onClickというのが指定されていて、そこにクリック時のメソッド名が書いてあるのです。
えー、そんなの聞いてないよ、と思ったのですが、これ以外のタネや仕掛けは見つけられなかったので、私もやってみました。

こんな感じです、これは、前回ちょっと書いたアプリの一覧のほか、センサーの一覧を表示するプログラムを1つのパッケージにまとめたものです。pbとsbのボタンがありますが、sbのほうはSetOnClickListenerがコメントになっています。その代わり、onClickと同等の処理をsensorとして作っています。そして、sbのlayoutを定義したxmlにandroid:onClick=sensorと書けば、ボタンを作ったりしなくても動くということです。Xperiaで試しましたが、ちゃんと動きました。

public class main extends Activity {
      private Button pb ;
      private Button sb ;
      private Context mContext ;
      
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mContext = getApplicationContext();
      
        pb = (Button) findViewById(R.id.perm_button);
        pb.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
                Intent intent = new Intent(mContext,permissionlist.class);
                startActivity(intent);
            }
        });
//      sb = (Button) findViewById(R.id.sensor_button);
//      sb.setOnClickListener(new OnClickListener(){
//        public void onClick(View v) {
//            Intent intent = new Intent(mContext,sensors.class);
//            startActivity(intent);
//        }
//      });
    }
    public void sensor(View v) {
          Intent intent = new Intent(mContext,sensors.class);
          startActivity(intent);
    }
}

2011年2月14日 (月)

順調なすべりだし?

昨日マーケットに出した電卓ですが、なんと、1日で20件以上もダウンロードされました。

正直な話、このblogのアクセス数より多いです。日本にしか出していない割には、iPhoneのストアに比べるとさびしいなどといわれている割にはアクセスあるものだなぁと関心しています。

作ったばっかり&それなりに先行が居るにしてはがんばっていると思います。とりあえず、広告もなんもないので一文にもなりませんけどね。

まぁ、今はダウンロード数の実績を作る期間なのでこれで良しとしましょう。

aPadがシンセンをでたらしい

以前発注した中華padですが、ようやく春節休みが終わり出荷されたようです。

ところが、EMS(中国の郵政省?)のサイトでidを追跡してもそんな荷物は無いといわれます。
東シナ海の藻屑と消えたかもしれません。

とりあえず、無事到着してくれることを祈るばかりです。
国内ではどこが持ってくるのか不明ですが。

個人で輸入したものにも消費税かかるんだよね。手続きを簡単に済ませることができる業者であることを祈るばかりです。

センサーの件は、実はリアルタイムにLEDを点けたいのですが、うまくいかずに悩んでいます。Developersサイトのサンプルにヒントがあったので、明日試してみる予定です。

センサーが没になったときのためにEvernoteのAPIの申請を出しました。まぁ、どちらにしろ、そのうちやるつもりですが。

2011年2月13日 (日)

パッケージの一覧

次はセンサーと言っておきながら、記事はセンサーではありません。

センサーは動いたのですが、結果を通知させるところで詰まっています。

なので、別のとこでお茶でも濁しておきましょう。お題はインストールされているパッケージ一覧の取得です。

PackageManagerなるものを呼び出すと、PackageInfoのリストとして結果が返ってきます。このとき、パラメタとしてflagを渡すと、パッケージの条件を指定することができます。

とりあえず、最近こればっかりやってる気がするArrayAdapterで表示するようにしたのが以下です。ここでは、PackageInfoのなかのpackageNameを取り出してListViewに入れています。次のアプリで特定のintentを持つ別アプリをintent発行前に一覧表示させたいなぁ、と思ったのでその準備として作ってみました。

public class applicationlist extends ListActivity {
      static final String TAG = "PkInfo";

      private Context mContext;
      private PackageManager pm ;
      private List<ApplicationInfo> mApList ;
      private List<PackageInfo> mPkList ;
      
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

       mContext = getApplicationContext();
       pm = getPackageManager();
       int flag = 0;
       mPkList = pm.getInstalledPackages(flag);
      
        setListAdapter(new ArrayAdapter<PackageInfo>(this,R.layout.list_item, mPkList){
           public View getView(final int pos,View cv,final ViewGroup parent) {
                  if (cv == null) {
                        cv = new TextView(mContext);
                  }
                  ((TextView) cv).setText(mPkList.get(pos).packageName);
                  return cv;
            }          
        });
    }
}

パブリッシャーになった日

公開してしまいました。

Developersサイトには公開の手順についてあれこれ書いてありますが、Eclipseを使って手続きする限り、ほとんどの部分は必要ないです。理解している必要はありますが。

つまるところ、鍵を作って、エクスポートすれば署名されたapkが出来上がります。

鍵は35年有効にしました。35年後はたぶん生きてはいないでしょう。仮に生きていたとしても、プログラムを作ってはいないでしょう。そういう意味では一生ものです。2048bitのRSAが35年後も健在かはわかりませんけどね。

で、Googleに25ドルのお布施をはらってパブリッシャーになりました。

でも、規約の中にAndroidMarket以外では宣伝しないとか、気になる文言があったように思います。これって、独占契約ってこと?あちこちでマーケットが立ち上がりつつあるので、そういうことを言いたい気持ちは分からんでもないですが、そんなのオープンでもなんでもないじゃんかよ、Googleさん。

でも、考えてみれば、ライセンスライブラリとか、マーケットごとにリンクしなければいけないわけで、あまりたくさんのマーケットに首を突っ込むのも大変そうです。

骨折り損のくたびれ儲け

最近、作業用のPCをシャットダウンしようとしても待機中になってなかなかシャットダウンできないことが多くりました。

Eclipse、Evernote、ChromeやIE8複数枚、最近はお絵かきのためのPaintShopなども開いていることがあるので、止めるのが大変なのは分かるのですが、起動時にchkdskがかかることもままあり、ちょっとまずいかな?という状態になってきました。

アプリつくりがひと段落したので、思い切ってVirtualBoxを動かしていたマシンにWindows7のディスクだけつなぎ変えて、9350e+6GBmemoryで動かすことにしました。最近はFedoraに現役を譲って半隠居状態だったので。

作業用のPCには460GTXが載っていることもあって、電源は今のものを維持する必要があり、Diskを差し替えれば済むとは行かないところが作業をややこしくしています。

2台のPCのフタを空け、マザーボードを取替え、GPUを挿して、Diskをつないでできあがり。
というと簡単そうですが、最近は暗いところで基盤のシルクなどの小さい時を見るのはつらいです。ぶつぶついいながら、ようやく完了。

しかし、SafeModeにしてもdiskのドライバを読むところでフリーズします。まぁ、しょうがないですね、MBのチップセットが別ものなので。じゃぁ、修復セットアップ、と思いインストールDVDから起動するのですが、DVDを読み終わったところで、インストールの選択が現れずにDiskのOSをブートしようとします。(そして、当然固まります)

うーむ、プロダクトキー転用のプロテクトなのでしょうか。しかし、OSをブートしないようにしようにももう一台もばらしてあるのですぐには動かせません。

結局、構成を元に戻すことにしました。戻す途中でメモリスロットが1本いかれたらしく、起動時にブザーがピーピー鳴ります。あいにく、Win7のPCはスロットが2本しかないので、1本使えないと1GBに減ってしまいます。さすがに1GBはつらいので、6GBのうちの2GBのDIMMを一本転用して2GBに変更します。今日はロクなことが無い日です。

2011年2月11日 (金)

ListViewの下のView

雪が降りました。まぁ、なごり雪でしょう。とりあえず今は止んでいるようなので、明日はそれほど大きな混乱はなさそうです。

雪で動けなくなる前に床屋を済ませ、食料の買出しをしましたが。

さて、ListViewの話です。件の計算機に行を追加する機能を増やしたのですが、ボタンを押してどんどん行を増やしていくと、想定していなかった動作をしました。
どのようなレイアウトになっているかというと、上に全体の情報を表示する部分があり、中間にListViewを置いて、下にボタン群があります。このボタンを押すとどうなるかというと、ボタンがはみ出すまでListViewが延びて行き、そこでボタンを押せなくなります。

ListViewにスクロールバーが付くと思っていた私が甘かったです。でも、どうやらこれで正しい仕様のようです。

つまり、androidは上にあるものから順にViewを実体化していき、画面からはみ出したところでViewを作るのをやめてしまうらしいのです。表示される可能性がないものは作らないということです。だから、layout_heightがwrap_contentなListViewが画面サイズを超えると、その下にあるViewは作りません。このとき、ListViewはまだ画面から出ていないのでスクロールバーは付きません。

とりあえず、簡単な解としては、ListViewのlayout_heightをサイズ指定するというのがあります。確かにこうすれば全体が表示できるのですが、画面サイズが違う端末で表示すると、あまりうれしくない結果を招きます。

もっといい方法は、というと、ListViewより下にあるViewをListViewのfooterにする、というのがよさげです。こうすれば、ListViewの項目として画面を作ってくれそうです。

こんなこともあろうかと、最近覚えたinstanceofという小技を使ってWarikanAdapterは複数のWarikanクラスを格納できるよう作り変えておいたので、あとはListViewの外の項目をHeaderとFooterに入れればいいはずです。これはまた明日やることにしたいと思います。

アイコンもできたし、もうすぐ完成です。

2011年2月10日 (木)

割り勘計算機(5)

相変わらずやってます。

Dialogの表示がおかしい件は解決しました。

なんと、InflateしたViewをsetContentViewしていたのが原因でした。

Dialogのコンストラクタ内で外側のViewは組み立てられるらしいのですが、これを壊していました。addContentViewに変えたらちゃんと外枠もでました。

今はレイアウトなおしたり、ちまちま修正しています。エミュレータで見ると結構でかいのでsmallの字体でも気にならなかったのですが、Xperia実機だとsmallはかなり小さいのでmediumに変更しようかと考えているところです。でも、そうすると、また全体の配置を作り直さなければならず、...

今のところ、結果を保存する機能はないのですが、とりあえず世に問うて、実がありそうなら機能追加しようかなぁという感覚です。実際にはテーブルをひとつ作って、onStopでsqliteに掃き出して、onCreate時に読めばいいだけなんですけどね。

まぁ、DBhelperがやってみたくなったら試しにつくりましょう。

ということで、次はなににしようか詮索中です。詮索?やっぱりセンサーですかね。
xml解析とかも使えるようにならなければとは思うのですが、いいネタが思い浮かびません。
センサーネタとしては、傾けると水がこぼれるけど濡れない、豆腐屋のコップとか、まぁjokeネタもあるんですが、もうちょっと役に立つもので行って見たいと思っています。が、かなりアイデア商品なので、公開前に内容を紹介できるかは分かりません。

2011年2月 7日 (月)

ListViewの中のボタンからActivityにイベントを通知する

Developersサイトでメソッドを見つけたので検証してみました。

ListViewの中にボタンがあると、ListViewのOnItemClickはクリックイベントを拾えなくなります。その代わり、ボタンのクリックでイベントが通知されるのですが、ボタンはListViewの行の数だけできるのでそれを受け取るにはリスナーを経由する必要があります。

すでにOnItemClickListenerがあるわけで、それに渡せばいいんじゃない?というか、OnIemClickListenerのidパラメタてなんに使うの?という疑問の答えがこれです。プログラムそのものはチュートリアルのListViewサンプルの改造です。

public class main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        ListView lv ;
        final LayoutInflater minf = LayoutInflater.from(this);
        ViewGroup rootvg = (ViewGroup)minf.inflate(R.layout.main, null);
        lv = (ListView) rootvg.findViewById(android.R.id.list);
        lv.setAdapter(new ArrayAdapter(this,R.layout.list_item, COUNTRIES){
                  public View getView(final int pos,View cv,final ViewGroup parent){
                  cv = minf.inflate(R.layout.button_list, null);
                  TextView co = (TextView)cv.findViewById(R.id.TextView01);
                  co.setText(COUNTRIES[pos]);
                  Button bo = (Button)cv.findViewById(R.id.Button01);
                  bo.setOnClickListener(new OnClickListener(){
                        public void onClick(View v){
                              ((ListView) parent).performItemClick(v, pos, (long)0);
                        }
                  });
                  return cv;
            }
        });
        setContentView(rootvg);
        lv.setTextFilterEnabled(true);
        lv.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent,View view, int position, long id) {
                  Toast.makeText(getApplicationContext(),((TextView)view).getText(), Toast.LENGTH_LONG)
                  .show();
            }
        });
    }

かなり入れ子になっているので見づらくて申し訳ないです。つまり、ArrayAdapterのgetViewの中でTextViewとButtonが並んだ行をinflateして、ボタンにonClickListenerをつけます。そして、その中でperfomItemClickすればActivityでセットしたOnItemClickListenerが呼ばれます。

分かってみればそれだけのことですが。 もちろん、ボタンが複数あってもidをきちんと設定して判定すればどのボタンが押されたか分かります。

2011年2月 6日 (日)

ThemeとStyle

前のエントリで書きましたがテーマとスタイルについて

とりあえず、Developers サイトにある情報がほとんどすべてなのですが、重要なのはページの最後のほうにあるThemeとStyleのリンクです。

つまり、Themeというスタイルリソースが全体の構成を定義していて、文字やリンクの色といった項目の属性にについて決定しています。各種スタイルはstyle.xmlのほうに書かれていて、たとえば通常の文字が使用するスタイルはTextAppearanceという名前です。

どうやって使うかというと、たとえば自分のレイアウトのTextViewにstyle=@android:style/TextAppearanceと書いておきます。そして、Themeを継承したMyThemeを自分のテーマとして作成し、その中の文字の色、textColorPrimaryを自分の好きな色に置き換えれば、いちいちレイアウトのxmlを編集しなくても全部のTextViewの色を設定しなおすことができます。

でも、使ってみると色々疑問が沸いてきます。

なぜか、ListViewの中のTextViewにはスタイルが適用されない。もちろん、個別にレイアウトに書いてInflateしたのは効くのですが、TextAppearanceと指定してもテーマの指定が反映されません。

反転表示(明るいバックに暗い文字)というスタイルがない。アプリケーション名のヘッダなどに使われているのでどこかにあるはずだと思うのですが、見つかっていません。style.htmlにある*Inverseというスタイルを使うと、黒バックに黒文字になってしまい、まったく読めません。

まぁ、平日はあまり時間の掛かることはできないので、今度の週末までに小さなテストプログラムを書きながら調べてみたいと思います。

2011年2月 5日 (土)

From the barrel

なんか、”酒とLinux”なんてサブタイトルをつけながら、酒の話題もLinuxの話題もないので少し酒の話を

去年の暮れ以来ザ・マッカランがナイトキャップだったわけですが、それも無くなったので、買出しに行きました。

実は、年末にビール券が眠っているのを発見したのでその勢いで普段は買わないような酒を、と思って臨んだ買出しのターゲットは、実はRoyal Saluteだったわけですが、残念ながらちょっと手が届かなかったのでChivasの17年になりました。その差額で、というわけでもないのですが、もうひとつ買ってきたのがタイトルのニッカ・フロム・ザ・バレルです。樽出し、ということで50度以上あるらしいのですが、アルコールがツンとくる感じはなく、キックもそれほど強くないです。グレーンの風味がちょっとアクセントになっていて、嫌味のない味付け、これで1680円ならお買い得!と思ったのですが、容量が500mlでした。720換算だと2500円近いわけで、まぁお値段相当ですね。違う見方をすれば、世界レベルでも遜色ないということでもありますが。

そんなこんなで、500mlの壜はすでに空になりました。

割り勘計算機(4)

あれからもう少し紆余曲折あったのですが、一応ロジックとしては完成しました。

問題は、やっぱり、一番大きいのはDialogのサイズが設定されないことでしょうか。

androidのThemeとして、Theme.Dialogなるものもあるそうなので、Dialogのコンストラクタの第2パラメタに自分で作ったTheme(androidをparentに指定)のidを書いたり、android.R.style.Theme_Dialogを書いたりして見たのですが、やっぱりサイズは設定されません。

Manufestのアプリのstyleにこのテーマを指定するとアプリの画面がダイアログのようになるので、このテーマにサイズが入っていることは間違いないと思うのですが。

StyleとかThemeとかは一度作れば後は流用できるので、あせらずじっくりやりたいと思います。

とりあえず、明日またがんばりましょう。

3.0 preview

みなさん、もう3.0 previewはお試しでしょうか。

私もやってみました。どうも今朝はプログラム作る気合が入らなかったので。

まだ、起動中なんですが(ええ、起動中に文章が書けるくらい時間かかります)、とりえずエミュレータのWXGA画面はQWVGA(1920x1200)で見てもでかいです。

で、SDKのサイトにもかれていますが、遅いらしいです。まぁ、この起動時間みても容易に想像できます。

どうも、実機がないと開発をするというのは現実的ではない気がします。でも、まだ実機はありません。

起動してそろそろ10分経つように思うのですが、いまだにアンドロイドのロゴがテカテカしています。とりあえず、思い悩んでも仕方ないので別件を片付けることにします。

2011年2月 4日 (金)

Custom Dialog(2)

なんとか週末前に動くようになりました。

結局、何が悪かったかというと、ほとんど勘違いですが、

  1. DialogにもonCreateはある。
  2. AlertDialog.Builderというのは、クラスの外からダイアログを組み立てるツールである。

ということです。

最初、onCreateというのはActivityのメソッドでActivityを継承していない(DialogはObjectの子)クラスには無いのかと思っていたのですが、単なる勘違いで、Dialogの初期化はonCreateでやるのだそうです。まず、そこを直しました。

でも、ダイアログでないのはやっぱり直らず、どうしたものかと思っていたのですが、どうやら、2.が根本的な勘違いだったようです。つまり、Builderはクラスは作り直さずにダイアログの構造(ボタンを増やすとか)を変えるためのもので、今回のようにEditTextが欲しいといった、想定外のことはできないのです。それなのにBuilder使って、できたダイアログは返していませんでした。
Builderはやめて、全部layoutからinflateすることにしました。そのため、AlertDialogを継承する必要な無くなったので、それもDialogへ変更し、EditTextにOnKeyListenerをつけてENTERを無効にしたり、ボタンにonClickリスナを登録して、データを渡すために作った自前のリスナを呼び出す処理を追加したりして、なんとか機能するようになりました。

全体をTableLayoutで作ったら、EditTextの長さによってダイアログ全体が大きくなったり、小さくなったりとか、手直しが必要な部分はあるのですが、これで部品は全部揃いました。

先にシェイクダウンして、ロジックを全部組み立て、レイアウト調整はその後にしたいと思います。今回はテーマなどもまじめに作って、少し見栄えのいいものしたいと思うので。

出来上がったダイアログはこんな感じです。

命名があまりにもやっつけですね。まぁ、後でリファクタリングかければいいので変数名をいじる危険がほとんど無いのは助かります。そういう点はとても楽でいいです。

class KinDialog extends Dialog {
	static final String TAG = "KinDialog" ;
	private Context mContext ;
	private int mKingaku ;
	private int mNinzu ;
	private EditText eKin;
	private EditText eNin;
	private OnDataChangeListener mListener;
	protected KinDialog(Context context,OnDataChangeListener listener, int kingaku, int ninzu) {
		super(context);
		mContext = context;
		mKingaku = kingaku;
		mNinzu = ninzu;
		mListener = listener;
	}
	/*
	 * onCreate
	 * @see android.app.AlertDialog#onCreate(android.os.Bundle)
	 */
	protected void onCreate(Bundle savedInstancdState){
		super.onCreate(savedInstancdState);

		LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

		requestWindowFeature(Window.FEATURE_NO_TITLE);

		View dialogView = inflater.inflate(R.layout.kindialog, null);

		TextView dTitle = (TextView) dialogView.findViewById(R.id.dialog_title);
		dTitle.setText("Sogo info");
		TextView kinView = (TextView) dialogView.findViewById(R.id.kin_title);
		kinView.setText("Kingaku");
		TextView ninView = (TextView) dialogView.findViewById(R.id.nin_title);
		ninView.setText("Ninzu");
		Button bOk = (Button) dialogView.findViewById(R.id.button_ok);
		bOk.setOnClickListener(new View.OnClickListener(){
			public void onClick(View v){
				int k = Integer.valueOf(eKin.getText().toString());
				int n = Integer.valueOf(eNin.getText().toString());
				mKingaku =k;
				mNinzu=n;
				
				mListener.OnDataChange(k, n);
			}
		});
		Button bCancel = (Button) dialogView.findViewById(R.id.button_cancel);
		bCancel.setOnClickListener(new View.OnClickListener(){
			public void onClick(View v){
				dismiss();
			}
		});
		eKin = (EditText) dialogView.findViewById(R.id.kin_box);
		eKin.setOnKeyListener(new View.OnKeyListener(){
			public boolean onKey(View v,int keyCode,KeyEvent event){
			// we ignore ENTER key
	    		if (keyCode == KeyEvent.KEYCODE_ENTER	) {return true;}
			return false;
		}});
		eNin = (EditText) dialogView.findViewById(R.id.nin_box);
		eNin.setOnKeyListener(new View.OnKeyListener(){
			public boolean onKey(View v,int keyCode,KeyEvent event){
	    		if (keyCode == KeyEvent.KEYCODE_ENTER	) {return true;}
			return false;
		}});
		eKin.setText(String.valueOf(mKingaku));
		eNin.setText(String.valueOf(mNinzu));
		
		setContentView(dialogView);

	}
	public void setOnDataChangeListener(OnDataChangeListener listener){
		mListener=listener;
	}
	interface OnDataChangeListener{
		void OnDataChange(int k,int n);
	}
}

2011年2月 1日 (火)

Custom Dialog

とりあえず、ダイアログで数値を入力することにしてダイアログを作り始めました。

Developerサイトを参考に、レイアウトからViewをinflateしてダイアログを表示する処理を作ったのですが、showDialogしても画面が暗くなるだけで新しいダイアログは出ません。
もちろん、OnCreateDialogを上書きしてあります。

レイアウトにEditTextがあるのがいけないのでしょうか。でも、TimePickerはEditTextがあっても動いているので、それが直接の原因とも思えません。なにか、setなんちゃらをやらなければいけないのでしょうか。それとも、onCreateからshowDialogしているのがいけないのでしょうか。
ソースが長くなるのは嫌だといって、生意気にも別のクラスに作ったのがいけないのでしょうか。

でも、Logの出力を見ていても、showDialogより前からメッセージは出ていません。まったく不思議です。とりえあず、思い悩んでも仕方ないので明日考えることにして今日は寝ます。

« 2011年1月 | トップページ | 2011年3月 »