洗濯表示アプリ

洗濯表示が変わるそうですね。
そんなニュースを見たので、ちょっと簡単なアプリ作ってみました。

対し他アプリではないんだけど、
マテリアルデザインっぽくしてみよう~ということで
あんまりデザインはやらないんですが、
デザインとアニメーション少し頑張ってみました。

一番力はいってるのは新洗濯表示と旧洗濯表示の切り替えの部分で、
Meaningful transitionsで紹介されてるHierarchical timingを実装してみました。
意外にめんどくさかった!!!

グーグルのHierarchical timing

グーグルのHierarchical timing

GridViewで並べたアイコンの左上から順に切り替わっていくような形になってます。
これが実装されてるものあんまりないかもしんないから珍しいかもしれないです。
良かったらチェックしてみてください~

洗濯表示のHierarchical timing

洗濯表示のHierarchical timing

洗濯表示アプリ

洗濯表示アプリ



洗濯表示 – https://play.google.com/store/apps/details?id=exciton.jp.laundrysymbol



この記事のトラックバック用URL - http://mashi.exciton.jp/archives/61/trackback


PendingIntentとAlermManager

ActivityやServiceを時刻指定で起動させたいときは、PendingIntentを作成し、Alermマネージャーに登録する
この2つのクラスをなんとなくセットで使っていると動作がよくわからず、複数のタイマーをセットした時におかしなことになります。

この2つのクラスはどう働いているか、別々に考えるとわかりやすいです。

まず、よくあるサンプルコード


public foobarTimer(Context context, Calendar when, String message){
  //起動させたいActivity, ServiceなどのIntentを指定
  Intent intent = new Intent(context, MainActivity.class);
  intent.putExtra("tag_name", "hello");//起動時に渡したい値をセット

  //intentを指定してPendingIntentを作成する。
  PendingIntent pIntent = PendingIntent.getService(context, 0, intent, 0);

  //AlermManagerをコンテキストより取得
  AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

  //AlermManagerに起動する時間と起動したいIntentをセットしたpIntentを指定
  am.set(AlarmManager.RTC_WAKEUP, when.getTimeInMillis(), pIntent);
}

よくあるサンプルだし、通常のタイマーとしてはこれで問題なく動くんだけど、

PendingIntent pIntent = PendingIntent.getService(context, 0, intent, 0);

よくわかんないから0でいいや!ってなってしまいがち


Android ReferenceのPendingIntentをみると
getActivity(Context context, int requestCode, Intent intent, int flags)
第2と第4引数はそれぞれrequestCodeとflagsとやらを指定しろということになってる。

まず第2引数のrequestCodeは、そのアプリケーション内でPendingIntentを区別するためにユニークな値を入れる必要がある
たとえば幾つかのタイマーをセットできるアプリを考える。
先ほどのfoobarTimer関数を利用してこのように3つのタイマーを同時にセットした場合、これらはすべてrequestCode=0と指定されている

Calendar after10 = Calendar.getInstance().add(Calendar.SECOND, 10);
Calendar after20 = Calendar.getInstance().add(Calendar.SECOND, 20);
Calendar after30 = Calendar.getInstance().add(Calendar.SECOND, 30);
foobarTimer(this, after10, "10秒後です");
foobarTimer(this, after20, "20秒後です");
foobarTimer(this, after30, "30秒後です");

この場合、同じrequestCodeであることが原因で、3つが正しくセットされない。
結果としては30秒後に「10秒後です」と表示される。
というとんでもない事になります。


なぜこのようなことが起きるか掘り下げてみると、まずこの関数
PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)
必ず新しくPendingIntentを作り出すわけではありません。
登録されているPendingIntentを再び返したり、なければ新しく作成したり、などをしているようです。
それを判断するのが requestCodeflagsなわけです。

PendingIntentのFlagsの説明をみると

FLAG_CANCEL_CURRENT Flag indicating that if the described PendingIntent already exists, the current one should be canceled before generating a new one.
FLAG_NO_CREATE Flag indicating that if the described PendingIntent does not already exist, then simply return null instead of creating it.
FLAG_ONE_SHOT Flag indicating that this PendingIntent can be used only once.
FLAG_UPDATE_CURRENT Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent.

4つのFLAGが表記されてます。

詳しく説明すると

FLAG_CANCEL_CURRENT: 同じrequestCodeのPendingIntentが存在したら、それをキャンセルして新しく作ります。
FLAG_NO_CREATE: 同じrequestCodeのPendingIntentが存在すればそれを返します。そうでなければNullを返します。
strong>FLAG_ONE_SHOT: 一度特定のrequestCodeを持つPendingIntentが作られたら、それ以降で同じrequestCodeを指定された場合は最初に作られたPendingIntentを返し続けます。
FLAG_UPDATE_CURRENT: 同じrequestCodeのPendingIntentが存在するばあい、それをつかうが、putExtraの値は新しく更新します。

という指定になっています。
flagsに0を指定した場合にどうなるか、見つけられなかったのですが、FLAG_ONE_SHOTと同じ動きをしているとおもわれます。


そしてAlermManager.set()ですがこれは単純に、指定された時間にPendingIntentを実行する。
ただし、すでに同じrequestCodeのPendingIntentがセットされていたら、それを更新する。と考えればよいです。

30秒後に「10秒後です」と表示されたのは、2回めのPendingIntent.getActivity()で同じrequestCodeが指定されたため、
1回めに作成された「10秒後です」がセットされたPendingIntentが返されて、それが30秒後の指定でAlermManager.set()されてしまったために起きた現象です。


PendingIntentとAlermManagerを使う場合は
requestCodeを意識して、書き換えなのか、新規登録なのかを考えながら書く必要があります。

以下のサイト参考にさせていただきました。
http://d.hatena.ne.jp/yujimny/20110303/1299115905



この記事のトラックバック用URL - http://mashi.exciton.jp/archives/45/trackback


AndroidのUIスレッドTimer

Androidでポップアップウィンドウとか出した時に、数秒後に閉じるみたいなことって結構あるけど、
普通のTimerで↓みたいにやるとうまく行かない。


    new Timer(true).schedule(new TimerTask() {
      @Override
      public void run() {
        hidePopupWindow();
      }
    }, delay);

Activityに属するウィジェットの表示なんかを変更しようとする場合は
Handlerを通じてUIスレッドから実行しないといけない。

んだもんだから、下記のようなコードになる


final Handler handler = new Handler();
new Timer.schedule( new TimerTask(){
        @Override
        public void run() {
            handler.post( new Runnable() {
                public void run() {
                     hidePopupWindow();
                }
            });
        }
    }, delay);

hidePopupWindow()したいだだけなのにずいぶんと大げさなコードになっちゃう。
こりゃいかん!

ということでUIスレッドタイマー作った!


public class UITimer {
  private Timer timer;

  public UITimer(final Runnable run, long delay){
    this(run, delay, 0L);
  }
  public UITimer(final Runnable run, long delay, long period){
    timer = new Timer(true);
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        new Handler().post(run);
      }
    };
    if(period > 0){
      timer.schedule(task, delay, period);
    }else{
      timer.schedule(task, delay);
    }
  }

  public void cancel(){
    if(timer != null)
      timer.cancel();
  }
}

使い方はこんな感じ。
どや、これでかんたんやろ!


    new UITimer(new Runnable() {
      @Override
      public void run() {
        hideUndoPopup();
      }
    },3000);

あぁ、関数ポインタが欲しくなってくる、、、、

=====================
TimerやTimerTaskを使わないで
Handlerだけで実現する方法もあるようです。

[AndroidでタイマーからUIを操作するAdd Star]
http://d.hatena.ne.jp/seinzumtode/20130504/1367662040



この記事のトラックバック用URL - http://mashi.exciton.jp/archives/37/trackback


PythonとRubyのふんわりとした比較

なんか新しい言語に手を出してみよう!
と思い立ったので、今風なLL言語でもやってみようと思います。

候補はPythonとRuby
この2つは割りと似たり寄ったりなので、好きな方をやればよいという話にはなる。
いろいろな比較をしてみてもだいたい似たような言語だ。
片方にやれてもう片方にできないということはほとんどなさそう

問題はどっちが好きなのかわからないので、戦ってもらいました。
細かい比較とかはよそに任せてふんわりと比較してみます。

●構文を比較!

サンプルプログラムとしてはゼロから入力値までの数を3で割ったあまりごとにカウントする関数という特に意味のないもの。
あまりがゼロのものだけ、インスタンス変数でカウントしてみている。

Rubyの構文

class Foo
   def countModulo3(num)
      modulo1 = 0
      modulo2 = 0
      @modulo = 0
      for i in 0..num do
         if i.modulo(3) == 1 then
            modulo1 += 1
         elsif i.modulo(3) == 2 then
            modulo2+=1
         else
            @modulo++
         end
      end
      return @modulo
   end

楽しそう!とは思わなかった。とてもお行儀が良いという印象。
do then end end end…
ちなみにdo とか then は省略してもよいそうだ。
でもendは当然だが省略できないって!
C言語系やjavaなんかと比べると大括弧がないし、PHPみたいに$$$$とかないので
シフトあんまり押さないでも良さそうーという気はする
インスタンス変数が@だけでいいのは、楽な場面がちょこちょこ思い浮かぶ。でも妙に浮いてる気もする?

Pythonの構文

class Foo:
   def countModulo3(self,num):
      self.modulo = 0
      modulo1 = 0
      modulo2 = 0
      for i in range(0, num + 1):
         if i % 3 == 1:
            modulo1 += 1      
         elif i % 3 == 2:
            modulo2 += 1
         else:
            self.modulo += 1
      return self.modulo

インデントのみでブロックを判断するという、なかなか思い切った構文
いろいろスッキリはしてるけど、なんだか少し不安にならないでもない。
スペースの数間違えただけでif文の終わりが変わっちゃう!
c言語のように、{}で囲って自由に記述できるようになっていて、インデントはお好きな様に。という方針だと
同じコードでもいくつかの書き方が生まれてしまうけれど、こうして和えて縛りをきつくすることで、多様性をなくしてるという側面もあるようだ

forループのカウントは配列を生成するrange関数をつかうのが定石のようだ
この辺りに余計なルールは極力増やさないという意思が感じられるような気がする

文法が簡素なのは最初は少し頼りない感じはあるんだけど慣れれば書くのは楽になりそうかな?
しかしend end end はどうも好きなれなさそうです。ごめんなさい。

Pythonさんよろしくお願いします!


この記事のトラックバック用URL - http://mashi.exciton.jp/archives/28/trackback


wordpressはじめました。

ワードプレス、気なってはいたんだけど、ようやく入れてみました。
CMSとして使ってるのをよく目にはしてて、便利そうだなーとは思ってたんですが、活用できそうな機会がなかなかなかったので、スルーし続けてました。

ちょこちょこ技術的なことの覚書なんかも書いておきたいなーとおもってたので
ブログつけてこうと思います。



この記事のトラックバック用URL - http://mashi.exciton.jp/archives/14/trackback