2011年3月28日月曜日

android アプリ 節電しようぜ! リリース

金曜日の夜のことです。寝る前にネットに目を通すと、以下のような情報を見つけました。

-----東電が電気使用状況データをCSVで公開 「アプリ作ったら知らせて」と経産省
東京電力が電気使用状況データをCSV形式で公開したことを受け、経済産業省情報プロジェクト室は、そのデータを活用した外部サービスを作ったら知らせてほしいとTwitterで呼びかけている。
2011年03月24日 15時54分 更新

東京電力がこのほど電気使用状況データをCSV形式で公開したことを受け、経済産業省情報プロジェクト室(@openmeti)は3月24日、そのデータを活用したアプリを作ったら知らせてほしいとTwitterで呼びかけた。「優れたアプリは国でも取り上げていきたい」という。

東電が公開しているのは、当日と前日の電気使用量の速報値。電気使用状況はこれまで東電のグラフで確認できたが、23日からはデータをCSV形式でダウンロードできるようになり、外部の開発者がそのデータを使ったサービスを作りやすくなった。

経産省情報プロジェクト室は、東電の電気使用状況データを活用したアプリを作ったら「@openmetiに向かってつぶやいてください」とコメント。集まった情報はひとまず、民間のWikiページ「東北関東大震災(東北地方太平洋沖地震)@ウィキ」にまとめる方針で、「編集して情報を加えていっていただけると助かります」ともツイートしている。

東電の電気使用状況データを活用したサービスは、ヤフーが公開した「電力使用状況メーター」や、エヴァンゲリオン風デザインの「NERV専用監視装置」など続々と登場している。-----
http://www.itmedia.co.jp/promobile/articles/1103/24/news068.html

上記を読んで、東電も色々大変だと思い、土曜日にざっくりと「節電しようぜ!」というアプリを作成しました。


これはただ単にCSV形式ファイルをダウンロードして、最新の電気使用量を取得するアプリです。

yahooなどのWEBと表示できる機能は同じですが、アプリを立ち上げると最新情報を取得するできる点が異なっています。
また、WEBが繋がらない場合でも、内部に過去のデータをもっているので、データを見ることができます。

とりあえず急ぎでざっくりと作成したので、今は電力情報しか見ることができませんが、時間があるときに
バージョンUPして色々と機能を追加していけたらと思っています。
明日くらいには検索でもひっかかるようになると思います。アプリ名は「節電しようぜ!」です。



そんな感じの現状報告です。
自分からツイートする気はないので、ダウンロードしてくれた方が呟いてくれたら幸いです。

疲れた休日でした。では、お休みなさい。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2011年3月16日水曜日

Pythonはじめました

Pythonの勉強をはじめました。
理由はソーシャルサイトを作成しようと考えているからです。
そのための言語を色々と調査していたのですが、結局Pythonにすることにしました。
正直、最後はRubyとPythonのどちらにするか激しく迷ったのですが、Google App EngineとFaceBookで
の実績を評価することにしました。

というわけで、これからはPythonの情報も取り扱っていこうと思います。
なんか日本語の情報がやたら少ないですけど、日本じゃ人気ないんですね。
でも、英語圏では情報が多いのであまり気にする必要もなさそうです。
本格的に利用していくつもりなので、基本からがっつり勉強する為に
「初めてのpython」第3版
を購入しました。

まだ全部は読んでいませんが、良い本です。
Pythonはプログラミング経験のある人なら、「なんとなく」動くコードが書けてしまう言語です。
でも、本格的に利用しようと思うのなら、絶対にこの本を読んでおくことをおすすめします。
さらにいうなら、繰り返し読み込み、演習も覚えこむくらい何度も解いたほうがいいでしょう。
結局のところ、そういった無意識レベルの基礎力が最終的な作りこみの段階でいきてくるのですから。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2011年3月5日土曜日

Android Tips TextView内の文字列リンクから特定のActivtyを呼び出す ~ContentProviderとLinkifyの理解~

Linkifyのリンクからパラメーターを渡してActivityを呼び出す処理が必要になり、ググッたらContentProviderの理解が必要だとわかりました。 しかし、ContentProviderの情報は色々と分散していて理解しにくかったので、まとめます。

・ContentProviderとは?

ContentProviderを利用すると、異なるアプリケーション間でデータを共有できる。
COntentProviderを利用することで、特定のデータタイプを他のアプリケーションが利用できる。

例えば、Androidで利用されている正式なContentProviderには、電話帳がある。
電話帳には、名前、住所、電話番号がリストで表示されている。

content://contacts/people/

という特定のURIを利用することで、どのアプリケーションであってもこのデータにアクセスすることができる。
androidURIの構成は以下の通り。

スキームcontent://
オーソリティcontacts
パスpeople

WEBのURIとほぼ同じですね。オーソリティがホストにあたります。ということで、実装して試してみます。

開発用os(jar)は現在メインで開発している2.1、エミュレータは2.3で確認

1、まずはエミュレーターを立ち上げて電話帳にデータを投入


2、では、実装していきます。

2-1、

AndroidManifest.xmlに

<uses-permission android:name="android.permission.READ_CONTACTS" />

を記述。

2-2、

Activityクラスを作成します。

以下ソースコードです。

public class ProviderTest extends ListActivity {

    public static final String TAG = "ProviderTest";
    
    private ArrayList<ContactPojo> list;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.provider);
    }
    
    @Override
    public void onStart() {
        super.onStart();
        Log.d(TAG, "onStart start ");
        
        ContentResolver resolver = this.getContentResolver();
        Cursor c = resolver.query(Contacts.CONTENT_URI, new String [] {Contacts.DISPLAY_NAME} , null, null, null);
        
        this.list = new ArrayList<ContactPojo>();
        while(c.moveToNext()) {
            
            ContactPojo contactPojo = new ContactPojo();
            
            contactPojo.display_name = c.getString(0);
            
            this.list.add(contactPojo);
        }
        
        if (c != null) {
            c.close();
        }
        
        Log.d(TAG, "onStart end ");
    }
    
    @Override
    public void onResume() {
        super.onResume();
        setListAdapter(new ProviderTestList(this, R.layout.provider_list, this.list));
    }
    

    class ProviderTestList extends ArrayAdapter<ArrayList<ContactPojo>> {
        private Context mContext;
        private ArrayList<ContactPojo> list;

        public ProviderTestList(Context context, int textViewResourceId, ArrayList<ContactPojo> list) {
            super(context, textViewResourceId);
            this.mContext = context;
            this.list = list;
        }
        
        @Override
        public int getCount() {
            return this.list.size();
        }

        @Override
        public long getItemId(int position) {
            return position;
        }
        
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            
            View row = convertView;
            ViewWapper viewWapper = null;
                
            if (row == null) {
                LayoutInflater inflater = getLayoutInflater(); 
                row = inflater.inflate(R.layout.provider_list, parent, false);
                viewWapper = new ViewWapper(row);
                row.setTag(viewWapper);
            } else {
                viewWapper = (ViewWapper)row.getTag();
            }
            
            
            ContactPojo contactPojo = (ContactPojo)this.list.get(position);
            
            viewWapper.getDispName().setText(contactPojo.display_name);
               
            contactPojo = null; // release
            
            return row;
            
        }
    }
        
    /**
     * ホルダーパターンView
     */
    class ViewWapper {
        
        View base;
        TextView disp_name;
        
        ViewWapper (View base) {
            this.base = base;
        }
        
        TextView getDispName() {
            if (disp_name == null) {
                disp_name = (TextView)base.findViewById(R.id.disp_name);
            }
            return disp_name;
        }
        
    }
    
}

一覧を表示するように、ListActivityで作成してます。

特に重要なのは
  • getContentResolverでContentResolverを取得していること。
  • Cursorオブジェクトを取得していること。
です。

続いて表示xmlのprovider.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
     <ListView 
         android:id="@id/android:list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
        
     <TextView 
        android:id="@id/android:empty" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" 
        android:text="データはありません"  />
        
</RelativeLayout>

加えて、リストxmlのprovider_list.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
    <TextView 
        android:id="@+id/disp_name" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        />
        

</RelativeLayout>

上記のソースをビルドして実行します。

上記のような感じで出力されます。

ContentResolverのqueryで指定してる「Contacts.CONTENT_URI」が電話帳のデータにアクセスする為のURIです。Contacts.CONTENT_URIのURIの形式を取得してみましょう。以下が結果。
  • URIスキーム(Contacts.CONTENT_URI.getScheme()):content
  • ホスト名(Contacts.CONTENT_URI.getHost()):com.android.contacts
  • パス(Contacts.CONTENT_URI.getPath()):/contacts
となります。…というか、URI違うじゃん。調査したところ、androidのversionによって違うみたいです。
確認のために、自分でURIを作成してアクセスしてみます。

getContentResolverの後ろのコードに以下の処理を追加します。

ContentResolver resolver = this.getContentResolver();
    
    Uri.Builder builder = new Uri.Builder();
    builder.scheme("content");
    builder.authority("com.android.contacts");
    builder.path("contacts");
    
    //Cursor c = resolver.query(Contacts.CONTENT_URI, new String [] {Contacts.DISPLAY_NAME} , null, null, null);
    Cursor c = resolver.query(builder.build(), new String [] {Contacts.DISPLAY_NAME} , null, null, null);
        

ビルドして実行します。
同じ結果になりましたね。

以上の処理から理解できるのは、URIで電話帳にアクセスすることができ、結果をCursorオブジェクトで取得していることですね。

気になるのは、ContentProviderがCursorを返す仕組みになっていることです。
データベースを通さない処理の場合はどうするのでしょうか…。また、intentを利用する仕組みとどう関連があるのか…。

とにかく、ContentProviderは理解したのでLinkifyとintentを関連付けるサンプルを作成していきます。

3、Linkfyサンプルを十分に読み込んで実装していきます。

参照するのは

http://android-developers.blogspot.com/2008/03/wikinotes-for-android-routing-intents.html

です。

まずは文字列リンクを作成します。

getViewメソッドのContactPojoオブジェクトを取り出している下に、以下のコード処理を追加します。

ContactPojo contactPojo = (ContactPojo)this.list.get(position);
    
    // viewWapper.getDispName().setText(contactPojo.display_name);
    
    Pattern matcher = Pattern.compile("テスト");
    viewWapper.getDispName().setText(contactPojo.display_name);
    String viewURL =    "content://jp.co.sample.android.muzukashii/name/";
    Linkify.addLinks(viewWapper.getDispName(), matcher, viewURL);

ビルドして実行します。

おお、リンクが作成されましたね。

次はAndroidManifest.xmlに

<provider android:name="jp.co.sample.LinkTestProvider" android:authorities="jp.co.sample.android.muzukashii" />

を追記します。

  • android:authoritiesは、URIのホストと同じ意味です。URIのROOTとして扱われます。
  • android:nameはjavaクラスのフルパスを指定します。

では、呼び出されるLinkTestProviderクラスを作成していきましょう。このクラスでは、ContentProviderクラスを継承します。

注意すべき点は、updateやinsertをOverrideする必要があるということです。なんかずさんな抽象化ですね。DB使わない人もいるでしょうに。

気持ち悪いけどここは無視して作成します。で、作成したのが以下のコードです。

public class LinkTestProvider extends ContentProvider {
    
    public static final String TAG = "LinkTestProvider";
    
    public static final String AUTHORITY =
            "jp.co.sample.android.muzukashii";

    
    private static final int NOTE_NAME = 2;

    
    private static final UriMatcher URI_MATCHER;


    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public String getType(Uri uri) {
        switch (URI_MATCHER.match(uri)) {
          
        case NOTE_NAME:
            
            return "hatoyama.kan.owawa/minsyu.kiero";

        default:
            throw new IllegalArgumentException("Unknown URL " + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public boolean onCreate() {
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        return null;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        return 0;
    }
    
    static {

        URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
        URI_MATCHER.addURI(AUTHORITY, "name/*",
                           NOTE_NAME);

    }

}

上記のコードで重要なのは、staticとgetTypeメソッドです。
  • staticでUriMatcherにURIを作成しています。
  • 投げるURIに応じたUriMatcherを全て作成します。
URIはProviderTestのgetViewメソッドに追加した以下のソースと対応しています。

Pattern matcher = Pattern.compile("テスト");
    viewWapper.getDispName().setText(contactPojo.display_name);
    String viewURL =    "content://jp.co.sample.android.muzukashii/name/";
    Linkify.addLinks(viewWapper.getDispName(), matcher, viewURL);

getTypeメソッドで、Uriを振り分ける処理を行っています。
色々なパターンで分岐可能なので、以下の公式サイトのソースを参考にしてみてください。

http://developer.android.com/reference/android/content/UriMatcher.html

上記のソースではcase NOTE_NAME:に処理が入り、「hatoyama.kan.owawa/minsyu.kiero」文字列が返却されます。

この文字列はMIMEタイプを表しています。なので、このMIMEタイプによって呼び出されるActivityクラスを作成するようにします。

作成したのが以下のクラスです。

public class GoalActivity extends Activity {
    
    private TextView sendparam;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.goal);
        
        this.sendparam = (TextView)findViewById(R.id.sendparam);
        
        Intent intent = getIntent();
        Uri uri = intent.getData();

        if (uri != null) {
            this.sendparam.setText(uri.getPath());
        }

    }
    
    @Override
    public void onStart() {
        super.onStart();
    }
    
    @Override
    public void onResume() {
        super.onResume();
    }
}

上記の処理では、URIのパスを取得して画面に表示しています。

続いて表示xmlのgoal.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
    <TextView 
        android:id="@+id/sendparam" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        />
        
</LinearLayout>

最後にandroidManifest.xmlにGoalActivityのintentを設定します。

<activity android:name=".GoalActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:mimeType="hatoyama.kan.owawa/minsyu.kiero"/>
            </intent-filter>
        </activity>

intent-filterを設定します。android:mimeTypeは、LinkTestProviderクラスのgetTypeメソッドで返すMIMEタイプ文字列に対応します。

では、上記のソースをビルドして実行します。
続いて、リンク文字をタップします。

おお。見事にActvityが呼び出されて画面遷移できましたね。

URIのpathもきちんと取得できています。

上記の処理から理解できるのは、
  • 文字リンクのパターンを利用して特定のURIを作成することで、activityの呼び出しを制御できる。
  • Providerクラスで受けとったURIをgetTypeメソッドで分岐し、任意のactivityを呼び出すことが出来る。様々なパラメーターも付加出来る。
これまでやってきたことを応用することで、WEBのような処理を行うUIが色々作れそうですね。

かなり長くなってしまいましたが、これで終了です。お疲れ様でした。

android開発にそれなりに通じていないと、内容的に少し難しかったかもしれませんが、すごく役に立つパターンだと思うので、是非勉強してみてください。

みなさんが素晴らしいアプリを開発して、僕を唸らせてくれることを期待しています。

でわ。

追伸

URIの概念がよくわからないという人は以下の書籍がオススメです。WEB開発に携わるエンジニアは是非是非読んでもらいたい名著です。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

バラク・オバマどっとこむに学ぶWEB構成

Google app engineやAmazonのサーバーをはじめ、色々なクラウドが格安で利用できるので、ソーシャルサイトでも構築しようかと考えています。しかし、これまでにWEBサイトは構築してきましたが、あまりソーシャルサイトは利用したことがありません。
ということで色々と勉強していこうと思っています。
まずは、FaceBookの創業者でオバマのインターネット戦略担当を務めたクリス・ヒューズの手法を参考にするために、バラク・オバマどっとこむの研究とまとめ。

・ベースの色は青色
青色は、知性と精神に関する重要な色彩で、創造性、心のコントロール、頭の回転などを高める。演説が必要なときなどに大きな力を発揮したり、コミュニケーションを円滑にする効果があるとのこと。


http://homepage2.nifty.com/osiete/s590.htm

・言語はphp
まあ、ざっくりつくるのには適してますね。私はphp嫌いなのでパス。

・構成のメモ書き

------------------------------------------------------
header
------------------------------------------------------
navi
------------------------------------------------------
recommned comtents(4つ)                             | 寄付
(数秒ごと)                                                   |
------------------------------------------------------
main                                                           | aside bar
                                                                 |
                                                                 |
                                                                 |
                                                                 |
------------------------------------------------------
footer
------------------------------------------------------

・他に気がついたこと。
naviにstoreがあって収益にしているw。日本の政治家が同じようなことしたら叩かれるな。

・利用しているネットワークメディア
faceBook
twitter
Youtube
Flickr
MysSpace
Black Planet
MiGente
Linkedin

使いすぎ。普通の個人なら

faceBook
twitter
Youtube
Flickr

でいいんじゃないんでしょうか。

・Blogのshare
Digg
FaceBook
Newsvine
Stumble
del.icio.us

とりあえず、ブログ構成も色々と良いパターンをためしていくつもりです。
少しうっとうしく感じるかもしれませんが、より良い情報とUIご提供のためしばらくはご容赦ください。

でわ。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加
Related Posts Plugin for WordPress, Blogger...