Android

2011年2月12日土曜日

AndroidでLibraryを使う(Part2)

さらに前回の続き…。

前回はビルド・パスの構成にてライブラリを追加しましたが、この方法だとLibrary内のリソースが参照できない;;
<libraryPackageName>.R.xxxとかでLibrary側のR.javaのリソースIDは参照できるようだが、そのIDを使ってgetString()とかやってもLibrary側のリソースは取得できない。

さらにLibraryの内部でリソースにアクセスする場合にもcontextが必要で、contextはプロジェクトのMain側で取得するため、プロジェクトのMain側のリソースにアクセスすることはできるが、Library側のリソースにはアクセスできません。

どうやら、リソースを参照するにはライブラリのソースパスごとプロジェクトに含めてやる必要がありそうです。
(どうにかなんないのかな??リソースを使うLibraryはJARで配布できないんだろうか?)

具体的には、

  • プロジェクトのプロパティを開く→Androidのタブ
  • 追加を選んで、Libraryのプロジェクトを選択します。
    ※Libraryのプロジェクトは事前に作成するか、既存のプロジェクトをImportするかしておきます。



  • あとはOKを押すだけで完了。ソースパス毎追加するとパッケージ・エクスプローラはこんな感じになります。

  • genの中にLibraryのR.javaが追加されています。



  • これで、Library側のR.javaも参照できて、そのIDでリソースが参照できるようになります。 ただし、プロジェクト Main側のリソース名とLibrary側のリソース名が区別されない(どちらもR.string.xxxとかで参照することになる)ので、名前の付け方には注意する必要がありそうです。

2011年2月10日木曜日

AndroidでLibraryを使う。

前回の続き…。

今度は作ったLibraryを別のProjectで使う方法。
Libraryの運用方法により、Library自体をProject内部に保存しておきたい場合と、外部のものを参照したい場合の2通りの運用方法が考えられます。

まずは、ProjectにLibraryファイルを含めて運用したい場合。

  1. 普通にAndroid Projectを作成。

  2. 既存のプロジェクトを使ってももちろんOK!

  3. プロジェクト内にLibrary(.jarファイル)をコピー。

  4. 場所はどこでも構わないと思うけどlibフォルダを作ってコピーするのがわかりやすいかと。

    ↓こんな感じ


  5. ビルドパスの構成変更

  6. プロジェクトを右クリックしてビルド・パス→ビルド・パスの構成を選ぶ

    ↓↓こんな画面が開きます


    ここで、JARの追加を選ぶとさらに次の画面に


    ここで先程追加したJARファイルを選択してOK。今回はlibフォルダの中に追加してます。
    そうすると↓のようにビルド・パスにライブラリが追加されます。

    このままOKで完了。パッケージ・エクスプローラに参照ライブラリーの項が追加されています。

  7. ライブラリを利用するコード

  8. ライブラリのパッケージをimportすると、ライブラリ内のクラスが使えるようになります。たったこれだけ。
    package com.sample.Application;
    
    import android.app.Activity;
    import android.os.Bundle;
    import com.sample.library.SampleLibrary;
    
    public class SampleApplicationActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            SampleLibrary sampleLibraryClass = new SampleLibrary();
            
            sampleLibraryClass.test(); //SampleLibraryのtest()メソッドを実行
        }
    }
    
外部Libraryを参照する場合
    プロジェクトにLibraryを含めたくない場合(共通Libraryを使う場合など?)は、上記手順の
    2.JARファイルのコピーを行わない。

    3.ビルド・パスの構成の 『プロジェクトのプロパティ・Javaのビルド・パス』の画面で『外部JARの追加』を選ぶ。
    出てきたダイアログで使いたいのJARファイルを選択する以外は一緒です。

2011年2月8日火曜日

AndroidでLibraryを作る

Android用のライブラリを作成する方法

手順をメモ。
  1. プロジェクト作成
    • 新規→Androidプロジェクトを選択
    • 通常通りにプロジェクト名・ビルドターゲットの設定を行う。
    • Create Activityのチェックを外す。


  2. プロジェクトのプロパティ設定
    • プロジェクトを選択→右クリック→プロパティ→Androidタブで Is Libraryをチェックする。


  3. AndroidManifestの設定
    • アプリケーションタブでDefine an <application> tag in the AndroidManifest.xmlのチェックを外す。
    • なお、Label/Iconの指定は無視されるので気にしない。


    • これで、できたAndroidManifest.xmlはこんな感じでとってもシンプル。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.sample.library"
          android:versionCode="1"
          android:versionName="1.0">
    </manifest>
    

  4. リソースの整理
    • デフォルトで不必要なリソースができているので削除する。


    • こんな感じでできてるはずなので、drawable-xxx/icon.png(3か所), layout/main.xml, values/string.xmlを削除。
    • リソースを使用しない場合は、resフォルダ内のサブフォルダ drawable-xxx, layout, values等は削除しても構わないが、 assets, res, genのフォルダのみは残しておかないとエラーになる。
    • genフォルダ内にR.javaが自動生成されている。気持ち悪いので一応これも消しておく。
    • リソースを使用する場合は、必要なものを残しておくか、削除後に新しく作成する。

  5. ソースクラスの作成
    • ライブラリとして実装したいクラスをjavaで普通に作成する。

  6. ビルド実行
    • 普通に自動ビルドされるが、一旦クリーンアップして再ビルドするのがなにかと問題が起きにくい。
    • default.propertiesが非同期と言われた場合は、そのファイルを右クリック→リフレッシュしてみる。

  7. ライブラリ(*.jar)作成
    • プロジェクトを右クリック→エクスポート→Java→JARファイル→次へ を選択。
    • エクスポートするものを選択。
      初期設定ではすべてが選択されているが、rootにある次のものは除外すべき。
      (.classpath, .project, AndroidManifest.xml, default.properties, propguard.cfg)
      これらを除外しないと、(これらを除外していない)複数のLibraryを使用するときにDuplicate ..... といって怒られる。
    • また、ライブラリを自プロジェクト内のフォルダに生成した場合、2回目のエクスポート時にライブラリもエクスポート対象になっていると、「JAR ファイルは、それ自体にはエクスポートできません。」と表示される。この時は、あわてずライブラリをエクスポート対象から除外する。


    • その他はデフォルトのままで特に問題なし。Jarファイルの場所を名前を選択し、次へ もしくは 完了。
    • 次へを選んだ場合は適宜設定を進めて完了を選ぶ。

  8. これで、選択した場所にライブラリが作成される。
    • あとは、できたjarファイルを好きなところにコピーして運用するだけ。ライブラリの使い方はまた別途書きます。

2011年2月7日月曜日

Twitter雑感

Twitter参加しています。
@aoi_terenceというIDでやっていますので、覗いて見てください。

ということで、現在フォローしている数1891、フォローされている数1767です。
かなりヘヴィユーザーですが、殆ど地元山形の方との出会い交流の場になっています。

さて、Twitterやる上で覚えなくてはいけないことをちょっと説明します。
以下はさっき呟いた内容です。
  1. 南ジャスコへデート?旦那と。
  2. こんなラベルにしたよ。新しいCD。 http://twitpic.com/3xa1tb
  3. @web_eye 主にかあ、してないから主婦じゃないなあ。
  4. 現在は可読性を重視するので短い名前は付けないように、また動詞と名詞、形容詞の順番を英文に近くとなってますね。開発ツールもそれに対応しているのでパンチは楽ですが。RT @_h4: aoi_terence 変数名の付け方で世代がわかりますね。学生時代の実習はpascalで、研究には
  5. どれくらいで復活するんだろうね?QT@ishikotukotu: わたしは一時下山したけど、、、代わりに東北電力さんがすごい勢いで登っていきましたよ~~。ナイターまで復活したら、ナイター行きます~。
  6. 主婦って何をすれば主婦って呼ばれるのかな?三食ご飯作ってないからなあ。RT @web_eye: 私達ってそもそも主婦なんかな?主婦の定義が気になった朝…w RT aoi_terence: web_eye スーパー主婦とな?一番私がなれなさそうなものだな…
解説
1.は、ただ呟いただけのまず基本の呟き。
2.は、ただの呟きに他サイトにあげた画像リンクを貼ってます。
  画像あげる場所はTwitter対応のところが複数あります。
3.@web_eyeに呟きを投げて居ます。通常@やReplyと言われるものです。相手先の@やReplyに表示されます。
4.非公式RT;参照して返信。相手の呟きを自分の呟きに取り込んで返信しています。
 これをすると私をフォローしている方にも参照内容が見えます。
 あまり推奨されてませんが、これに関しては後ほど。
5.QT:上記の非公式RTと一緒です。
他に公式RT があります。参照して情報を付加せずに呟いてます。と言う感じ。

で、まあ、こんな感じでツイッターをだらだらやっていると、遠くの方から、
RTを非公式で使うな、呟きをだらだら長くするな
と言う声が聞こえるのです。
確かに、同じユーザさんをフォローしてると同じ発言が重複してきて見づらいってのは分かるのですが、如何せん現在の私のツイッターは一人で誰に向かって呟いてるのか分からない状態ではなく、ある程度意味を持った集まりの中で繋がった関係を持って呟いているので、呟きの前後の状況が分かった方が話の流れに乗り易いのです。
これは既にコミュニティを作ってるのと同じ感覚です。
意図して作ったのではなく、同じような地域で暮らしているもの同士がふとした生活の中の情報を共有しているうちに出来ていったもので、ある程度の人数が集まってきたのもこのRT・QTのおかげだと思います。
自分のフォロワーさんがRT・QTして居る方ってどんな人だろう、あ、私が知りたい情報を知ってる人だ。じゃあ、私もフォローしておこう。
こんな連鎖で、どんどん膨らんできている気がします。
現実にお会いした方も、もう10人を超えようとしていて異業種交流が活発になっています。
このように、目的をもってフォローして行くのはとても有意義なのですが、Twitter本来の姿からするとどうでしょうね?
でも、悪い使用方法ではないと思うので、ここで、非公式RTは罪悪ばかりじゃないと言うことを言いたかったのです。

2011年2月6日日曜日

Activity内でのViewの遷移について

さて、アプリケーションの開発についてですが、
大抵のAndroidアプリ開発サイト(本)では、Activity = Windowっぽく解説してあります。

つまり、複数の画面間の遷移が必要なアプリの場合は、
Activity1⇔Activity2⇔Activity3・・・のようにActivityをIntentで遷移するのが一般的だということでしょうか。

しかし、草木塔アプリは1つのActivityでViewを入れ替える方式で作ってみました。
もちろん、Activity切り替え方法を否定するつもりは毛頭なく、こういった実装方法もあるのでは?といった意味で実験的手法です。
実際やってみるとパンくずリスト付きの画面遷移っぽいことをやるのにはこっちの方が向いてるかもしれません。

 この方式で悩ましい点は、
  1. 俗にMVC手法で言うところのControlerの役割をどうする?
    • 本来Activityがこの役割のはず。→でも今回はActivityは1個って決めたから;;
    • View = ViewControlerという位置づけにする。つまりUserView Classを作成して必要に応じOnClickとかをImplementしてUIイベントをハンドルしようということ。
    • こうすると、ViewとControlerが分離されてないじゃないか…と言う声も聞こえてきそうだけど、この場合はR.layoutで指定した部分をViewだと言い切ることにする。現にlayout部分では、Viewの要素の定義やら、レイアウトに関する記述がある。
  2. 戻る処理をなんとかしなければならない。
    • 通常、Activityではバック キーでActivityを閉じてしまいますが、今回は前の画面に戻るようにしなければならない。
    • この処理は必須ではなく、画面上に戻る遷移のボタンを設けることも可能。(けど一般的なApplicationの操作から乖離するからやめた方が良い?)

ということで、sampleコードは次のようになります。
 (OnBackPressed()はAPI Level5 なんで、その辺はゴニョゴニョ・・・。)

MainActivity Class
メインのActivityはViewの制御機能を持たないようにしています。

public class MainActivity extends Activity {
 private Stack<View> childView;


 /*********************************************************
  * Application実行時の最初のイベント。
  * 最初の画面を作成し、WindowListのTopに設定する。
  *
  * @see android.app.Activity#onCreate(android.os.Bundle)
  *********************************************************/
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  requestWindowFeature(Window.FEATURE_NO_TITLE);

  childView = new Stack<View>();
  childView.clear();

  // 最初のViewを表示
  pushContentView(R.layout.user_first_view);
 }

 /*********************************************************
  * 戻るボタンが押されたイベント処理。
  *
  * @see android.app.Activity#onBackPressed()
  *********************************************************/
 @Override
 public void onBackPressed() {
  if(!popContentView()) {
   // 取り除く前のViewがない場合は、
   //本来のBackPressed(=finish())を実行(必須ではない)
   super.onBackPressed();
  }
 }
 /*********************************************************
  * 子Viewを追加する。
  *
  * @param view 追加する子View
  *********************************************************/
 public void pushContentView(View view) {
  childView.push(view);
  super.setContentView(childView.peek());
 }
 /*********************************************************
  * 子Viewを追加する
  *
  * @param resid 追加する子のリソースID
  *********************************************************/
 public void pushContentView(int resid) {
  // 最初の子Viewを作成
  LayoutInflater inflater
   = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
  View view = (View)inflater.inflate(resid, null);

  childView.push(view);
  super.setContentView(childView.peek());
 }
 /*********************************************************
  * 子tViewを取り除く
  *
  * @return true 取り除き成功 / false 取り除けなかった
  *********************************************************/
 public boolean popContentView() {
  if(childView.size() > 1) {
   // ViewStackに前の画面がある場合はPop
   childView.pop();
   //最上位のViewをsetContentView()する。
   setContentView(childView.peek());
   return true;
  }
  return false;
 }
}

最初のViewのClass
ボタンをクリックすると次のViewに遷移するようにしてみました。

public class UserFirstView extends LinearLayout {
 /*********************************************************
  * コンストラクタ(LinearLayout)
  *
  *********************************************************/
 public UserFirstView(final Context context, AttributeSet attrs) {
  super(context, attrs);
 }
 /*********************************************************
  * Inflaterを使ってViewを実体化する場合は
  * onFinishInflate()以降で findViewByIdをする。
  *
  *  @see android.view.View#onFinishInflate()
  *********************************************************/
 @Override protected void onFinishInflate() {
  //Buttonの処理を追加
  Button buttonNext = (Button)findViewById(R.id.buttonNext);

  buttonNext.setOnClickListener(new OnClickListener() {
   /*********************************************************
    * ボタンがクリックされた
    * →次の画面に遷移する
    *
    * @see android.view.View.OnClickListener#onClick(android.view.View)
    *********************************************************/
   @Override public void onClick(View v) {
    MainActivity mainActivity = (MainActivity)getContext();
    // 次のViewを表示
    mainActivity.pushContentView(R.layout.user_next_view);
   }
  });
  super.onFinishInflate();
 }
}

次のViewのClass
ボタンをクリックすると前のViewに戻るようにしてみました。

public class UserNextView extends LinearLayout {
 /*********************************************************
  * コンストラクタ(LinearLayout)
  *
  *********************************************************/
 public UserNextView(final Context context, AttributeSet attrs) {
  super(context, attrs);
 }
 /*********************************************************
  * Inflaterを使ってViewを実体化する場合は
  * onFinishInflate()以降で findViewByIdをする。
  *
  *  @see android.view.View#onFinishInflate()
  *********************************************************/
 @Override protected void onFinishInflate() {
  //Buttonの処理を追加
  Button buttonNext = (Button)findViewById(R.id.buttonPrev);

  buttonNext.setOnClickListener(new OnClickListener() {
   /*********************************************************
    * ボタンがクリックされた
    * →前の画面に遷移することもできる
    *
    * @see android.view.View.OnClickListener#onClick(android.view.View)
    *********************************************************/
   @Override public void onClick(View v) {
    MainActivity mainActivity = (MainActivity)getContext();
    // 前のViewを表示
    mainActivity.popContentView();
   }
  });
  super.onFinishInflate();
 }
}

UserFirstViewのXMLです
UserNextViewは省略しますが似たようなものです。あくまでSampleなんで…

<?xml version="1.0" encoding="utf-8"?>
<com.sample.UserFirstView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
 <TextView
   android:layout_width="wrap_content" android:layout_height="wrap_content"
   android:text="FirstView">
 </TextView>
 <Button
   android:id="@+id/buttonNext"
   android:layout_width="wrap_content" android:layout_height="wrap_content"
   android:text="Next">
 </Button>
</com.sample.UserFirstView>

※ということで、結局この方法のメリットは何かと言うと、各画面間でたくさんパラメータを受け渡ししなければならない時にIntentだとちょっと不便…を解消できるかなと。

なお、ブログにソース貼り付けるにあたり、こちらのページを参考にさせていただきました。

2011年1月31日月曜日

アプリ開発記(1.草木塔編)

:::Android Aplication::: 草木塔のページでも紹介している通り、アプリを開発&公開しています。
 ※草木塔の画像や位置をみることができるアプリです。


アプリの開発にあたり、最初に感じたことは…

全体的にはとっても作りやすくていい感じなのですが、その中で感じた不満をぶちまけてみます。

・標準のリソースってださい。(何があるのかわかんない;;)
 ボタンとか貼り付けると、デザイン的にもちょっと微妙なおっきいボタンが…。
 iPhoneの洗練された(とあくまでAppleが言っているのであって、主観ではありません!)UIのイメージからはかけ離れているように感じます。
何か作るときはまずリソースから作んなきゃならないみたい。


・是非はあると思いますが、iPhoneでいうところのUINavigation関連のような標準的なFrameWorkが用意されていない。
 もちろんほとんどのAndroid端末には戻るのハードボタンがついているのでiPhoneのNavigationBarのように戻るボタンとかパンくずリストとかの実装をどうするのかは微妙な感じなのは知ってますが…
 あの標準のタイトルバーはないでしょう、もう無条件でrequestWindowFeature(Window.FEATURE_NO_TITLE); 決定みたいな。


※草木塔アプリでは自前のタイトルバーを用意してiPhoneっぽいNavigationBarをイメージしてみました。


・ListViewの機能が微妙。
 Category付のListViewとか作るのがちょっと大変。
 ExpandableListViewとか使うと以外に簡単にできるのかもしれないが、今回はListViewの勉強を兼ねてListViewに細工して使ってみた。




 ・標準でピンチズーム対応のViewがない。
 ピンチで拡大縮小するのもiPhoneの専売特許?かどうかはわかりませんが、ピンチでの拡大縮小はある程度市民権を得ているものと思われ、実装していないとなんだかな~のアプリになりそう。
 マルチタッチ対応がAnrdoid2.0からということで、ピンチズームはどうなんだろうと言う意見もあるかのしれないが、この状況をみる限り2.0以下はほとんど無視して構わなそう!?って言うか無視するって決めました。(1.6な方ごめんなさい!)


※草木塔アプリでは、画像を表示する部分でピンチズームに対応しています。
iPhoneっぽく、ダブルタップで初期状態(標準ズーム)に戻るようになってるんですよ!?
また、この画面をシングルタップすると、詳細表示画面に遷移するのですが、ここにはくるんと回って遷移するAnimationをSDK Sampleからいただいて採用しています。


ここまでいろいろとiPhoneと比べて書いてきましたが、実は(諸般の事情でまだ公開していませんが)草木塔アプリのiPhone版が最初に存在しており、それを移植したからなんです。

現時点では不満点はまだまだありますが、それでも作りやすい・使いやすいものであることは間違いないようです。
今後、ライブラリとかSDKのアップグレードとかでどんどん良いものになっていくことを期待します。
Published with Blogger-droid v1.6.6

2011年1月7日金曜日

GALAXY Tabってこんなやつ Part2

>

GALAXY Tabでブログ更新

アメブロにこんな記事を更新してみました。 ----------------------------------------------------------------- Galaxy Tab が我が家に来てから、色々文句言いながら使ってます。 取り敢えず先住民のアイポッド君と比較してみます。
  1. 外見に関して
  2. <良いところ> 大きくて見易い 意外と液晶が綺麗 片手で持って、操作が出来る
    <悪いところ> 結構厚い、1センチ近くあるから持ちづらい 片手で持ってると、流石に小指が痺れる 見た目より、重い
  3. 操作性
  4. <良いところ> 電源のスイッチがおおきいので、押しやすい。 比較的音質がいいかな
    <悪いところ> カメラのシャッターボタンがホームボタンの脇に表示されて間違えて終了しちゃう。 ズーム操作が出来ない。
  5. 日本語入力時
  6. <良いところ> 画面が大きいのでタッチが楽。 キ-ボード入力も楽なので、ローマ字入力が出来る。 Androidなので、色々な変換ソフトの選択肢がある。
    <悪いところ> フリックセンスが悪い。 とにかくキーセンスがださい。 自分で細かく設定しないと使いづらくて。。。 試しに、殆ど変換なしのフリック入力でどんな文章になるかテストです。 ちやみに,今からフリックエラーガどれくらいでるか、修正無でやってみますが、やっぱ。文節へんかんご遅くてかすなので、もう少し早く最適な変換に成ってほしいです。ちょっと、すとれすふるこなあ、そう、かってにゆうりよくしようとして、こッテナルノガオオイデス 流石に、ギャラクシータブでブログ書くのは疲れました。 携帯からまめにブログ更新をする、有名人は偉いなあ。
----------------------------------------------------------------- と、途中加筆訂正しましたが、こんなもんでした。

カメラ機能について

カメラに関しては、調査不足だったのでどんな機能があるか全然徒手空拳でした。 携帯電話に付いてるカメラ機能位なんだろうなあと思って使って見たらと言う前提で使った結果が以下です。
  1. ズームがない!
  2. え?なんでズームがないの? SO905iにさえ付いてたのに、遠くのものをズーム出来ない。 自分が撮りたい部分だけを撮影できない。 結構ショックでした。
  3. ライトが眩しい!
  4. 暗い所を撮影する時、フォトライトとフラッシュが光ります。 バッテリーが大きいので結構強い光です。 カメラに見えないものが、あんな強い光を放つのは周囲の人もびっくり。
  5. 動画を撮っても容量気にしない
  6. SIMに保存するので2GのSIM積んでれば、容量なんて気にしない。 片手持ちだとさすがに撮りづらい。 大きい液晶で見ながら撮影が出来ます。
  7. 撮った写真のサンプル
  8. 撮った動画のサンプル

  9. 幼稚園の壁画紹介です。外からも中からも入っていかないと見えないところを紹介してます。 歩きながら撮ってるので、手振れしてるとは思いますがこんな感じならOK?
  10. 設定画面色々
  11. 撮影サイズ:2048×1536、2048×1232、1600×1200、1600×960、1024×600、800×600 ホワイトバランス:自動、晴天、くもり、白熱光、蛍光灯 撮影効果:標準、ネガポジ反転、モノクロ、セピア ISO:自動、100、200、400 画質設定:スーパーファイン、ファイン、標準
    プレビュー表示:撮影するたびにプレビューする GPS:撮影画像にGPS情報を設定するか シャッター音:3種類 保存先:本体もしくはmicroSDカード 設定リセット
    露出値
    フラッシュ:自動、On、Off