My Note Pad

エンジニアリングや日々の雑感を書いていきます

たった数日でFire TV Stickを箱に戻した

先日、AmazonのセールでFire TV Stickを購入しました。

yuki10.hatenablog.com

購入した主な理由はプライムビデオを大画面のTVで見たい
見るものがなくなったらいずれはNetflixあたりも。。

という感じです。

が、「本日、ネットでPS4でプライムビデオを見ることができる」ということを知りました。。。

www.amazon.co.jp

また、最近のテレビでは最初から対応しているようです。

というわけで、早速帰宅してからPS4で試してみました。
アプリをダウンロードしてAmazonアカウントでログインすると何事もなくプライムビデオを視聴することができました。

PS4はスペックもFire TV Stickよりはるかに良いので、サクサクです。
さらにコントローラーも持ち慣れている上にスタンバイモードからの起動も一瞬です。

というわけで、今後はPS4でプライムビデオを見ることにしました。

Fire TV Stickは、、帰省したときにでも実家に置いてこようと思います。

Fire TV Stick購入!

Fire TV Stickを購入しました。

http://www.amazon.co.jp/Amazon-W87CUN-Fire-TV-Stick/dp/B00ZVNYLS8

以前はChrome Castを使用していました。

Chrome CastからFire TV Stickに切り替えた理由としては以下の通りです。

  • Fire TV Stickがセールで安くなっていた
  • Chrome CastはAmazon Prime Video非対応
  • Fire TV Stickはリモコン付き
    • スマホからキャストするのが面倒くさい
    • スマホはNexus 5Xを使っているため、そこまで面倒ではないのですが・・
  • YouTubeはあまり見ない

Prime会員なので、オーダーした翌日には到着しました。
パッケージはこんな感じです。

f:id:yuki10k:20160607231455j:plain

外のパッケージを外すと意外に地味なパッケージ

f:id:yuki10k:20160607231523j:plain

蓋を開けると、リモコンとFire TV Stick本体。
音声入力機能は特に必要なかったので通常のリモコン版です。

f:id:yuki10k:20160607231541j:plain

さらにその下には、

  • 説明書
  • 電源アダプタ
  • USBケーブル
  • 電池
  • HDMI延長ケーブル(USBケーブルの下に入っています)

が入っていました。
電池が入っているのは親切です。

f:id:yuki10k:20160607231554j:plain

安っぽさが無いのは好印象でした。

実際にテレビに接続してWi-Fiのセットアップまですると、自分のAmazonアカウントと紐付けされていました。
Fireタブレットもそうですが、一体どうやっているんだろう・・
オーダー時にシリアルIDか何かと紐付けているんでしょうか・・

ともあれ特に難しい設定もなく、40インチのテレビでPrime Videoを見ることができるようになりました。
画面が大きいと画像が荒くなるかなと懸念していましたが、通信回線が安定していればそんなこともなくキレイな映像が楽しめます。

Prime Videoは作品が少ないと言われていますが、見たい作品は沢山あるので自分としては満足です。
そのうち、見たいものがなくなってきたらNetflixあたりを検討するかもしれません。
それもFire TV Stickがあれば楽しめるので気兼ねなく利用できそうです。

とりあえず、弱虫ペダルを全部観ようと思います。

Android学習(DI・DB編)

前回↓に引き続き、mixiのAndroidTrainingで時間を見つけてはAndroid開発について学んでいます。

yuki10.hatenablog.com

yuki10.hatenablog.com

今回は、2.基礎編 10.データベースの項です。

mixi-inc.github.io

RDBは仕事でも使うので、取っ付きやすい章でした。
せっかくなので、SQLiteOpenHelperではなくORMを利用してみることにしました。

Android用のORMは色々なライブラリが公開されていましたが、今回はAndroid Ormaを利用してみました!

GitHub - gfx/Android-Orma: A lightning-fast ORM for Android as a wrapper of SQLiteDatabase

また、作者の方が公開しているチュートリアルを参考にさせていただきました。

gfx.hatenablog.com

その中で、OrmaDatabaseクラスのインスタンスをDIで@Singletonをおすすめとの記述があったので、合わせてDagger2にも挑戦してみることにしました。
Dagger2については、こちらの記事を参考にさせていただきました。

Dagger2 導入Step By Step - Qiita

依存ライブラリ等の定義

プロジェクト直下のbuild.gradle

  • repositoryにmavenCentralを追加
  • dependenciesにaptの定義を設定
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }

続いてプロジェクト/app下のbuild.gradleの依存関係に

  • Dagger2の定義を追加
  • Ormaの定義を追加

以下のような順に追記しました。

dependencies {
    ・・・
    compile 'com.google.dagger:dagger:2.0.2'
    apt 'com.google.dagger:dagger-compiler:2.0.2'
    provided 'javax.annotation:jsr250-api:1.0'

    apt 'com.github.gfx.android.orma:orma-processor:2.4.7'
    compile 'com.github.gfx.android.orma:orma:2.4.7'
}

Moduleクラスの作成

import部分等は省略していますが、こんな感じで作ってみました。
OrmaDatabaseもここで@Singletonで定義しています。

@Module
public class ApplicationModule {

    private final Application application;

    public ApplicationModule(Application application) {
        this.application = application;
    }

    @Provides
    @Singleton
    Context provideApplicationContext() {
        return application.getApplicationContext();
    }

    @Singleton
    @Provides
    public OrmaDatabase provideOrmaDataBase(Context context) {
        return OrmaDatabase.builder(context).build();
    }
}

ComponentInterfaceの作成

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    void inject(MainActivity mainActivity);
}

Applicationクラスの作成

public class MainApplication extends Application {

    private ApplicationComponent applicationComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        initializeInjector();
    }

    private void initializeInjector() {
        applicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .build();
    }

    public ApplicationComponent getApplicationComponent() {
        return applicationComponent;
    }
}

AndroidManifest.xmlにも忘れずに定義します。

    <application
        android:name=".MainApplication" ・・・>
        ・・・
    </application>

実際にDIしてみる

以下の様な感じでApplicationComponentを取得してinjectメソッドを実行することで、@Injectと定義しているormaにDIすることができました。

public class MainActivity extends AppCompatActivity {

    @Inject
    OrmaDatabase orma;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getApplicationComponent().inject(this);
    }

    private ApplicationComponent getApplicationComponent() {
        return ((MainApplication) getApplication()).getApplicationComponent();
    }
}

Ormaを利用してDBを扱う

テーブルは課題に合わせて以下の様な感じで作りました。
アノテーションで属性等を定義できるので分かりやすいです。

@Table
public class AndroidCodeName {

    @PrimaryKey(autoincrement = true)
    public long id;

    @Column(indexed = true)
    public String name;

    @Column
    @Nullable
    public String version;

    public static AndroidCodeName_Relation relation(OrmaDatabase orma) {
        return orma.relationOfAndroidCodeName().orderByIdDesc();
    }
}

今回はinsertとselectだけ載せておきます。

insertはこんな感じ。

    private void insert() {
        AndroidCodeName androidCodeName = new AndroidCodeName();
        androidCodeName.name = appNameEditText.getText().toString();
        androidCodeName.version = appVersionEditText.getText().toString();

        orma.insertIntoAndroidCodeName(androidCodeName);

        Toast.makeText(MainActivity.this, "insert success", Toast.LENGTH_SHORT).show();
    }

さらにselect

    private void select() {

        AndroidCodeName_Relation relation = AndroidCodeName.relation(orma);

        // Relationを利用してデータを取得
        Log.d(TAG, "from Relation");
        for (AndroidCodeName androidCodeName :relation) {
            Log.d(TAG, androidCodeName.name + ":" + androidCodeName.version);
        }


        // Helper経由でデータを取得
        Log.d(TAG, "from Helper");
        AndroidCodeName_Selector selector = orma.selectFromAndroidCodeName()
                .orderByIdAsc();

        for (AndroidCodeName androidCodeName : selector) {
            Log.d(TAG, androidCodeName.name + ":" + androidCodeName.version);
        }
    }

今回はDaggerでOrmaDatabaseをDIする所を中心に挑戦してみましたが、OrmaがRxJava用のインターフェースを備えているようなので、RxJavaを絡めて学んでみたいなと思います。
※RxJavaも触ったことがありません。。

Android開発者は今から始めると学ぶことが多いですね。。

スターオーシャン5購入

発売から2ヶ月以上経過していますが、ようやくスターオーシャン5を購入しました。

スターオーシャン5 -Integrity and Faithlessness- | SQUARE ENIX

というのも、Amazonでの評価があまり良くなかったので見送っていました・・

購入したときにはAmazon限定版で3300円程だったので、思い切って購入しました。
(今は少し値上がりしているみたいですが。。、限定版じゃなければ3000円以下で買えるようです。

数時間遊んでみたのでその感想を。

カメラワーク

まずはカメラワークが酷いというレビューが多かったので自分も気になっていたのですが、確かに上下に揺れて酔いそうになる感じ・・
これは辛いなーと思い設定を見ていると、「カメラの上下の感度」が設定できるようになっていたので低めに設定すると大きく改善し、快適にプレイできるようになりました。

イベントスキップできない

これが地味に効いて来ます。
普段はまぁ、別にいいかという感じなのですが、ボスバトル前にイベントが入る事が多く、ボスで全滅して再度挑戦するときにスキップできないのが辛いです。
それでいて町中のmobの会話は表示されても一瞬で消えてしまうので何言ってるか分からない。。

ストーリー

レビューでも書かれていますが、短いという印象。
まだクリアしていませんが、攻略サイトでどのあたりかな〜と確認して見たところ、そろそろ中盤あたりでした。
(街とフィールドが少し登場したくらい・・)
とはいえ、内容は嫌いではないです。
ベタなパターンが多い気はしますが。

バトル

プレイ前はシームレスバトルと聞いてもあまりピンとこなかったのですが、これはアリだと思います。
(ダークソウル3プレイした後だからかも・・?)
敵味方が入り乱れる攻城戦なんかでは、敵の部隊を倒す -> 近くの戦闘に介入といった流れが非常にスムーズで楽しめました。
また、パーティーメンバーに控えという概念がなく、全員で戦闘というのも迫力があっていい感じです。
味方のメンバーが多いので、難易度調整のために敵の攻撃力が高めに設定されている印象が高いですが。。
また、3竦み?がうまく機能しているのか・・?と疑問に。
そもそもパーティーメンバーが多く、バトルエフェクトも派手なので狙ってやるのはなかなか難しいのですが、それでもこちらの小攻撃で相手の大攻撃をキャンセルできないことが多い気がします。
ガードも簡単に破られるし・・



とりあえず、まだクリアしていないのでこんな所で・・。
個人的には☆3.5くらいで、そこまで悪くはないなという印象です。
定価で買っていたらちょっと・・・となっていたかもしれないですが。。

とりあえず、クリアまではプレイしようと思います。
やりこみはその時の満足度次第ということで・・!

Androidで嵌った所(HTTP request編)

仕事が忙しくてなかなか進まないのですが、空いた時間を見つけてはmixiAndroidトレーニングを進めています。

現在は2.基礎編 9.ネットワーク通信のセクションです。
実習1の

  1. 画面のEditTextに入力されているURLを取得して、
  2. そのURLにGETリクエストを送り、
  3. レスポンスを画面のTextViewに表示する

だけの簡単なお仕事です(のはずでした)。

まずはAndroidManifest.xmlに、ネットワークのパーミッションを定義

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

今回は折角なのでOkHttpを使ってみました。

github.com

まずはbuild.gradleにOkHttpの依存関係を追加します。

dependencies {
    ~
    compile 'com.squareup.okhttp3:okhttp:3.2.0'
}

続いて通信処理を書いていきます。
MainActivity#onCreateに書いてみたところ、NetworkOnMainThreadExceptionが発生してしまいました。
メインスレッドからネットワーク処理ができないようです。。

こちらの記事を参考にさせていただきました。

shirusu-ni-tarazu.hatenablog.jp

今回関係なさそうな所は省略していますが、以下のような感じになりました。

MainActivity.java

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // GetButton
        View buttonGet = findViewById(R.id.buttonGet);
        buttonGet.setOnClickListener(getButtonOnClickListener);
    }

    private View.OnClickListener getButtonOnClickListener = new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            // EditTextからURLを取得
            EditText accessUrlText = (EditText) findViewById(R.id.accessUrl);
            final String accessUrl = accessUrlText.getText().toString();

            // Builderにセット
            Uri.Builder builder = new Uri.Builder();
            builder.path(accessUrl);

            // 別スレッドでリクエストを実行
            AsyncHttpRequest task = new AsyncHttpRequest(MainActivity.this);
            task.execute(builder);
        }
    };

AsyncHttpRequest.java

    private Activity mainActivity;

    public AsyncHttpRequest(Activity mainActivity) {
        // 呼び出し元のアクティビティ
        this.mainActivity = mainActivity;
    }

    // 非同期で呼ばれる処理
    @Override
    protected String doInBackground(Uri.Builder... builders) {

        Uri.Builder builder = builders[0];

        try {
            URL url = new URL(builder.build().getPath());
            Request request = new Request.Builder()
                    .url(url)
                    .build();

            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            return response.body().string();

        // 例外処理は今回適当
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 非同期処理の後に呼ばれる処理
    // doInBackgroundのreturn値が引数で渡されます。
    @Override
    protected void onPostExecute(String result) {
        TextView responseText = (TextView) mainActivity.findViewById(R.id.responce);
        responseText.setText(result);
    }

嵌った所は以下のとおり

  • OnClickListener内でAsyncHttpRequestのコンストラクタにActivityをどうやって渡せば。。
    • new AsyncHttpRequest(MainActivity.this);でいけました。
  • Builderにpathをセットする際に、builder.addPath(url)でセットすると先頭に/がついてしましまう。
    • builder.path(url)でいけました。
  • request投げているのにresponseが帰ってこない
    • Genymotionを使っているのですが、MacをスリープしたりWi-Fiが切れたりすると駄目っぽい・・?
    • Genymotion再起動でうまく動きました。

Android開発のFragmentで嵌った

GW前に前々から読みたいと思ってAmazonの欲しいものリストに入れていたCode CompleteのKindle版が上下巻とも半額だったので衝動買いし、GW中は、Code Completeを読んでいました。

ec.nikkeibp.co.jp

ec.nikkeibp.co.jp

書評は既に多くの方が書いているので割愛。

今回はCode Completeを読み終えたので、過去に途中で辞めてしまった、Androidアプリ開発に再度挑戦してみました。
AndroidSwiftで開発できるようになるといった噂も出たりしていますが、果たしてどうなるのか。。

参考資料

今回はmixiさんが公開している、AndroidTrainingを利用させていただき、学習を進めています。

mixi-inc.github.io

※昔、別の入門書をやったことがありますが、結局作りたいアプリのイメージが沸かずに途中で止めてしまったため、あまり覚えていません・・

今回はトレーニング完了までに作りたいアプリのイメージを固めねば。。

1. アプリのレイアウト作成

このセクションは大きく嵌まる事もなく終了。
以下のレイアウトについて学べました。

  • LinerLayout
  • RelativeLayout
  • FrameLayout
  • ScrollView

Android Support Library 23.0からPercentRelativeLayoutPercentFrameLayoutというものが登場しているようなので、こちらも別途学習する必要がありそう。
また、マテリアルデザインについても別途学習が必要な気がします。

2.ActivityとFragment

ここの実習で結構ハマりました。
新しいActivityの実装は特に問題なく終了

新しいFragmentの実装部分で特に実習には書かれていなかったのですが、Bundle経由でパラメータを渡して表示してみようと思い、実装してみました。

↓最初の状態がこちら

public class Main3Fragment extends Fragment {

    public Main3Fragment() {
        // Required empty public constructor
    }

    public static Fragment createInstance(int hoge) {
        Fragment fragment = new Main3Fragment();

        Bundle args = new Bundle();
        args.putInt("hoge", hoge);
        fragment.setArguments(args);
        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_main3, container, false);
        TextView hogeText = (TextView) view.findViewById(R.id.hoge);
        hogeText.setText(savedInstanceState.getInt("hoge"));

        return view;
    }
}

onCreateViewメソッドに渡される引数のsavedInstanceStateBundle型なので、createInstanceメソッドで設定したhogeというパラメータがsavedInstanceStateから取得できるのかと思いきや、nullとなってしまいました。
色々調べた結果、以下のようにgetArgumentsBundlerを取得するように書き換えることでうまくいきました。

    // onCreateViewメソッドだけ抜粋
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_main3, container, false);

        Bundle arguments = getArguments();
        TextView hogeText = (TextView) view.findViewById(R.id.hoge);
        int hoge = arguments.getInt("hoge");
        hogeText.setText(String.valueOf(hoge));

        return view;
    }

※呼び出し元のActivityはこんな感じ

public class Main3Activity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);

        if (savedInstanceState == null) {

            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction transaction = fragmentManager.beginTransaction();

            // ここでMain3Fragmentのインスタンス生成とreplace
            transaction.replace(R.id.Main3FragmentContainer, Main3Fragment.createInstance(999));
            transaction.addToBackStack("main3FragmentContainerReplace");

            transaction.commit();
        }
    }
}

他にもonCreateViewではなくonCreateに実装してしまっていたりと・・色々ありましたが、今回はこんな感じです。

実習・課題形式なので、実際に入門書をそのまま写経するよりも身についているという実感があるのがいい感じです。

念願のPS4を手に入れた・・!

↓のような記事を書いてからだいぶ時間が空いてしまいましたが、

yuki10.hatenablog.com

よくやくPS4を購入しました!
(といっても少し前なのですが。。)

平日は仕事が忙しくて殆どプレイできず、土日も休日出勤だったり仕事の反動で寝てしまっていたり。。といった具合で、あまり遊べませんでした。

↓一緒に買ったソフトはこちら

www.darksouls.jp

色々悩みましたが、発売してあまり日が経っていないというのと、amazonでの評価で選びました。
ソウルシリーズやってみたかったし。

このGWで集中して一気にプレイしました。
忙しくてPS Plusに入るのに躊躇していたので、基本的にオフラインで進めました。

感想としては

  • 他のRPGでは味わえない難易度
    • ボスだけでなく道中で何度死んだことか・・
    • 時にイライラしますが、攻略できたときの達成感があります
  • ダークソウル3から始めるとストーリーに入り込めず置いてきぼりに
    • 「灰の人って何だ・・」という感じ
  • 装備の変更方法なんかも基本的にはチュートリアルがなかった(気がする)ので最初、操作を覚えるのが大変
    • ステータスの見方や弓の使い方が最後の方まで分からなかった

死んでも「もう1回」という感じで何時間もぶっ通しでゲームをしたのは久しぶりです。
ここまでハマれるゲームはなかなか無い・・!

ボスの攻略に関しては、YouTubeの色々な動画を参考にしました。
攻略動画見なかったら未だにクリアできなかったんじゃないだろうか。。

クリア時の状態はこんな感じです ラスボス用に、弓とかは外して重量70%を超えないようギリギリの装備で挑みました。(羽騎士シリーズとかだったかも)

  • プレイ時間 42時間
  • レベル 100
  • ダークソード + 10
  • 竜紋章の盾 + 2

キャラや武器のレベルを上げ過ぎるとマッチングしにくくなるらしいのですが、今回はオフラインモードでやってたのでそこはあまり気にせず。

あと、ウイイレ2016がプライスダウンして発売していたので、こちらも衝動買い。
時間のあるときにやりたいと思います。

www.konami.jp

今回、PS4を購入したことで新作が出ても購入のハードルが大きく下がりました。
FF15、PSVRの準備万端!