Android 4.1 (API Level 16)の ViewPropertyAnimator の変更点を調べました。

 

変更点

以下の3メソッドが追加されています。

  • withLayer()
  • withStartAction(Runnable)
  • withEndAction(Runnable)

 

解説

  • withLayer()

ViewPropertyAnimator を使用してアニメーションを実行する時、

アニメーション対象の View をハードウェアレイヤを使用してアニメーションさせます。

アニメーション終了後は、この設定はクリアされます。

ただし、ハードウェアアクセラレータが使用できない環境では、ソフトウェアレイヤが使用されます。

レイヤーの合成処理をハードウェアに任せることで高速化が期待できます。

 

  • withStartAction(Runnable) / withEndAction(Runnable)

ViewPropertyAnimator を使用したアニメーションの開始/終了時に実行したい処理を設定できます。

 

追加されたメソッドについて、実際に呼び出してみました。

以下のコードを実行すると、アニメーション開始時(3秒後)に、withStartAction() で指定した処理、

アニメーション終了時に、withEndAction() で指定した処理が呼び出されます。

また、withLayer() を呼び出しているので、ビュー(ここではボタン)のアニメーションは、ハードウェアレイヤ上で処理されます。

 

サンプルソースコード

final Button button = (Button) findViewById(R.id.button);

// 指定した View から ViewPropertyAnimator インスタンスを取得する
ViewPropertyAnimator vpa = button.animate();

// ハードウェアアクセラレータが使用できる環境では、ハードウェアレイヤを使用するように設定
vpa.withLayer();

// アニメーション継続期間を設定する(ミリ秒)
vpa.setDuration(3000);

// アニメーション開始時に実行する処理を設定する
vpa.withStartAction(new Runnable() {
    @Override
    public void run() {
        // アニメーション開始時に呼び出されます。
        // アニメーション開始遅延時間が設定されている場合は、
        // アニメーション開始遅延時間後に呼び出されます。
        String layerTypeString = "";
        int layerType = button.getLayerType();
        switch (layerType) {
            case View.LAYER_TYPE_NONE:
                // withLayer() を呼び出さなかった時
                layerTypeString = "LAYER_TYPE_NONE";
                break;
            case View.LAYER_TYPE_SOFTWARE:
                // withLayer() を呼出した時、
                // ハードウェアアクセラレータが使用できない環境では、ソフトウェアレイヤを使用される
                layerTypeString = "LAYER_TYPE_SOFTWARE";
                break;
            case View.LAYER_TYPE_HARDWARE:
                // withLayer() を呼出した時、
                // ハードウェアアクセラレータが使用できる環境では、ハードウェアレイヤを使用される
                layerTypeString = "LAYER_TYPE_HARDWARE";
                break;
                
        }
        Log.v("ViewPropertyAnimatorSample",
                "withStartAction() using " + layerTypeString);
    }
});

// アニメーション終了時に実行する処理を設定する
vpa.withEndAction(new Runnable() {
    @Override
    public void run() {
        // アニメーション修了時に呼び出されます。
        Log.v("ViewPropertyAnimatorSample", "withEndAction()");
        button.setVisibility(View.GONE);
    }
});

// ビューに対してアニメーションを設定する(-> アニメーションが開始されます)
vpa.rotation(90);

 

[Android] TimeAnimator 使い方

| トラックバック(0) |

Nyandroid.png

Android 4.1(API Level 16)から android.animation パッケージに TimeAnimator クラスが追加されました。

このクラスを使用すると、アニメーションフレームの更新通知を受け取って処理をすることができます。

 

アニメーションフレームの更新通知を受け取って処理することは、従来の ValueAnimator などのクラスでも実現できましたが、

TimeAnimator クラスでは、アニメーションの継続期間や補完関数を使用しておらず、

単純に、アニメーション開始後の すべてのアニメーションフレームの更新時(※)に呼び出されます。

※最短では VSYNC に合わせて、16 ミリ秒間隔。

 

使い方

  1. TimeAnimator クラスをインスタンス化する
  2. setTimeListener() を呼び出して、TimeAnimator.TimeListener を設定する。
  3. start() を呼び出して、アニメーションを開始する。

 

サンプルソースコード

TimeAnimator timeAnimator = new TimeAnimator();
timeAnimator.setTimeListener(new TimeAnimator.TimeListener() {
    @Override
    public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
        // totalTime : アニメーション開始後の経過時間(ミリ秒)
        // deltaTime : 前回の onTimeUpdate 呼出し時からの差分(ミリ秒) ex.16ミリ秒

        // ここで必要な処理をする
    }
});
timeAnimator.start();

 

おまけ

TimeAnimator クラスは、正確に言えば、以前のバージョンでも hide としては存在していました。

Android 4.0 以降では、TimeAnimator クラスは、以下の記事で紹介した機能で使用されています。

 

参考(Nyandroid ソースコード)

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui;

import android.animation.AnimatorSet;
import android.animation.PropertyValuesHolder;
import android.animation.ObjectAnimator;
import android.animation.TimeAnimator;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import java.util.HashMap;
import java.util.Random;

public class Nyandroid extends Activity {
    final static boolean DEBUG = false;

    public static class Board extends FrameLayout
    {
        public static final boolean FIXED_STARS = true;
        public static final int NUM_CATS = 20;

        static Random sRNG = new Random();

        static float lerp(float a, float b, float f) {
            return (b-a)*f + a;
        }

        static float randfrange(float a, float b) {
            return lerp(a, b, sRNG.nextFloat());
        }

        static int randsign() {
            return sRNG.nextBoolean() ? 1 : -1;
        }

        static <E> E pick(E[] array) {
            if (array.length == 0) return null;
            return array[sRNG.nextInt(array.length)];
        }

        public class FlyingCat extends ImageView {
            public static final float VMAX = 1000.0f;
            public static final float VMIN = 100.0f;

            public float v, vr;

            public float dist;
            public float z;

            public ComponentName component;

            public FlyingCat(Context context, AttributeSet as) {
                super(context, as);
                setImageResource(R.drawable.nyandroid_anim); // @@@

                if (DEBUG) setBackgroundColor(0x80FF0000);
            }

            public String toString() {
                return String.format("<cat (%.1f, %.1f) (%d x %d)>",
                    getX(), getY(), getWidth(), getHeight());
            }

            public void reset() {
                final float scale = lerp(0.1f,2f,z);
                setScaleX(scale); setScaleY(scale);

                setX(-scale*getWidth()+1);
                setY(randfrange(0, Board.this.getHeight()-scale*getHeight()));
                v = lerp(VMIN, VMAX, z);

                dist = 0;

//                android.util.Log.d("Nyandroid", "reset cat: " + this);
            }

            public void update(float dt) {
                dist += v * dt;
                setX(getX() + v * dt);
            }
        }

        TimeAnimator mAnim;

        public Board(Context context, AttributeSet as) {
            super(context, as);

            setLayerType(View.LAYER_TYPE_HARDWARE, null);
            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
            setBackgroundColor(0xFF003366);
        }

        private void reset() {
//            android.util.Log.d("Nyandroid", "board reset");
            removeAllViews();

            final ViewGroup.LayoutParams wrap = new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.WRAP_CONTENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);

            if (FIXED_STARS) {
                for(int i=0; i<20; i++) {
                    ImageView fixedStar = new ImageView(getContext(), null);
                    if (DEBUG) fixedStar.setBackgroundColor(0x8000FF80);
                    fixedStar.setImageResource(R.drawable.star_anim); // @@@
                    addView(fixedStar, wrap);
                    final float scale = randfrange(0.1f, 1f);
                    fixedStar.setScaleX(scale); fixedStar.setScaleY(scale);
                    fixedStar.setX(randfrange(0, getWidth()));
                    fixedStar.setY(randfrange(0, getHeight()));
                    final AnimationDrawable anim = (AnimationDrawable) fixedStar.getDrawable();
                    postDelayed(new Runnable() { 
                        public void run() {
                            anim.start();
                        }}, (int) randfrange(0, 1000));
                }
            }

            for(int i=0; i<NUM_CATS; i++) {
                FlyingCat nv = new FlyingCat(getContext(), null);
                addView(nv, wrap);
                nv.z = ((float)i/NUM_CATS);
                nv.z *= nv.z;
                nv.reset();
                nv.setX(randfrange(0,Board.this.getWidth()));
                final AnimationDrawable anim = (AnimationDrawable) nv.getDrawable();
                postDelayed(new Runnable() { 
                    public void run() {
                        anim.start();
                    }}, (int) randfrange(0, 1000));
            }

            if (mAnim != null) {
                mAnim.cancel();
            }
            mAnim = new TimeAnimator();
            mAnim.setTimeListener(new TimeAnimator.TimeListener() {
                public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
                    // setRotation(totalTime * 0.01f); // not as cool as you would think
//                    android.util.Log.d("Nyandroid", "t=" + totalTime);

                    for (int i=0; i<getChildCount(); i++) {
                        View v = getChildAt(i);
                        if (!(v instanceof FlyingCat)) continue;
                        FlyingCat nv = (FlyingCat) v;
                        nv.update(deltaTime / 1000f);
                        final float catWidth = nv.getWidth() * nv.getScaleX();
                        final float catHeight = nv.getHeight() * nv.getScaleY();
                        if (   nv.getX() + catWidth < -2
                            || nv.getX() > getWidth() + 2
                            || nv.getY() + catHeight < -2
                            || nv.getY() > getHeight() + 2)
                        {
                            nv.reset();
                        }
                    }
                }
            });
        }

        @Override
        protected void onSizeChanged (int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w,h,oldw,oldh);
//            android.util.Log.d("Nyandroid", "resized: " + w + "x" + h);
            post(new Runnable() { public void run() { 
                reset();
                mAnim.start(); 
            } });
        }


        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            mAnim.cancel();
        }

        @Override
        public boolean isOpaque() {
            return true;
        }
    }

    private Board mBoard;

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

        getWindow().addFlags(
                  WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                );
    }

    @Override
    public void onResume() {
        super.onResume();
        mBoard = new Board(this, null);
        setContentView(mBoard);

        mBoard.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int vis) {
                if (0 == (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) {
                    Nyandroid.this.finish();
                }
            }
        });
    }

    @Override
    public void onUserInteraction() {
//        android.util.Log.d("Nyandroid", "finishing on user interaction");
        finish();
    }
}

Android SDK Tools, Revision 20 から、システムワイドなトレースツールである systrace が追加されました。

このツールを使うと、ユーザランドとカーネルの詳細なトレース結果を得ることができるので、パフォーマンス解析に役立ちます。

 

準備

  • PC に「Android SDK Tools, Revision 20」をインストールする。
  • PC に Python (実行環境)をインストールする。
  • Android 4.1 端末を PC と接続する。
  • 端末上の設定アプリで「開発者オプション」 > 「トレースを有効にする」 で任意の有効なトレースを選択する。

 

systrace の使い方

android-sdk/tools/systrace ディレクトリに移動し、systrace.py を実行する(※)。

※実行するには「python systrace.py」、または、実行権(x)を付加して「./systrace.py」

デフォルトでは 5 秒間トレースされますが、-t でトレース時間(単位は秒)を指定できます。

systrace1.png

 

実行結果

実行すると、trace.html ファイルが生成されるので、Chrome ブラウザ(※)で開きます。

※Firefox では正常に動作しませんでした

 

下図は、「API Demos」 > 「Graphics」 > 「OpenGL ES」 > 「Sprite Text」 を 1 秒間トレースした結果です。

trace.html ファイルは、HTML + Javascript で操作できるようになっていて、

色のついているエリアをダブルクリックすると、拡大できたり、範囲選択すると、下側に詳細な説明が表示されます。

VSYNC 美しいです!

VSYNC 美しいです!

trace.png

 

おまけ

systrace の出力結果には、trace-viewer という Chrome の Javascript ベースなトレースツールを使っているようです。

trace-viewer is the javascript frontend for Chrome's about:tracing UI, and can be used to visualize and analyze traces from various tracing libraries, including the linux kernel and Chrome's base/trace_event system.

また、systrace ツール自体は、python スクリプトで記述されていて、内部的には、adb shell から  atrace を実行しているようです。

 

あわせて読みたい

Android 4.1(Jelly Bean) から Activiy 起動アニメーションが簡単に指定できるようになりました。

 

Activity 起動アニメーション種類

  • スケールアップ(ScaleUpAnimation)
  • サムネイルスケールアップ(ThumbnailScaleUpAnimation)
  • カスタムアニメーション(CustomAnimation)

 

使い方

  1. ActivityOptions クラスの静的メソッド(makeXXX)を呼び出して同クラスをインスタンス化する。
  2. インスタンス化した ActivityOptions を、startActivity の引数に渡す。

 

以下、それぞれのアニメーションの解説です。

 

スケールアップ(ScaleUpAnimation)

画面上の指定された開始位置から、新しいアクティビティを拡大するアニメーション。

 

  • ソースコード
// アニメーションの基点となるビュー
Button view = (Button) findViewById(R.id.button);

// スケールアップ用 ActivityOptions をインスタンス化
ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(
    view,
    0, 0, view.getWidth(), view.getHeight());

// アニメーションを指定してアクティビティを起動
startActivity(
    new Intent(this, SecondActivity.class),
    opts.toBundle());

 

サムネイルスケールアップ(ThumbnailScaleUpAnimation)

指定したサムネイル(Bitmap)を指定した位置から、新しいアクティビティを拡大するアニメーション。

 

  • ソースコード
// アニメーションの基点となるビュー
Button view = (Button) findViewById(R.id.button);

// ここではサンプルとしてスケールアップするアニメーションの画像に
// ボタンの画像(Bitmap)を使用していますが、任意の画像を使用することができます。
view.setDrawingCacheEnabled(true); // 後で元に戻すこと
view.setPressed(false);
view.refreshDrawableState();
Bitmap bitmap = view.getDrawingCache();

// サムネイルスケールアップ用 ActivityOptions をインスタンス化
ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
    view,
    bitmap, 0, 0);

// アニメーションを指定してアクティビティを起動
startActivity(
    new Intent(this, SecondActivity.class),
    opts.toBundle());

view.setDrawingCacheEnabled(false);

 

カスタムアニメーション(CustomAnimation)

カスタムアニメーション(リソース)を指定して、新しいアクティビティを拡大するアニメーション。

 

  • ソースコード
// カスタムアニメーション用 ActivityOptions をインスタンス化
ActivityOptions opts = ActivityOptions.makeCustomAnimation(
    MainActivity.this,
    R.anim.zoom_enter, R.anim.zoom_exit);

// アニメーションを指定してアクティビティを起動
startActivity(
    new Intent(this, SecondActivity.class),
    opts.toBundle());

 

  • カスタムアニメーションリソース(サンプル)・・・R.anim.zoom_enter
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/decelerate_interpolator" >
    <scale
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromXScale="2.0"
        android:fromYScale="2.0"
        android:pivotX="50%p"
        android:pivotY="50%p"
        android:toXScale="1.0"
        android:toYScale="1.0" />
</set>

 

  • カスタムアニメーションリソース(サンプル)・・・R.anim.zoom_exit
    • <set xmlns:android="http://schemas.android.com/apk/res/android"
          android:interpolator="@android:anim/decelerate_interpolator"
          android:zAdjustment="top" >
          <scale
              android:duration="@android:integer/config_mediumAnimTime"
              android:fromXScale="1.0"
              android:fromYScale="1.0"
              android:pivotX="50%p"
              android:pivotY="50%p"
              android:toXScale=".5"
              android:toYScale=".5" />
          <alpha
              android:duration="@android:integer/config_mediumAnimTime"
              android:fromAlpha="1.0"
              android:toAlpha="0" />
      </set>
      

       

      あわせて読みたい

      Android 4.1(Jelly Bean) から新しく 3 つのスタイルが使用できるようになりました。

      • BigTextStyle
      • BigPictureStyle
      • InboxStyle

      また、通知領域に簡単にボタンを追加できるようにもなっています。

       

      以下、それぞれの画面キャプチャとソースコードです。

      画面キャプチャと、ソースコード中の文字列を比較しながら見ると、わかりやすいと思います^^

       

      Notification.BigTextStyle

      BigTextStyle は「テキスト(Summary Text)」と「小さいアイコン」を表示できます。

       

      • 画面キャプチャ

      Notification.BigTextStyle.png

      •  ソースコード
      // NotificationManager
      NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
      
      // Small and large icon
      int smallIconId = R.drawable.ic_action_search;
      Bitmap largeIconBitmap = BitmapFactory.decodeResource(
          getResources(), R.drawable.ic_launcher);
      
      //-----------------------------------------------------------------------
      // BigTextStyle
      //-----------------------------------------------------------------------
      Notification notificationBigTextStyle = new Notification.BigTextStyle(
          new Notification.Builder(this)
              .setContentTitle("ContentTitle")
              .setSmallIcon(smallIconId)
              .setLargeIcon(largeIconBitmap))
          .bigText("BigText")
      //  .setBigContentTitle("BigContentTitle") // Notification.Builder#setContentTitle() を上書き
          .setSummaryText("SummaryText")
          .build();
      nm.notify(0, notificationBigTextStyle);
      

       

      Notification.BigPictureStyle

      BigPictureStyle は「大きな画像(Big Picture)」を表示できます。

       

      • 画面キャプチャ

      Notification.BigPictureStyle.png

      •  ソースコード
      //-----------------------------------------------------------------------
      // BigPictureStyle
      //-----------------------------------------------------------------------
      Notification notificationBigPictureStyle = new Notification.BigPictureStyle(
          new Notification.Builder(this)
              .setContentTitle("ContentTitle")
              .setSmallIcon(smallIconId)
              .setLargeIcon(largeIconBitmap))
      //  .bigLargeIcon(largeIconBitmap) // Notification.Builder#setLargeIcon() を上書き
          .bigPicture(largeIconBitmap)
      //  .setBigContentTitle("BigContentTitle") // Notification.Builder#setContentTitle() を上書き
          .setSummaryText("SummaryText")
          .build();
      nm.notify(1, notificationBigPictureStyle);

       

      Notification.InboxStyle

      InboxStyle は、複数行の「テキスト(Line)」、「テキスト(Summary Text)」と「小さいアイコン」を表示できます。

      ※8 行目以降は、"..."表示されます

       

      • 画面キャプチャ

      Notification.InboxStyle.png

      •  ソースコード
      //-----------------------------------------------------------------------
      // InboxStyle
      //-----------------------------------------------------------------------
      Notification notificationInboxStyle = new Notification.InboxStyle(
          new Notification.Builder(this)
              .setContentTitle("ContentTitle")
              .setSmallIcon(smallIconId)
              .setLargeIcon(largeIconBitmap))
          .addLine("addLine(1)")
          .addLine("addLine(2)")
          .addLine("addLine(3)")
          .addLine("addLine(4)")
          .addLine("addLine(5)")
          .addLine("addLine(6)")
          .addLine("addLine(7)")
          .addLine("addLine(8)") // 8行目以降は"..."で表示される
      //  .setBigContentTitle("BigContentTitle") // Notification.Builder#setContentTitle()  を上書き
          .setSummaryText("SummaryText")
          .build();
      nm.notify(2, notificationInboxStyle);

       

      ボタンを追加する

      Notification 作成時、Notification.Builder#addAction() を呼び出すと、ボタンを追加することができます。

      ※最大3つまで追加できます

      ※ボタン押下時のアクションは、PendingIntent で指定します

       

      • 画面キャプチャ

      NotificationWithButtons.png

       

      • ソースコード
      // PendingIntent
      PendingIntent pendingIntent = PendingIntent.getActivity(this,
          0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
      
      //-----------------------------------------------------------------------
      // BigTextStyle + Button
      //-----------------------------------------------------------------------
      Notification notificationBigTextStyle = new Notification.BigTextStyle(
          new Notification.Builder(this)
              .setContentTitle("ContentTitle")
              .setSmallIcon(smallIconId)
              .setLargeIcon(largeIconBitmap)
              .addAction(android.R.drawable.ic_input_add, "Add", pendingIntent)
              .addAction(android.R.drawable.ic_input_delete, "Delete", pendingIntent))
          .bigText("BigText")
      //  .setBigContentTitle("BigContentTitle") // Notification.Builder#setContentTitle() を上書き
          .setSummaryText("SummaryText")
          .build();
      nm.notify(4, notificationBigTextStyle);
      

      Google 公式サイト

       

      Google I/O 2012 基調講演(Keynote)

       

      Android 4.1 一般向け

       

      Android 4.1 開発者向け

       

      Nexus 7

       

      Nexus Q

       

      Google Glass

       

      Google Play

       

      Google Compute Engine

       

      Google Drive

       

      Google Docs

       

      Chrome

       

      ChromeBox

       

      ※しばらく(DevFestXまで)は、メンテしようと思います^^

      @shin1ogawa さんの提案で、docs に移行しました。

      →→ Google I/O 2012 リンクメモ - Google ドキュメント

      @shino_merry さん の作品の「いんふぉばたん」の素材を頂いて JCROM テーマをつくりました。

      ※テーマは(本記事の下の方のリンクから)ダウンロードできます

       

      壁紙

      infobar_wallpaper.png

      壁紙はカワイイ顔のどあっぷ。

      ナビキーは手を抜いて機能を表すアイコンを描かなかったので上級者向けです。。。

      ※左から 【Back】 【Menu】 【Home】 【Toggle Status Bar】 【Recents Panel】

       

      ロック画面

      infobar_lockscreen.png

      お腹を撫でるとロック解除ー。

       

      通知トラッキングビュー&通知バー

      infobar_statusbar.png

      Notification は、タップすると光ります。

      通常は読みやすやを優先して暗めの画像にしています。

       

      Launcher の背景

      infobar_launcher.png

      よくみると、背景画像に「いんふぉばたん」が隠れています。

      アプリの読みやすを優先して画像を暗めにしています。

       

      RecentsPanel

      infobar_frame.png

      思わず何度も押してしまう RecentsPanel 。

       

      テーマダウンロード

      http://www.adakoda.com/adakoda/2012/06/25/mytheme.zip ・・・約1MB

       

       

      JCROM 公式サイト

      https://sites.google.com/site/jcromproject/

       

      テーマは、以下のページを参考に決められたファイル名とサイズで作り、

      SD カードに置くだけで自分好みのテーマを使用できます。

      https://sites.google.com/site/jcromproject/home/creating_themes

       

      お絵かきできる人には、是非テーマを作っていただきたいです。

      2012年6月16日(土)午前9時~翌午前1時に NHK-FM で アニソン三昧 があるそうです!

       

      今日は一日○○三昧(まるまるざんまい)

      http://www9.nhk.or.jp/zanmai/program/120616.html

      • 第1部 9:00~11:50
      • 第2部 12:15~18:50
      • 第3部 19:20~25:00

       

      Android 端末でも NHK-FM を聞ける「NHKネットラジオ らじる★らじる 」というアプリがあるので、

      ぜひインストール&予約し、当日アニソン三昧しましょう♪

       

      NHKネットラジオ らじる★らじる - Google Play の Android アプリ

      https://play.google.com/store/apps/details?id=jp.nhk.netradio

      netradio1.png netradio2.png

       

      ※2012/6/16追記

      ・途切れ途切れの再生にならないようにデフォルトでバッファリングが1分に設定されています。
      遅延が気になる方は30秒に変更した方が良いでしょう。

      ・PC 版はこちら → http://www.nhk.or.jp/fm/

       

      過去のアニソン三昧

      • 2006年「今日は一日"アニソン"三昧」
      • 2007年「今日は一日 アニソン三昧SS(セカンド・ステージ)」
      • 2008年「今日は一日 アニソン三昧ファイナル」
      • 2010年「今日は一日 帰ってきたアニソン三昧」

       

      あわせて読みたい

      Windows Phone 7.5 で、WebClient を使用してXMLを読み込み表示するサンプルを探していたら、

      以下の Microsoft の公式ページにありました。

       

      ということで、実際にソースコードを作成して試してみました。

      wp75_twitter.png wp75_twitter_menu.png

       

      以下、ソースコードの解説です。

      ※オリジナルのソースコードに書かれていないコメントなどを追記しています

       

      ソースコード解説

      アプリケーションを起動すると、MainPage のコンストラクタが呼び出されます。

      ※MainPage はウィザードで自動的に作成される PhoneApplicationPage クラスのサブクラス

      コンストラクタでは、独自に定義した GetTweets メソッドを呼び出し、指定したユーザの TL を表示しています。

      // コンストラクタ
      public MainPage()
      {
          InitializeComponent();
          // 指定したユーザーのタイムラインを表示する
          GetTweets(TwitterId);
      }
      

       

      コンストラクタから呼び出された GetTweets メソッドでは、

      指定された文字列を検索するための Twitter API の URI 文字列を作成し、

      WebClient クラスを使用して非同期読み込みを開始しています。

      // 指定したユーザのタイムラインを取得して表示する
      private void GetTweets(string strId)
      {
          // Twitterで検索する文字列を作成
          String queryString = HttpUtility.UrlEncode(strId); // URLで使用できる文字列に変換
      
          // TwitterAPIのURIを作成
          String uriString = "http://search.twitter.com/search.atom?q=" + queryString;
      
          // Uriインスタンス生成
          Uri u = new Uri(uriString);
      
          WebClient cli = new WebClient();
          // ダウンロード完了後に呼び出されるイベントハンドラを設定
          cli.DownloadStringCompleted += new DownloadStringCompletedEventHandler(cli_DownloadStringCompleted);
      
          // 指定したURIを非同期でダウンロード
          cli.DownloadStringAsync(u);
      }
      

       

      非同期読み込みが完了すると、DownloadStringCompleted に設定したイベントハンドラが呼び出されます。

      ダウンロードしたデータ(文字列)から XML のインスタンスを生成し、データコンテキストに設定しています。

      // 通信を実行し、結果を画面に表示する
      void cli_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
      {
          if (e.Error == null)
          {
              // 指定したURIから読み込んだ文字列を取得
              String stringResult = e.Result;
      
              // 指定した文字列から StringReader(StringReader は TextReader のサブクラス)
              StringReader sr = new StringReader(stringResult);
      
              // 指定した TextReader を使用して、新しい XmlReader インスタンスを作成する
              XmlReader xr = XmlReader.Create(sr);
      
              // 指定した XmlReader から配信フィードを読み込む
              SyndicationFeed sf = SyndicationFeed.Load(xr);
              
              // 読み込んだ配信フィードをデータコンテキストに設定
              this.DataContext = sf;
          } else
          {
              MessageBox.Show("通信エラーが発生しました。\r\n" + e.Error.Message);
          }
      }
      

       

      データコンテキストにデータを設定すると、データバインディングにより自動的に、

      XAML に定義していたオブジェクトのプロパティに値が設定、再描画されます。

      この例では Twitter API で取得した以下のデータをデータバンディングさせています。

        • Links[1].Uri ・・・ツイートしたアカウントのプロフィール画像のURI
        • Authors[0].Name ・・・ツイートしたアカウントの名前
        • Title.Text ・・・ツイート本文

      ※Twitter API - GET search の仕様は GET search | Twitter Developers にあります。

      <phone:PhoneApplicationPage.Resources>
          <DataTemplate x:Key="SyndicationItemTemplate">
              <StackPanel Orientation="Horizontal" Width="460">
                  <Image Height="91" Width="91" Source="{Binding Links[1].Uri}" Margin="4"/>
                  <StackPanel Orientation="Vertical" Width="350">
                      <TextBlock Text="{Binding Authors[0].Name}" FontWeight="Bold" >
                      <TextBlock.Foreground>
                          <SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
                      </TextBlock.Foreground>
                      </TextBlock>
                      <TextBlock TextWrapping="Wrap" Text="{Binding Title.Text}" />
                  </StackPanel>
              </StackPanel>
          </DataTemplate>
      </phone:PhoneApplicationPage.Resources>
      

       

      このサンプルで使用されている主なクラスのドキュメントへのリンク

      Windows Phone Emulator が起動しない場合の対処法

      Windows Phone Emulator(エミュレーター)起動時、

      error.png

      別の Virtual Machine Manager を実行中です。他の Virtual Machine Manager
      を終了し、しばらく待機してから、エミュレーターを再起動してください

      のようなアラートが表示されて、エミュレーターが起動しない場合の対処法。

       

      私の環境では、別途インストールしていた

      uninstall.png

      Intel® Hardware Accelerated Execution Manager

       

      をアンインストールすると、無事、エミュレーターを起動することができました。

      ※Windows Phone SDK 7.1.1 で確認

       

      ちなみに、この 「Intel® Hardware Accelerated Execution Manager」 は、

      Android SDK Tools, Revision 17 で追加された Android Emulator の高速化のためのものです。。。

      <<前のページへ 1234567891011

      2016年8月

        1 2 3 4 5 6
      7 8 9 10 11 12 13
      14 15 16 17 18 19 20
      21 22 23 24 25 26 27
      28 29 30 31