Translate

BTemplates.com

Powered by Blogger.

2017年9月28日木曜日

2017-09-27 到達点メモ


ローカライズを英語名で検索する場合は
ローカライズの設定を英語にした状態で調べないと
正しく出ない。
日本語だとまた違うのかもしれないが、試していないのでちょっとわからない。
言語名を覚えていなくて恐縮なのだが
日本語、英語、中国語以外の言語設定で
検索した場合は、少なくとも駄目だった。

現状、キャプチャーを取りつつ
レイアウトの確認をしている処であるが、
ローカライズすると日本語より文字が多くなり
想定していないところで改行し、レイアウトが崩れてしまう。

割と多かったのが、初期化を外国語に翻訳すると
文字数が多くて改行することがそれなりにあった。
大抵は、リセットに置き換えると何とかなったのだが
スペイン語ではどうにもならなかった

例:
リセット  --> Restablecer
0にする   --> Establecer a 0
元に戻す  --> Restaurar
初期化     --> Inicialización
初めから  --> Desde el principio

で、思いついたのが一つあってしょうがないので下のやつで通すことにした。
00m00s
デザイン的にきれいではないけど、何となく意味が通じると信じたい。

タブレットのキャプチャーを取ろうと思ったら
一部、文字がString型に置き換わっていないのを発見した。
泣きたい。

明日作業に取り掛かるという事で
今日はここまで。


2017年9月27日水曜日

2017-09-26 到達点メモ


昨日設定したローカライズの動作確認をしていた。
見た感じ問題はなさそうだが、ローカライズのテストが面倒だった
現状、ローカライズはエミュレーターでテストをしているのですが
英語しか入力ができない且つパッと見て国名がわかりにくい
*後で調べたら普通に日本語にできる方法があった。

具体的にはGoogle翻訳だとドイツ語はGermanになるけど
Deutschlandで検索しないと出てこない。
後、表示されるのが、ドイツ語ならドイツ語で表示されるので
ロシアとかがРоссияという風な感じで表示されるので本当に地味にわかりにくい。

日本語に翻訳するようなアプリを考えたけど
ローケルアプリ系は今のバージョンだと
Androidの設定をいじらないといけないから
現実的ではないです。

で、ちょっと分、秒のレイアウトの配置のずれが木のせいで見過ごすには
ちょっと無視できないレベルになってきたので
せめて中央に配置するぐらいにはしようと思って今なおしている処なのですが
何故か中央に配置することができない。


理想現実



解像度がhdpiの時に発生するのが確認できているので
android:gravity="center_vertical|center_horizontal"を設定していても
大きさに余裕がないと正しく配置ができないのかも??

調査した結果、対策としては文字のサイズを小さくすることで
以下の画像のように中央に表示できることが確認できました。



拡張ライブラリで大きさ24%という風に設定しているのですが
どうも、用意した大きさに対してフォントのサイズが大きすぎたようで
その為、中央に配置することができなかったみたいです。

というかmdpiでは90spで指定していたのに
何故かhdpiでは100spで指定していた……。
そりゃあ、おかしくなるのは当たり前ですよね……。

ひとまず、私の設定では80sp辺りがちょうどいい感じでした。
ある種の最大の問題が片付いたので
今日はここまで。



2017年9月26日火曜日

2017-09-25 到達点メモ


Youtube動画を作る際は、テキストで説明するならば
字幕で作ったほうが多分楽。
あと、一回字幕を作ると、翻訳はそこまで手間ではない
ただし、翻訳は下に表示されるので
一部の動作が見えなくなる時がある。
それを考えると、動画編集でカバーできる部分はあるとは思うが
下に表示するUIはあまり良くないのかもしれない。


主要言語一覧
国名コードを調べたい時に便利なサイト
言語から国名コードを調べたい時に便利なサイト

◆ローカライズ化のする際に楽な手順

0.改行マークのコード(\n)を入れていると、翻訳がおかしくなる時があるので
削除しておく。

1.変換したい場所をcsvにして、三つ区切りにする
例:
<string name="test">,,</string>

2.Excelで開いて、翻訳した内容を
真ん中にコピーする

3.Excelの中身を全部コピーして、
テキストエディターに貼り付ける

4.置換でタブを削除して、それをコピーして
XMLに貼り付ける

5.消した改行コードを入れる

◆その他
・ヒンディー語は、未知の言語過ぎたので
今回は見送り。テキストエディターだと表示されない部分がある。
ただし、AndroidStudioでは全文表示された。
あと、一文字の表現をどうやればいいのかちょっと分からなかったのも
見送った理由の一つ。

・ズレると死ぬので追加する場合は、多分上から順に加えたほうがいいと思われる。

・中国にGooglePlayは存在しない
「Google Play」、中国で年内に復活か--レノボ幹部が発言との報道
*2016年の話。2017年9月25日時点では復活していません
米グーグル,中国市場からの“撤退”を表明


ひとまず、母語話者1億人以上のものはカバー出来るやつは全部カバーした。
動作確認を終えたら、一先ず上げるか???
英語欄だけに対応言語を書いて、それで終わりも手かも。

2017年9月19日火曜日

2017-09-18 到達点メモ


Record Espresso Testの使い方を調べてみた。

・記録でサポートできない、もしくは余分な所があるので削除する作業が必要である。
・すべての動作が記録されるわけではない。例えば、画面を単純にタップしたイベントとかは記録されない。(*例:OverFlowボタンをタップした後に画面外をタップしてウィンドウを非表示にするという動作をやった場合、画面外のタップのコマンドは認識されないので、他のボタンをタップする処理を入れるとエラーになる)
・画像を見比べることは出来ない。また複雑な動作のテストも難しい
・DateもしくはTimePickersはあるみたいなのだが、どうもNumberPickerはないっぽい???そもそも、今使っているピッカーが外部ライブラリーなのであってもそのまま生かすのは難しそうだが……。
・通知ドロワーの動作を取得することができない。例えば、通知ドロワーをクリックするとアプリがアクティブになる動作とか。
・あくまでアプリの部品がタップされたかどうかを覚えるのであって、それ以外は覚えないようである。


参考サイト
Record Espresso Test でテストコードを自動生成してみる
DroidKaigi2017 - 変更に強いEspressoテストコードを効率良く書こう
Espresso cheat sheet(PDF)
Espresso Test Recorderを使ってUIテストを作成する
PickerActions(公式ドキュメント)

という訳で実際にRecord Espresso Testで記録した後に
実際動作を試したところ以下のようなエラーが出た
java.lang.RuntimeException: WakeLock under-locked

原因としては、stopボタンをタップした時に、WakeLockを解除しているのだが
タイマー起動中にアプリを終了させる可能性を考えて
Destroyでも解除の命令を入れている。
で、理由は解除しているのに更に解除の命令を入れた為、このエラーが出た。
対策は以下のようにすればよい

if(wakeLock.isHeld()){ wakeLock.release(); }

参考サイト
java.lang.RuntimeException: WakeLock under-locked C2DM_LIB

思わぬバグを見つけて少し得した気分である。

考えてみれば当たり前の話ではあるが、一度パッケージ名を決めて公開したら
もうそのパッケージ名は変更することができない。
アプリ開発は、独自ドメインを持ってから、そのアドレスをもとに
パッケージ名を設定すると検索の設定辺りで大変お得です。

古いデータだけど、VoiceTimerで検索するとYoutubeで引っかかるから検索の仕組みってよくわからない……。

アプリをアップデートしたので今日はここまで。
良かったらアップデートしたキッチンタイマーアプリを
ダウンロードしてください。
VoiceTimer


2017年9月16日土曜日

2017-09-16 到達点メモ


今日はAndroid6.0をエミュレーターでテストした時に
タイマー一覧をクリックする→5分を選択→開始する→初期化する→タイマー一覧をクリックする→7分を選択してタップするを繰り返すと
偶にタイマーを選択した瞬間に0になる時があるというバグの検証をする

可能性としてはかなり低いが、
一応メモとしてWheelPickerという自作ライブラリを使っている事を明記しておく

今やらないとずっといつかやるになるので自動テストの検証をする
ひとまず、Appiumを試してみる

動作確認は以下のサイトを参考にしている
Android, iOSでGUIテストを自動化するためのAppium [環境構築編] [Windows + Node.js]


npmを使うので、まずそれを入れようと思ったのだが
どうもnode.jsを入れるとそれに付随してnpmも入るらしいので
早速入れてみる。無事入ったのを確認できた。

参考サイト
Node.js / npmをインストールする(for Windows)

という訳でさっそくappium-doctorをnpmで入れてみて
試してみた




何気にNode.jsを要求されている件について。
まぁ、入れたからいいんだけどさ……。
*この時参考にしたサイトの題名をよく読んでいなかった。

環境変数を設定できるようにするには
Win10の場合だと、設定→バージョン情報→関連情報のシステム情報→システム詳細設定で見ることができる。もっと見やすい方法がありそうな気がするがとりあえずこれで良しとする。
JAVA_HOMEは普通に調べたらわかったが、ANDROID_HOMEが結構曲者だった
*参考にしたサイトに普通に記述してある。
ANDROID_HOMEはAndroidSDKの事を指しているらしい。
AndroidStudioを立ち上げて、Configure→ProjectDefalutes→ProjectStructureで
AndroidSDKの場所がわかるようになる
再度試したところ、%JAVA_HOME%\binで引っかかった。
どうやらJAVA_HOMEのURL自体に\binはいらないらしい

参考サイト
Cordova でビルドしようとしたら ANDROID_HOME is not set と言われた
Android SDKの場所の確認方法
PATHの設定及び環境変数JAVA_HOMEの設定
Android Studioの設定

で、ここから動作テストをしようと思ったのだが、
操作方法が全く分からん……。
調べても一年前の記事がほとんどだし、どうしたらいいのか……。

此処までやっておいてあれだが、飽くまで楽にテストをするのが目的なので
いったんAppiumは保留にしておく

つぎは、Espresso Test Recorderの方を試すことにする。
これはエミュレーターの操作から自動テストを出力する機能である。
というか、記憶のどこかにあったけど、思い出せなかったのでスルーしていた。

操作方法は以下のサイトを参考にした。
一つ以外特に何か設定はいらなかった

参考サイト
Record Espresso Test でテストコードを自動生成してみる

設定中に色々してたらこんなエラーが出た
Error:Conflict with dependency 'com.google.code.findbugs:jsr305' in project ':app'. Resolved versions for app (3.0.1) and test app (2.0.1) differ. See http://g.co/androidstudio/app-test-app-conflict for details.

対処方法は下が一番早い

androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') {
  exclude group: 'com.google.code.findbugs'
}
参考サイト
Error:Conflict with dependency 'com.google.code.findbugs:jsr305'


で、録画中に分かった事だが、バグの詳細が分かった。
どうも極端に思い処理をしているときに停止ボタンをタップすると
値が0になるようである。

録画機能を使う際に気を付けることとして
通知ドロワーの処理は録画範囲外なので気を付ける事。

androidTestUnitの書き方を調べたほうがいいかも
このままだとエラーが起こってもどこでエラーが起こったのかがわかりにくい。

結局、書き方を調べるのにそっちのけで
エラーの原因を探していたのだが原因が分かった。
画面の更新を別クラスのHandlerでかけているのだが
恐らくStop→別クラスでキャンセルメソッド(内部値のカウントをゼロにする。また、この値を現在の残り時刻としている)を呼び出す→別クラスの内部値をもとに画面更新処理をやる
*画面更新のメソッドはMainActivityでおこなっている。
此処で関係あるのは、MainActivityと別クラスの二つだけである。

上記の手順でやっているのだが、処理が重いと実際の画面更新よりも内部の処理が先に走ってしまい、0になった時に画面を更新してしまう為、値がずれるという事が起きてしまう。
上手く説明できている気がしないが、要は処理が重いと想定した順番通りの更新順にならないという事が起きるという話だと思っている。

対策は、MainActivityで開始ボタンを押したかどうかのフラグをもっているのでそれをMainActivityの画面更新メソッドでthis.flagという形で指定して開始ボタンを押していない時は、更新処理をしないという処理を行えばよい。

状態の管理は、呼び出し元(ここではMainActivity)を参照するようにすれば
飽くまで全体の流れはMainActivityで制御しているので
このようなズレが発生しても問題が起こりにくいのではないかと思われる。

頭がゆだってきたので、Androidはこれくらいで終わり。
後はudemyでコースを買ったのでそれのさわりをやって終わり。
さわりをやった感想としてはもともと初心者向けの内容だったので
基本的な話しかなかった。

今日はここまで。

2017-09-15 到達点メモ


RemoteViewで通知ドロワーを作る際に気を付ける事として
・解像度にかかわらず最大値の高さは変わらないため為、解像度にアイコンの大きさは依存しない。個人的にはlayout_centerVertical="true"で配置するなら36dpくらいでちょうどいい大きさだと思う。
・その代わり、機種によって横の大きさが異なる為、それを意識してデザインする必要がある。具体的には、タブレット機種。今回は縦固定だから関係ないが、横表示をやるなら、同様に注意する必要がある気がする。
・タイトルは18dpで、本文は15dpに設定した。個人的に本文はデフォルトの色(style="@android:style/TextAppearance.StatusBar.EventContent"で設定された色)ではなく、黒に近い色が見やすくていいと思う。あと、タイトルは黒にしたが、本文は青に近い黒を採用した。違う色同士の方が見やすい気がしたのが理由です。

話は変わるが、本アプリ制作において今更ながらに失敗したなと感じたことが幾つかあえる。
・SmartNewsのUIを見て問い合わせは素直にメール送信の機能で作ればよかったと思った。グーグルフォームは多言語対応していないので(言語切り替え的なことができない。自分のは、態々翻訳した言語で同様の内容の問い合わせフォームを新たに作っている)
・宣伝動画は日本語を基本で作って字幕で対応したほうが絶対楽だった。
・事前調査が足りなかった。グーグル検索でも名前を検索してみるべきだった。
一方で連想しやすい名前じゃないと検索に引っ掛かりにくいので独自の名前が良いとは一概には言えない。
他にも何かあった気がするが思い出したら追加する。

タップしたらアプリが終了していても起動するようにしたかったので
broadcastでActivityを立ち上げるようにしたい。
しかし、broadcastではstartActivityをそのままでは使えない
のでcontext.startActivity(intentActiviy);をする必要がある

以下のサイトを参考にした
システムの起動時にアプリを起動する


開発者向けオプションでタップの表示というコマンドがあった。
タップ位置がわかると動画のわかりやすさが全く違う。
というか最初作った時はわざわざタップした場所を赤線で囲むようなことをしていた。
念のため、adbコマンドで録画してみたがきちんと映っていたのを確認できた。
アプリの方だと音ズレの問題と動画サイズを細かく調整できないので
こっちの方が結局やりやすい。

アップロードする前にエミュレーターで操作時に選択リストをタップすると
00:00になる時があるので検証してみたが
Android6.0の時に頻繁に起こるようである。

割とさっさとどうにかしたいので
テスト用のログの作成とテストの簡素化をするような方法を調べるようにしたい。
今日はここまで






2017年9月15日金曜日

2017-09-14 到達点メモ


大まかにレイアウトが決まった気がする。
タイトルの上に空間を取ったほうが見やすい気がする
具体例は下の画像を参照

タイトルの上の空間無し タイトルの上に空間を入れる

次の問題は、レイアウトの統一とアプリ終了後に
停止ボタンを押すとエラーになる問題をどうするか……。

アプリ終了後に停止ボタンを押すとエラーになるのは当たり前の話ではあるのですが
とか考えていたのですが、普通にReceiver側でMainActivityが存在しない時は動作しないという風に書き換えたら普通に対処できた。

レイアウトは統一できた。
うーん。今のところ、停止ボタンをタップできるのがタイマーが終了した時のみ
なのだが、こうして作ると通常時もスタートとストップボタンが欲しくなる……。
実装は難しくはないのだが、現状は停止ボタンを押したときに
通知は消える仕様になっているし、かといって消さないと消えない通知が存在する可能性が高くなるからあまりやりたくはないのだが……。
元々はロック画面の時タイマーを止められるようにしたいというのが目的だから
一先ずはこれで良しとしよう。

コードをリファクタリングしていて気が付いたのだが
どうも、switch文の条件分岐を使いたい場合は、必ず値が固定でないとダメなようである。
具体的には以下のような書き方はfinalを使っていても許されない。
具体的には赤字のnumの部分で赤並線が引かれる。

    public void updateUI(int now_sec, int state){
        final int num = now_sec;
        switch (state){
            case num:
                break;

        }

恐らく定数は決め打ちでないとダメなようである。
具体的には final int num = 1 と書けば赤並線は出ない。
この場合はもう仕方がないので、if文を使うしかない。

参考サイト
R.id.xxx を switch 文で使うと case expressions must be constant expressions

なんかエミュレーターでテストしてたら謎のバグを発見した
タイマー一覧をクリックする→5分を選択→開始する→初期化する→タイマー一覧をクリックする→7分をクリックするを繰り返すと
偶にタイマーを選択した瞬間に0になる時がある。
実機で20回くらい試したが挙動が確認できない……。
どういうことなの…???

通知ドロワーのレイアウトを確認したかっただけなのに……。
色んな意味で頭が痛くなってきたので今日はここまで。

2017年9月13日水曜日

2017-09-13 到達点メモ


中間報告としてのメモ

//通知部分の作成

        NotificationCompat.Builder mBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_notification_clock)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                        RemoteViews customView = new RemoteViews(this.getPackageName(), R.layout.notification_layout);
        customView.setTextViewText(R.id.notification_title_id, "VoiceTimer");
        customView.setTextViewText(R.id.notification_text_id, mConstRParams.finish_button_name);

        Intent intent = new Intent(this, MyBroadcastReceiver.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.setAction(FINISH_ACTION);

        int request_code = ACTING_REQUEST_CODE;
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this,request_code,intent, PendingIntent.FLAG_UPDATE_CURRENT);
mConstRParams.finish_button_name, pendingIntent);
        customView.setOnClickPendingIntent(R.id.notification_button_id,pendingIntent);
        mBuilder.setContent(customView);
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(mId, mBuilder.build());

//通知部分のレイアウトの作成

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <ImageView
        android:id="@+id/notification_icon_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"/>
    <TextView
        android:id="@+id/notification_title_id"
        android:textColor="@color/gradient_start_color"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/notification_icon_id"
        style="@android:style/TextAppearance.StatusBar.EventContent.Title" />
    <TextView
        android:id="@+id/notification_text_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/notification_icon_id"
        android:layout_below="@id/notification_title_id"
        style="@android:style/TextAppearance.StatusBar.EventContent" />
    <Button
        android:id="@+id/notification_button_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/notification_text_id"
        android:layout_below="@id/notification_title_id"/>
</LinearLayout>


これで、表示はめちゃくちゃだが、ロック画面でもアプリ操作をすることができる。
現状アイコンの表示ができないのと、普段の表示と変わるので
これで統一する必要がある。

参考サイト
AndroidのNotificationでカスタムViewの高さを広げる
Adding button action in custom notification
NotificationのUIをカスタマイズする


Vector画像をbitmapに変換する際に参考にしたサイト
Getting Bitmap from vector drawable


メモ事項として
・remotelayoutを使う場合でも、setSmallIconは定義しなくてはいけない
・layout_marginを使用した後に、layout_marginLeftは適応されない
・layout_toRightOf系はLinearLayoutでは使用できない。きちんとRelativeLayoutになっているか確認すること

形は大体見えてきたので、あとは通常時の表示と合わせるのと
停止ボタン以外をタップした場合は、アプリを立ち上げる処理を入れることをやればよい。
これで大体の処理は終わるはず。
今日はここまで

2017-09-12 到達点メモ


うーん……。とりあえず動いたのは確認できた。
ので、一部抜粋する。

ひとまず、onCreateで下記に内容でreceiverを登録し
        myBroadcastReceiver = new MyBroadcastReceiver();
        intentFilter = new IntentFilter();
        intentFilter.addAction(FINISH_ACTION);
        registerReceiver(myBroadcastReceiver, intentFilter);

manifestファイルで下記の内容を追記し
<receiver android:name=".MyBroadcastReceiver" />


投げる際に以下の内容を書き
        // 通知をタップした際に、起動しているアクティビティをそのままの状態で呼び出す
        Intent intent = new Intent(this, MyBroadcastReceiver.class);
        //存在するアクティビティを使いまわす必要がある為
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.setAction(FINISH_ACTION);
        int request_code = ACTING_REQUEST_CODE;
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this,request_code,intent, PendingIntent.FLAG_UPDATE_CURRENT);
        mBuilder.addAction(R.drawable.ic_play_icon, mConstRParams.finish_button_name, pendingIntent);

で、あとは別クラスでpublic class MyBroadcastReceiver extends BroadcastReceiver 的なのを作れば、一先ず、タップするとストップする処理を作ることができた。

参考サイト
Determine addAction click for Android notifications
ブロードキャストレシーバの実装によるアクティビティとサービスの通信
BroadcastReceiverでAlarmManagerのアラームを受け取る
BroadcastReceiver not working when app is not running

些細な事だが、昨日折角参考サイトを用意したのに
結局読まなかったな……


ただ、三つほど問題があって
一つは、PlayMusicが起動中、addActionが表示されない事
もう一つは、画面ロック中はaddActionが表示されない事です
*addActionかは不明だがPlayMusicはボタン表示が出来る。
最後の一つは、VGAのアイコン画像が表示されない事です。

調べた感じだとPlayMusicではここの処理でやってそう
公式ドキュメントをきちんと読んでないのが丸わかりですね(白目)

此処のサイトのprivate void initMediaSession() 辺りが参考になるかも?
ただ、個人的に何度見ても気になるのは音楽再生専用のメソッドの気がして
しょうがない……。

今日はここまで




2017年9月12日火曜日

2017-09-11 到達点メモ


進まなくても、何が駄目だったかをメモしないと
同じことの繰り返しになるのでメモをしないとダメだな。

通知エリアと通知ドロワーの二つがあり
今回自分がしたいのは通知ドロワーにボタンをつけて
アクティビティを立ち上げずに、アプリの操作をしたい

参考サイト
公式ドキュメント-通知

この機能はGoogleMusicで出来ることは確認した。

ボタンを作るのはAddActionを使えば作れる。

参考サイト
[Android] Android 4.1 で追加された Notification styles


現時点では、きちんと動作確認ができていないので推測になるが
おそらく、PendingIntent.getBroadcastで通知を飛ばし
受け取る用のクラスを作り、そこから操作するということをやるのではないだろうか?
構造的にはMainActiviyで発火を行い、MainReceiveクラスを作成しそこで
取得した後、そこからMainActiviyのクラスのストップメソッドを呼び出すなり
スタートメソッドを呼び出すなりすればよいと思われる。

参考サイト
Determine addAction click for Android notifications


まだ、ちゃんと読み込んでないけど
このサイトの内容が使えそう?

もう遅いので今日はここまで



2017年9月10日日曜日

2017-09-09 到達点メモ


知恵を絞れば案外何とかなるものだなぁ。
昨日言っていたASUS ZenPad 7.0のAndroid5.0.2で音声ファイルがロードできない時があるという問題は対処することができた。

割と力業ではあるが要するに
ロードを失敗したファイルをロードできるまで
ロードすればいいだけの話である。
具体的には以下のように実装した

        soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                Log.d(TAG,"sampleId = "+sampleId);
                Log.d(TAG,"status   = "+status);
                if(status != 0){
                    Log.d(TAG,"failed_reload");
                    int failed_number = 1;
                    failed_number = soundPool.play(woman_voice, 0 ,0, 1, 0,(float)2.0);
                    if(failed_number == 0){
                        soundPool.unload(woman_voice);
                        woman_voice = soundPool.load(l_context, R.raw.woman_voice_short_c, 1);
                    }
                    failed_number = soundPool.play(man_voice, 0 ,0, 1, 0,(float)2.0);
                    if(failed_number == 0){
                        soundPool.unload(man_voice);
                        man_voice = soundPool.load(l_context, R.raw.man_voice_short_c, 1);
                    }
                    failed_number = soundPool.play(clock_alarm, 0 ,0, 1, 0,(float)2.0);
                    if(failed_number == 0){
                        soundPool.unload(clock_alarm);
                        clock_alarm = soundPool.load(l_context, R.raw.clock_alarmdig_short, 1);
                    }
                    //sampleIDは、unloadしても数は減らないので
                    //sampleIDが30になったら、全部で10回は試行して失敗しているので
                    //そのときはもうアプリを終了させて再度立ち上げたほうが良い
                    if(sampleId > 30){
                        Toast.makeText(l_context,R.string.message_when_audio_file_loading_failed,Toast.LENGTH_SHORT);
                        MainActivity.getInstace().finishAndRemoveTask();
                    }


                }
            }
        });

コードに大体書いてあるのだが
sampleIDは事実上ロードした回数を指しているので
これをもとにピンポイントにロードすることができない。
その為、失敗したファイルのみをピンポイントで音声を再生する為には
別の工夫が必要である。
具体的には公式ドキュメントに音声再生できない場合は値が0で返ってくるので
再生できなかったファイルをunloadしてもう一度再生しなおせばよい。

公式ドキュメントを見てもonLoadCompleteのstatusについては、0が成功ぐらいしか
書いていないので何もわからないのだが、誰か-22の意味を知っている人はいないだろうか?

サンプル数は10も満たないので正確ではないが
自分がテストした限りでは、もう一度ロードすれば大体読み込めて
ロード失敗は多くても二回だけだった。

今日はこれを作ってほぼ満足したので今日はこれまで。

2017年9月9日土曜日

2017-09-08 到達点メモ


string.xmlで存在しないローケルを作って、それを削除した後
コンパイルをかけたら、以下のようなエラーが出る
Error:Error: Invalid resource directory name android
XXX(消したフォルダ名)

まず、正しいローケルの名前は
wikiのココが参考になります。なお、二文字のみです

で、正しい名前を作った後は
string.xmlが入っているフォルダのエクスプローラーを開きます
そうすると、消したはずのファイルのフォルダが残っていますので
それを削除します。

そのあと、クリーンビルドをかけて構成しなおすと
コンパイルができるようになります

それより、なぜか言語を変更すると一部のファイルが読み込めない件について
使っているのはzhです。*zhで中国語の簡体字で閲覧できるのはわかった。

念のため、日本語で再度確認をしてみたが
音声が再生されないとかはなかった。
細かく試した結果そんな事は無かった。
多分、今まで使っていた機器は性能が高かったから
全部ロードした後に表示できたけど
他のはそうではなかったというだけっぽい

素直にロードしたデータを使いまわす処理を実装しよう
という訳で原因はそれだったっぽい
以下を参考に解決しました。

参考サイト
AndroidアプリでContextを持ち回したい話

ただ、この方法だと一部の音声ファイルのロードができなかった。
色々試した結果、アラーム音の再生時間を2秒から1秒に縮めたところ
ロードできるようになった。
話によってはSoundPoolの再生が長いとロードされないという報告はあったが
そういう理由なのだろうか?
確かに、この音声ファイルがこの中で一番再生時間が長かったし
(*もっとも、空白時間も含めれば、1.7秒と1.5秒だったので2秒が境目なのかも?
実際の再生時間自体は、1秒くらいであるが)
大体音が鳴らないのがこのファイルだったのは確かだが……。
今回の問題に限っていえば、音声ファイルを編集したほうが早かったかもしれない。


解 決 し て い な い。

大まかに10回に2回くらいの割合でロードできないファイルがでる
しかも傍から見てランダム。

そして、少なくとも自分が使っているAQUOS ea Android7.0だと発生しない
ASUS ZenPad 7.0のAndroid5.0.2(API21もしくはLOLLIPOP)だとこの現象が発生する

結局見当がつかない
最悪、ロードできないファイルが存在したら
アラートを出して立ち上げなおしかなぁ……

いや、出来ればそれは避けたいが本当にどうしよう……。
煮詰まってきたので今日はここまで


追記:
忘れていたのでApplicationをextendしないで
グローバル変数化するやり方
此処のやり方は時間を見て試す


2017年9月8日金曜日

2017-09-07 到達点メモ


なんか動かないので見直してみたら使っていない変数を呼び出していたりしていた。
今回やっていて一番てこずったミスはこれ

    public int getTimerSec() {
        timerSec = (min10place *60*10 + min1place *60* + sec10place*10 + sec1place);
        return timerSec;
    }

これは各桁の分と秒を纏めて秒に変換する処理をやっているのだが、
上記のコードのままだと例えば9分39秒を579秒に変換するはずが
何故か、最終的に返される値が16209秒になっていた。
色々調べて気が付いたのだが、わかる人はいるだろうか?
*ヒント。元々は各桁の分と秒を纏めてミリ秒に変換するの処理だった。

     public int getTimerSec() {
        timerSec = (min10place *60*10 + min1place *60* + sec10place*10 + sec1place);
        return timerSec;
    }

上記の赤文字の部分が余計でした。
*1000していた処理で*の部分を消し忘れてたみたいです。

肝心のディープスリープの状態でHandlerがどれくらい動くのかを調べてみたのですが
ディープスリープが働いている状態でもHandlerは動いているみたいなのですが
Android7.0だと30秒が5分30秒ぐらいの長さになってしまいます。
これだったら正直前の方がまだましである。

再度調べてみたが
wakeLockかAleramMangerのどちらかを使えしか出てこない。
ただ、やっぱりAleramMangerは前調べた通り
一秒単位の細かい更新を図るのには向いていないようである
Timerを使ってはどうかという案が出て入るのだが
これってどうなんだろうか?

参考サイト
[Android]AppWidgetProviderでAlarmManager#setRepeatingがリピートしない

今回は今あるのをもう一度書き直す気力がなかったのと
wakeLockを実装するのが簡単そうだったので
今回はこちらを採用。
*一応軽く調べた限りでは、jobschedulerを使うらしいが
どうもメインのアクティビティ以外ではhandlerを使うように見えた。
ただ、調査のみで動作検証はしていないので、メモだけは残しておく。

簡単なメモとして、
・wakeLockはおそらくメインのアクティビティで呼ばないといけない
・wakeLock.acquire()をしていない時にwakeLock.release()を呼び出してはいけない
・wakeLockは一度作るとrelease()しても使いまわせる。

参考サイト
WakeLockを試す

今回使ったフラグ値は、PARTIAL_WAKE_LOCKで、スクリーンもキーボードも両方オフにするのですが、CPUは動いているので今回のDeepSleepを避ける際用途に使うことができました。
あと、今回は使わなかったので深くは気にしなかったのですが
PARTIAL_WAKE_LOCK以外にもフラグ値があと三種類あるのですが
どれもAPI17か13で廃止されているようです。
その割にはAndroid7.0で何故かFULL_WAKE_LOCKが使えた。

参考サイト
公式ドキュメント-PowerManager
公式ドキュメント-PARTIAL_WAKE_LOCK
公式ドキュメント-FULL_WAKE_LOCK
公式ドキュメント-SCREEN_DIM_WAKE_LOCK
公式ドキュメント-SCREEN_BRIGHT_WAKE_LOCK

無事アプリの更新もできたので。今日はここまで。



2017年9月7日木曜日

2017-09-06 到達点メモ


もしかするとアラームとキッチンタイマーの意味を勘違いしていたかもしれない。
アラームは、指定した時間に起きることが重要であって
それまでの時間はあまりリアルタイムに出すことは重要ではない
一方で、キッチンタイマーは終わりの時間ももちろん重要だが
それまでの時間も重要視している。

調べてみると、どうも時計とかの処理をやりたい場合は
Handlerの方がやりやすいというのが記述があった
どちらかと言えば、自分がやりたいことはアラームよりは時計にのほうが近いだろう
そもそもにしてどうも単体で呼び出した場合は、最速で5秒らしくまた繰り返し読んだ場合は最速で1分かかるらしい。
道理で、遅いわけだ……

参考サイト
techium-AlarmManagerを攻略する

一応、でけた。
handlerでやるのが楽だしスマートだ。

参考サイト
AndroidでTimerを使わずHandlerだけでお手軽に定期実行してあげる


公式ドキュメントの推奨方法だから
問題はないとは思うが一応調べたほうがいいかな……。
あと、いつの間にかConstraintLayoutというやつがあったんだな。
最近とかの話じゃなくて一年以上前には実装されていたみたい。

参考サイト
Androidの新しいLayout、ConstraintLayoutことはじめ
[Android] 新しいレイアウト登場!Constraint Layoutについて


調べてみたらHandlerは重い処理の時に落ちることがあるらしい。
今回に限ってはないとは思うのですが、念のためHandlerThreadの方で書くことにする。

参考サイト
Android 非同期処理についてまとめる メモ

あと、今回は、カウントの処理とメインのUIの処理で分けました。
その際に、カウントの処理の際にメインのUIを更新する関数を呼び出したいと思ったので此処の質問の答えの一部を参考に関数を作成しました。
具体的にはメインのアクティビティをインスタンス化したことだ。

ただし、呼び出し方を間違えたようで以下のようなエラーが出た。
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

その為、此処のサイト此処のサイトを参考にし
以下のように作成しました。
        runnable = new Runnable() {
            @Override
            public void run() {
                count++;
                if (count > limit_time) {
                    count = 0;
                    return;
                }
                // UIスレッドは明確に明示してやる必要がある
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        MainActivity.getInstace().updateUI(count);
                    }
                });
                handler.postDelayed(this, 1000);
            }
        };
runOnUiThreadは、activiyのメソッドの為
自作クラスで使う場合は、activityを継承してあげる必要があります。
あと、runnableの中にrunnableって使っていいというのがちょっと意外なだった。
何故駄目なのかと聞かれると何となくとしか言いようがないが。

一応のめどはついたし、今日は疲れたのでこれくらいで。

2017年9月6日水曜日

2017-09-05 到達点メモ


スリープは設定で自動では起きないとはいえ
VoiceTimerでちょっとまずいバグを見つけた。
具体的にはスリープ時にタイムアップすると
0000でないのにタイムアップするときがあるという現象です。
殆ど使っている人はいませんが、ご迷惑をおかけして申し訳ありません。

具体的には内部処理でCountDownTimerを採用してましたという話。
これディープスリープ時だと値がずれるらしいです。
正確には、タイマーの表記上は00:00になっていないのに
アラームが鳴っていたりしました。
一応認識はしていたのですが、きちんと現象としては再現できていなかったので
無視していた形でした。
どうもケーブルに接続しているとディープスリープにならないようでした。
内部の値的に0になっていないのか、単に画面更新がされていないのかちょっと区別ができなかったので……
自分もすっかり忘れていたのですが、Log.dの中身はケーブルを接続している最中に動作させなくてもLog.dを吐き出した直後にケーブルをつなげば、AndroidStudioのログでも見れるときもあります。
結果は、ログを見た限りでは内部の値も0になっていませんでした。

参考サイト
CountDownTimerを使ってはいけない2つの理由「Android」(1)
CountDownTimerを使ってはいけない2つの理由「Android」(2)

それで、AlarmMangerを使うところまではわかったのですが、
途中経過も知りたいのでこれだと機能が足りない。

参考サイト
[Android] タイマーアプリをAlarmManagerを使って作る

最初は、onActivityResultを使う事を考えていたのだが、
そもそも、receiveでは、contextは単にstartActivity()しか使えないため
requestcodeを送ることができないのでどう見ても無理。
で、色々調べまわったところ、まさしくやりたいことを見つけまして
How to update UI in a BroadcastReceiver
そうだよ。アクティビティに戻したいとかじゃなくて
UIを更新したいんじゃん。

 public void updateUI(final String str) {
        MainActivity.this.runOnUiThread(new Runnable() {
            public void run() {
     //use findFragmentById for fragments defined in XML ((SimpleFragment)getSupportFragmentManager().findFragmentByTag(fragmentTag)).updateUI(str);
            }
        });
    }
上あたりの内容が手っ取り早そうだったので早速試してみたが
うまくいかなかったので下のを試す
WakeLockじゃなくてAlarmManagerを使って定期的な処理を継続する

こっちをさっさと試せばよかった。
ひとまず、onReceiveをしたら
Viewの更新ができるようになった。
幾つか嵌ったところを書けば、intervalは単に値を指定しているだけなので
別にintentとかの処理は書かなくても良い
インターフェイスはメインのアクティビティにインタフェースの実装(implements)をしなくてはいけないというぐらいだろうか。
うーん。我ながら全然読んでいない感と勉強していない感……

参考サイト
とほほのJava入門-インタフェース
TECHBOOSTER-独自リスナーを作成する

色々考えこむよりは試した方が速そうだなぁ
一先ず動くものができないと話ならない。
まずは、AlarmManagerを試して問題があれば
Handlerだろうか

参考サイト
Android開発ログ-Androidの管理する時間について
Y.A.M の 雑記帳-AlarmManager

少ししか検証できていないが
どうもうまくいかん。というか初回はともかくして二回目以降は
明らかに1秒以上でたっても更新されない。
更新作業自体がないわけではないのだが、これではちょっと使い物にならない。
あと、スライドさせてアプリを終了させると異常終了が出るのが
ちょっとなぁ……。

そういえば、この件前に疑問に思って調べたけど分からなかった部分だから
割と真面目に一度質問したほうがいいかもなぁ……。


2017年9月5日火曜日

2017-09-04 到達点メモ


何の設定が悪いのがいまいちわからないのだが
アイコンの画像が正しく表示されない
此処に書くと、長すぎるで別記事を立てました。

ブログの書式に悪戦苦闘したので一度bloggerの使い方を調べる必要がある
あと、今回別デザインのアイコンに変更し、
GooglePlayにアップロードしたのですが
どうも、一度アップロードすると保存しなくても
データが載るみたいで、バージョンの更新を上げないと
アプリをアップロードすることができませんでした。

割と参考にしているアプリの説明文をあらためて読んだのですが
自分のアプリと違ってわかりやすさが段違いだったので
また書き直しになりそうです。

これが終わったら、そろそろローカライズを増やすか
新しいアプリのネタを練るとかしたい

XML変換したVector画像がAndroid7.0より前だと一部正しく表示されない


下の画像を使用して、アイコン表示をやりたかったが上手くいかない。
以下の画像は、Inkscapeというソフトを使って
SVGを作成した後に、AndroidStudioを使って
XMLに変換して取り込んだ。

<vector    android:height="@dimen/launcher_icon_size"    android:width="@dimen/launcher_icon_size"    android:viewportHeight="313.0457"    android:viewportWidth="313.5988"    xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#FF000000" android:pathData="M-752.22,150.45h28.57v65.71h-28.57z"/>
    <path android:fillAlpha="1" android:fillColor="#b3b3b3"        android:pathData="M66.17,0.41L247.42,0.41A65.77,65.77 0,0 1,313.19 66.17L313.19,246.87A65.77,65.77 0,0 1,247.42 312.64L66.17,312.64A65.77,65.77 0,0 1,0.41 246.87L0.41,66.17A65.77,65.77 0,0 1,66.17 0.41z"        android:strokeAlpha="1" android:strokeColor="#b3b3b3" android:strokeWidth="0.81412393"/>
    <path android:fillAlpha="1" android:fillColor="#ffcc00"        android:pathData="M35.26,210.42A103.88,118.54 0,0 1,102.32 61.26,103.88 118.54,0 0,1 233.02,137.78 103.88,118.54 0,0 1,165.99 286.94,103.88 118.54,0 0,1 35.27,210.45"        android:strokeAlpha="1" android:strokeColor="#ffcc00" android:strokeWidth="0.33088112"/>
    <path android:fillColor="#000080"        android:pathData="m160.45,3.99 l-32.63,51.5a105.49,119.86 0,0 1,5.57 -0.39,105.49 119.86,0 0,1 101.61,83.12 105.49,119.86 0,0 1,-6.73 91.64l77.01,-31.5zM228.27,229.87 L182.37,248.65a81.38,92.47 0,0 1,-3 2.26v-1.03l3,-1.23A81.38,92.47 0,0 0,211.88 145.74,81.38 92.47,0 0,0 133.49,81.61 81.38,92.47 0,0 0,109.48 86.06,81.38 92.47,0 0,0 108.09,86.63l-54.99,86.78a81.38,92.47 0,0 0,3.85 29l0.01,0.02a81.38,92.47 0,0 0,82.34 63.84l3.33,-1.36v1.06a81.38,92.47 0,0 1,-3.33 0.31l-46.01,18.82a105.49,119.86 0,0 0,73.63 3.96,105.49 119.86,0 0,0 61.35,-59.18zM93.29,285.09A105.49,119.86 0,0 1,34.18 211.71l-0.01,-0.03a105.49,119.86 0,0 1,-1.5 -6.03l-27.49,43.39 38.75,56.25zM53.1,173.41A81.38,92.47 0,0 1,108.09 86.63L127.82,55.49A105.49,119.86 0,0 0,102.27 60.86,105.49 119.86,0 0,0 32.67,205.65ZM110.31,94.79L151.01,94.79v57.75h52.88L203.88,195.93L109.78,195.93L109.78,152.55h0.53z"        android:strokeAlpha="1" android:strokeColor="#000080"        android:strokeLineCap="butt" android:strokeLineJoin="miter" android:strokeWidth="1.26294589"/>
    <path android:fillAlpha="1" android:fillColor="#000080"        android:pathData="m1605.09,1916.84 l-0.94,1.56a70.28,70.46 0,0 1,0.41 -0.03,70.28 70.46,0 0,1 67.7,48.86 70.28,70.46 0,0 1,3.26 18.05l2.74,-1.75v-36.15l-28.39,-30.55zM1675.52,1985.29 L1657.53,1996.77a53.2,53.34 0,0 1,-36.37 43.81,53.2 53.34,0 0,1 -32.34,0.05l-16.31,10.41a70.28,70.46 0,0 0,54.39 4.86,70.28 70.46,0 0,0 48.62,-70.61zM1572.51,2051.04a70.28,70.46 0,0 1,-30.04 -30.93l-8.56,14.12v22.69l4.92,4.37h17.61zM1542.48,2020.11 L1553.21,2002.41a53.2,53.34 0,0 1,35.34 -63.36,53.2 53.34,0 0,1 3.67,-0.99l11.92,-19.66a70.28,70.46 0,0 0,-20.33 3.36,70.28 70.46,0 0,0 -45.37,88.66v0.02a70.28,70.46 0,0 0,4.02 9.68zM1592.23,1938.06 L1553.21,2002.41a53.2,53.34 0,0 0,1 3.75l0.01,0.01a53.2,53.34 0,0 0,34.61 34.46l68.71,-43.86a53.2,53.34 0,0 0,-2.04 -23.3,53.2 53.34,0 0,0 -51.25,-36.99 53.2,53.34 0,0 0,-12.02 1.58zM1593.34,1942.95h19.47v34.28a13.43,13.46 0,0 1,3.7 3.77l33.65,-0.01v19.52l-39.17,0.01a13.43,13.46 0,0 1,-1.61 0.65,13.43 13.46,0 0,1 -16.89,-8.68h-0a13.43,13.46 0,0 1,0.84 -10.26z"        android:strokeAlpha="1" android:strokeColor="#000080" android:strokeWidth="0.11688769"/>
</vector>
理由はいまいちよくわからないのだが AQUOS eaで見たときのみ正しく表示され エミュレーターと手持ちのタブレットの表示だと 以下のように表示される。 加工した画像ではあるが大体こんな感じに表示される。 具体的には下の青く表示されるはずの部分が 線だけが残っていて、塗りつぶしがされない状態になっている

 

検証した感じでは、Androidのバージョンに一番関係がありそうではある。
AQUOS eaはAndroid7.0でタブレットは6.0で検証した。
バージョンが今回の問題で怪しいと思っている理由としては5.0と5.1と6.0では上記のようになるので、
エミュレーターであるが、Android7.0で解像度が420dpiとxhdpiでは、正しく表示された。
ほかのAndroidのバージョンだと
どの解像度でやっても変わんなかったので解像度は関係ない気がする
また念のため、自分が使っているアイコンが android:viewportHeightや
android:viewportWidthの値が200以下なので
198にしてみたが、それも関係がなかった。
そうなると、Android7.0なら認識できるものがあるという事になるが
どういう事なんだろうか?
 
後日、再度調査するか質問掲示板辺りに投げたいと思う。

2017年9月4日月曜日

2017-09-03 到達点メモ



remoteurlを調べたい場合は
git remote -vをする
割とよく忘れるので注意

参考サイト


git addすることをインデックスに登録するという
git add . しても予め含まれないようにするには
.gitignoreに設定を書けばよい。

既に過去にコミットしたファイルを含めないようにするには
以下のようにコマンドを打てばよい
git rm --cached ファイル名

なお --cached を付けないと
ファイルごと削除されるらしい。
なんかこのコマンドを試したとき
いつの間にかこれを指定したファイルが消えていたが
抜けたたんだろうか?もしくは操作ミス?
もしかするとコミット後にやったコマンドだから
コミットから削除するために消えたのかも。

git add . した後にきちんとインデックスに登録した内容が
除外されているか確認するには
git status とコマンドを打てばよい

自分はよくシェルコマンドを使って入力するので
do*.shって.gitigoneに書いておくと
良く使うコマンドを別けて書きたい時
に自動的にインデックスに含まれないようになるので便利

参考サイト


チュートリアルにherokuのコマンドでログを表示するコマンドを調べなさい
という演習があったので(正解はおそらくlogs)
調べてみたらdrainsというコマンドがあったので
ちょっと調べてみる。
どうも外部のサーバーにログを転送する機能らしい。
メイン処理はherokuにやらせるけど、監視だけは別のサーバーでやりたい時とかに
つかうんだろうか?

参考サイト


新しくアプリケーションを作るところから始めるのはちょっと面倒だったので
一からつくりなおして、今まで使っているgitのurlにpushしたら
コンフリクトを起こした。
本来ならきちんと調べたほうがいいんだろうが、そこは主題じゃないので
コンフリクトを起こしたフォルダを全部消し、git cloneでデータを持ってきなおした。
複数のpush先を持っている場合、データ内容が同じでも
remoteのurlは保持していないので、それぞれからremoteのurlを持ってくる必要がある
なお、クローンした場合は、クローンした先のremoteのurlは登録される
herokuに関しては以下のようにとってきた
heroku git:remote --app heroku_app_name
なお、remote_urlは特にインデックスに加えたり、コミットする必要はない

参考サイト

postgresの設定で躓いた。
調べてみたらMySQLでもクレジットカード登録すれば
5MBまでは無料で作れるらしい。

Railsに疲れたので後は別なことをやった。
というか本来の目的は、仕様書を比較的に楽に管理するためのツールづくりだから
あんましRailsそのものをやりたいわけじゃないんだよなぁ。
具体的にはVoiceTimerのGooglePlay用のスクリーンショットの作成をやった。
割と何書けばいいか迷ったが、いつの間にかアプリの一覧表示でも
スクリーンショットが表示されるようになったので結構馬鹿にできないと思う。

あと、今のアイコンって時計というのはわかるんだけど
声との関連性がわかりにくいのでそこをどうしようか考え中
最初は、Inkscape(SVG作成ソフト)のテキストで
VoiceTimerって入れるつもりだったのですが
AndroidStudioでSVG取り込む際に、
エラーになってテキストの部分が取り込めず
どうにもならなかった。

しょうがないので以下のように文字を使わない方向で試行錯誤した結果がこれです。

拡大してみる分にはあまり気にはならないのだけど
縮小すると何の画像かわかりにくくなるので
まだ調整がいりそう。

あと、ちょっとapkファイルを小さくできないかと思って調べてみたのですが
軽く調べた感じだと、zipalign、ProGuard、shrinkResources、IconFont
あたりでしょうか。
zipalignは使ってみたのですが、容量に差はありませんでした。
また、ProGuardは既に書かれていました。
shrinkResourcesは使ってみたらエラーが出まして
ザっとしか調べていないのですが、stackoverflowerの回答によると
gradleのバージョンを2.1.3に下げると動くらしい?
そして、今回のアプリに限って言えば、画像は全部ベクター画像なので
IconFontを使う必要がありませんでした。

とりあえず、今日はこんな感じでした。



参考サイト
年末の大掃除、アプリの容量を削減するためのチェックリスト
\build\intermediates\res\resources-anzhi-debug-stripped.ap_' specified for property 'resourceFile' does not exist

2017年9月2日土曜日

Railsチュートリアル(第四版)に基づいたRails5.0.3+Cloud9でのHerokuへの接続方法


*2017/9/3追記
飽くまで、herokuにデプロイするのが目的です。
その為、databese.ymlの設定は
SQLite3のままになっております。
静的表示をするぐらいなら問題ありませんが、
この状態のままではサーバーを使った動作を行うことは出来ませんので
適切にコードを書き換えてください

Ruby on Rails チュートリアル(第四版)の1.5.2 Herokuにデプロイする (1)
ができなくて、色々試してネットの情報を色々見ました。
見た感想としては私と同じようにHerokuにデプロイできなかった人は
多かったように見えました。

色々試してみたところ、rails new で作ったフォルダの中で
git init や heroku createなどをしてgit push heroku masterをすれば
herokuにプッシュできることを確認しました。

これが本来の手順として正しいのかはわかりませんが
探したときにあまりもこれといった解決方法が見つからなかったので
のせておきます。


以下が作業手順となります

gem install rails -v 5.0.3
rails new hello_app
cd hello_app

gemfileの内容をリンク先のリスト1.4.4の内容に書き換え

application_controller.rbに以下のメソッドを追加
  def hello
    render html: "hello"
  end

config/routes.rbに以下の内容を追加

root "application#hello"

bundle install
この際に以下のようなエラーが出るかもしれませんが
私は面倒だったので、Gemfile.lockを消して解決しました。
Bundler could not find compatible versions for gem "activesupport":

gitの処理をする前に、

rails server -b $IP -p $PORT

を入力してきちんと起動するか確かめてください。
此処でエラーが出ると、この後pushしてもリジェクトされます。


あとは以下のコマンドを入力して
適切な処理をしてください。
なお、:~/workspace/hello_app の場所で
コマンドを入力するようにしてください

git init
git add .
git commit -m "init"
heroku login
heroku keys:add
heroku create
git push heroku master

これで恐らく通るはずです。
上手くいけば、以下のようなメッセージが出るはずです
remote: -----> Launching...
remote:        Released v5
remote:        https://□□□-△△△-××××.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/□□□-△△△-××××.git
 * [new branch]      master -> master

では、早速開いてみてください。
具体的にはReleased v5の下にあるURLです

ページを開いた際に画面に
Method Not Allowed
と表示される人はおそらく開いているURLが間違っています
間違っているURLはおそらく最後に.gitが付いているはずです。

正しいURLを開けば
hello
と表示されるはずです。

以上となります。
構築お疲れさまでした。

参考サイト
Ruby on Rails チュートリアル(第四版)
[Railsチュートリアル第1章] Herokuにデプロイ出来ない(一番下の回答)
HerokuにデプロイするとMethod Not Allowedが出力される


2017-09-02 到達点メモ


相変わらず、Evernoteの初回起動が重い。
ソフトウェアの方を試してみるべきか?

Railsチュートリアルをやっていてcloud9→bitbuketの接続に関するメモ
cloud9のユーザー画面に移動して、歯車アイコンをクリック。
SSH Keysという項目をクリックしてその中身をコピーする
bitbuketの人物アイコンのBitbuket Labsをクリック。
セキュリティの項目にSSH鍵があるので、そこで先程コピーした内容を
貼り付ける。

あと、remoteのアドレスが、httpのままだったので
それをgit remote set-url origin ssh_urlで変更する

参考サイト
オンラインIDE Cloud9を使ってみる その3
GitHubとBitbucketへの公開鍵の登録方法+SSHで複数鍵の使い分け
gitのリモートリポジトリoriginのURLを変更する

後で纏めてメモするよりは、少しづつやったほうが
無駄に開いているchromeのタブも消せて便利かもしれない。

Railsチュートリアルをやっていて初めてbranchの意味を理解できたかもしれない。
元々、git自体無計画に実装することを想定していなくて、
前もってこれを作ると決めてから、branchを作成してそこの中だけでうまくいくかどうかを調べる。で、問題が無ければ、masterにマージしてやればよい。
これなら、やってみて無理だと思ったらbranchを削除すればいいし、
branchを使っていて更にバグが発生するようになってもmasterには影響を与えない。
便利だこれ。前にAndroidで開発していて、前に戻りたい時とかバグが頻発しそうな微妙な実装をする際にこれをやればリスクが低くなりそう。

rails g が動かない時は spring stop をコマンド入力すること
参考サイトだと、bin/spring(多分アプリケーションの中のフォルダ内でコマンドを撃たないと意味が無い)を入力していたけど、みた感じだと中身を表示しているだけっぽい?

参考サイト
【Ruby On Rails】 「rails generate」が動かない

cloud9+Railsでherokuにpush出来ない問題。
workspaceの中にあるアプリ名のフォルダに
git init、git add,git commit,heroku create
とかしたうえで、git commit、git push heroku masterをやったら動いた
いろいろ重ねたうえでの行いなのでこれは流石にきちんと検証しないとまずい。
多分だが、DBの有無やbuildpack系のコマンドはこの件に限って言えば関係なさそう。


参考サイト
[Railsチュートリアル第1章] Herokuにデプロイ出来ない(一番下の回答)


あと、ページを開いたらMethod Not Allowedと表示されているときは
URLが.gitになっていないか確認をする。
要するに開いているページが間違っている

参考サイト
HerokuにデプロイするとMethod Not Allowedが出力される

検証中に、また変なエラーが出た
具体的にはrails gをしたら、
method_missing': undefined method `load_defaults' というエラー。
面倒だから、バージョン指定して作りなおしたけど
軽く調べた感じだと、自動生成の時点で発生しそう。

参考サイト
rails gしたら`method_missing': undefined method `load_defaults' ってエラー出た

検証したら、かなり凡ミスが多くててこずった。
rootをroutesと打ち間違えたり、
#と/を打ち間違えたりしてた。
というか、チュートリアル自体を進めたかったんだけど
結局一日がつぶれてしまった……。

2017年9月1日金曜日

2017-09-01 到達点メモ


前置き

Q1.これは何?
A1.今日やった作業メモです。Evernoteに書いたやつの転載です。割とそのまま載せるのでパッと見何やっているかわからないと思います。

Q2.どれくらい正確なの?
A2.とりあえず動けばいいの精神なのであまり参考にしないほうがいいと思います。

Q3.何で書くことにしたの?
A3.理由は三つ。一つ目は、何処かで見たブログで下手でも余り正確でなくてもいいから公開したほうがいいという風な意見を見て感心したので真似しようと思ったから。
二つ目は、やっている感を外部にわかりやすく示すため。三つ目は、Evernoteが重くて使い物にならない時がある為です。
------------------------------------------------------------------------------------

状況:自分用にソフトウェア開発のドキュメントをサポートするWebサービスを作っている。
何でRailsで作っているかというと今の手持ちの中で一番学習コストが低かったのが
Railsだったため。なお、公開の予定はないです。

Rails5.0.3の話です。


本当にRailsのやり方をど忘れしている
その上なんかいつの間にか知らない機能があるし……

正直そこは主題じゃないので、置いておくとして
has_manyとbelong_toでつながれたモデルは以下のような形で保存できるようになります
要は、has_manyにあたる親のテーブルを、子のテーブルにつないで(その際に、複数形にすることを忘れない事)
buildをかけると新規作成したのと同じような状態になり
その後で親のテーブルをsaveで保存すると
このテーブルも保存したのと同じ状態になります。


  @project = Project.new(project_params)
  worker = @project.workers.build
  worker.name = @project.developer
  worker.name = "開発者" if @project.developer.blank?
  worker.is_project_member = true
  screen = @project.screens.build
  screen.name = "その他"
  respond_to do |format|
           if @project.save 
                format.html { redirect_to @project, notice: 'Project was successfully created.' }
                format.json { render :show, status: :created, location: @project }
  else
       format.html { render :new }
       format.json { render json: @project.errors, status: :unprocessable_entity }
           end
  end

こんなことも忘れてたんだよなぁ(白目)

どこでも値を保持できるようにしたかったので
最初はsessionを使おうかと思ったが、
本当にuser_idぐらいしか使えないみたいなので
素直にグローバル変数を使う事に。

グローバル変数でIDが構造が同じなのに
一部の場所だけエラーの表示のパラメーターでが
本来代入されているパラメーターがnilってなっているときは
変数が間違っていないか疑おう
じゃないと一人でオカシイオカシイとわめく羽目になります。

何故か値が更新されないのでグローバル変数を使っていたせいかと思っていたが全然違った。

×間違い
  @@project_id = $project_id
  def index
       @project_id = @@project_id
       @screens = Screen.where(project_id: @@project_id)
  end


〇正しい
  def index
       @@project_id = $project_id
       @project_id = @@project_id
       @screens = Screen.where(project_id: @@project_id)
  end

メソッド外で宣言すると、一回だけしか呼ばれないみたいで
その為に値が更新されなかったようである。
いや、これも当たり前なはずなんですけど(最初の頃間違いの方法で初期化処理やってたし)
普通頭からすっぽ抜けてたんですよね……

一度、真面目にRailsチュートリアルをやるべきな気がする。
Railsを極めたいわけじゃないんだけど、結局急げば回れのような気がする……

Vector画像でタブレット端末の対応の設定したけれども、最適化のヒントで対応していないと言われたら問い合わせをしよう


今回、VoiceTimerを使って設定した際に割と苦労したところです。

エラー内容は、【APK には一般的なタブレット画面密度に合わせたカスタムのドローアブルとアセットが含まれていること】でした。

ちなみに私の場合の対処方法は、vector画像をxmlに変換したファイルを
下記のように編集しました。具体的には、heightとwidthの値の部分を
dimenに置き換えました。

<vector
    android:height="@dimen/gear_icon_size"
    android:width="@dimen/gear_icon_size"

その後、dimen.xmlでそれぞれ解像度ごとにファイルを作り、
公式ドキュメントのガイドライン(4. タブレット画面向けに設計されたアセットを使用する)に従ってそれぞれの解像度に適した値を読み込むようにしました。
他にも細かい所を設定した気がしますが、大まかにはこの処理をした後に
apkをアップロードしました。

この状態でも、タブレット端末が非対応の扱いになっていたので
GooglePlayConsoleのヘルプの部分からメールでお問い合わせをし
そのあとにグーグルの方から、以下のアドレスに連絡するように
アナウンスを受けたのでそれに基づいて連絡しました。
https://support.google.com/googleplay/android-developer/contact/tabletq?hl=ja

幸い問題なかったようで大体二日ぐらいで返事が返ってきて
1~3日の営業時間内に対応してくれるとの事でした。

という訳でどう見てもタブレット端末に対応しているはずなんだけど、
タブレット対応してないと言われるという人は
グーグルさんにお問い合わせをしてみよう。

メモしていなかったので忘れてしまったのだが
私と同じように問い合わせをした人をネットで見つけました。