AsyncTaskの非同期処理を制御(終了をコールバック)してくれるCountDownLatchクラスについてメモ
AsyncTaskの複数実行する場合に、全ての非同期処理がすべて終了したら何らかの処理を行う場合、
インターフェイス(リスナー)で自力で行うことも可能であるが、タスクの制御をしてくれるCountDownLatchを使うと簡単に実装できる。
CountDownLatchは指定した非同期処理数を実行する非同期処理でカウントを減算して、指定数を消化したかどうかを判定することができるハンドリング用のクラスとなる。
実装方法
例として、複数のAsyncTask(今回はTestTaskとする)を実行し、実行中にプログレスバーを表示、
すべて完了時にプログレスバーを終了するサンプルコードを示す
private class ControlTask extends AsyncTask<Void, Void, Boolean>{ // テストタスクのカウント数を引数に指定 ※テストで3つ実施 CountDownLatch _latch = new CountDownLatch(3); @Override protected void onPreExecute() { super.onPreExecute(); // プログレス表示処理 } @Override protected Boolean doInBackground(Void... params) { try { // テストタスク実行 ※3つ new TestTask().execute(); new TestTask().execute(); new TestTask().execute(); _latch.await(10,TimeUnit.SECONDS); return true; } catch (InterruptedException e) { e.printStackTrace(); } return false; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); // プログレス終了処理 } } private class TestTask extends AsyncTask<Void, Void, Boolean>{ CountDownLatch _latch; public TestTask(CountDownLatch latch){ _latch = latch; } @Override protected Boolean doInBackground(Void... params) { // なんらかのバックグラウンド処理 return true; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); if(result){ if(_latch != null) _latch.countDown(); } } }
ControlTaskのCountDownLatchインスタンス生成時のコンストラクタの指定で非同期処理の実行数を指定
CountDownLatch _latch = new CountDownLatch(3);
ControlTaskのdoInBackgroundでTestTask非同期処理を上記で指定した数分実行させる。
このときにCountDownLatchのインスタンス変数を引数で渡す。※オブジェクトなので参照渡しとなる(厳密には語弊があるけど。)
各非同期処理ないではonPostExecuteで終了時にCountDownLatchのcountDownメソッドでカウントを減算させる。
_latch.countDown();
countDownの減算で、コンストラクタで指定した実行数を網羅したときに
CountDownLatchのawaitメソッドで完了し次に進むという流れになる
_latch.await(10,TimeUnit.SECONDS);
※このときawait()でも良いが上記指定の場合、完了しなくても最大10秒で次の処理に進む。念のため入れたほうが安心。
アプリ内課金テスト時の注意点についてメモ
アプリ内課金の動作テストを行った時に、つまづいたのでメモ
まず前回まで動作していたアプリ内課金を、アカウントなど新規作成し、移行をして、課金テストを行うとうまく動作しなかった。
googleのアプリ内課金の仕様がどうやら変わったとの事。
参考ページ ※だいたいこのサイトに助けてもらいました
http://gadget-f.hateblo.jp/entry/2014/08/24/192301
アプリをベータ版で公開にする
前回まではベータ版のドラフト状態で、テストができていたが、現在は出来ないようで、ベータ版にして公開まで行わないとテストができない。
そのため、アプリ公開時に必要な、アイコン画像等いくつか設定しないといけないように変わっている。
これは探した限りヘルプなどにも書いていないので注意が必要。ドラフト状態でテストを行うと、アプリの課金情報の取得がまずできないので、購入フローまでたどり着けない。
テストアカウントを作成してからテスト
テスト時はテストアカウントをgoogleデベロッパーコンソールから設定する必要がある。
そして、設定して反映にタイムラグがあり、直に反映されないことに注意が必要。本日試した結果30分はかかった。
反映された場合はgoogleの購入時ダイアログで「これはテスト用の注文です。実際の課金は発生しません」という文言が絶対にでるはずなので、出ていない場合は、まだ反映していないか、メールアカウントに誤りが無いか確認が必要。
反映していない状態の場合には、購入金額の請求がきてしまうので注意。
ソーシャルタイマー 〜 SNS予約投稿 〜
Google Playにアプリをリリースしました
https://play.google.com/store/apps/details?id=to.developer.socialtimer
アプリ詳細
Facebook/Twitterの予約投稿アプリ
機能:
•Facebook/Twitterの同時投稿 又は 対象snsのみが可能
•予約数に上限はなし
•写真1枚/コメントの時刻指定投稿が可能
•投稿時はノティフィケーションで通知
•端末自身で投稿 ※サーバを介さない
セキュリティ:
端末自身で投稿をするため、トークンや各種情報をサーバに送信しない
ためセキュリティ面で安全
注意:
端末自身で投稿するため、予約時刻の時点で端末の電源が入っている必要がある。
文字制限や連続投稿などの仕様は各種snsの仕様通りとなる。
例えば下記はアプリの仕様上判断できないためそのままスルーする。
- Twitterの場合、同じ内容の投稿は拒否される
- Facebookの場合、連続投稿を行うとタイムラインに反映しない場合がある
https://play.google.com/store/apps/details?id=to.developer.socialtimer
別プロセスでSharedPreferencesを参照する場合の更新情報取得方法についてメモ
SharedPreferencesを使いServiceで登録してActivityで開くや、その逆等の場合プロセスが違う事が原因か、最新情報を読み取れない事がある。
検証すると、読み込めるときもあるが違いがわからなかった。ただ実際のSharedPreferencesの中身は反映しているが、取得時にうまく取得できない、または前の情報を読み取るなどが見受けられたため、対応方法をメモする。
対応策
読み取るときにContext.MODE_MULTI_PROCESSを付ける事で解決する
context.getSharedPreferences(PREFERENCE_NAME,Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
http://developer.android.com/reference/android/content/Context.html#MODE_MULTI_PROCESS
検証する限り、その他バグ等はいまのところ見当たらないため、これで良いと思う
実機のdata/dataに保存したファイルを取得する方法をメモ
data/dataの中身を参照する事はadbのrun-asコマンドで可能だが、ファイル自体をローカルPCへpull取得する方法が結構微妙なのでメモ。
中身を参照はcatコマンドなどで参照できるのでいいが、sqliteのDBファイルの場合、中身をcatで見てもよくわからないので、ローカルに取得したくなる。
中身を確認する方法はこちら参照
adb pullコマンドについて
まずdata/dataでない場合はpullコマンドを使う事で簡単に取得できる
adb pull [端末上のファイル名] [PCのファイル名]
ただ権限がないユーザのためdata/dataのデータをpullすることはできない。そのため権限のあるsuと同様なrun-asで権限のあるユーザに切り替えることで参照まで可能。ただこの場合もまだデータをpullはできない。
そのため一度pull可能な場所にファイルを移動コピーする事でpullを実行すると良い。adbではcpコマンドは使えないためファイルの中身を参照してその値を別ファイル(pullできる場所)へ書き出すという方法が良い。
data/dataのファイルを取得する方法
まずはファイルをdata/dataからpullできる場所へファイル移動 ※ファイル書き出し
adb -d shell "run-as [パッケージ名] cat [カレントから取得したいファイル名] > /sdcard/test"
”adb shell” コマンドでアクセスした後に実行しても良いが、adbの[-d]オプションを付ける事で端末にコマンドを直接送る事ができる。
”run-as” コマンドで次に権限を取得。そしてファイルの中身をcatコマンドで取得し リダイレクト[>]でファイルに書き込みすれば完了。
今回はsdcard/内のtestファイル(新規作成)を出力先に指定している。
※ [カレントから取得したいファイル名] は data/data/[パッケージ名]/ の直下のファイル指定を絶対パス指定で行うこと
端末内の全パッケージ名取得
pm list packages
※adb shellでアクセスしてること
あとはpullして完了
adb pull /sdcard/test .
これを使ってメリットがあるのはdbファイルかプレファレンスファイル。
後この方法で取得できるのはデバッグモードのapkのみなのでリリース版では無理。
antでビルドをしたときにでたエラーについてメモ
antを使用してビルドをしてみるとデバッグ版はうまく生成されるが、
リリース版が「Cannot recover key」エラーで改善されなかったため、忘れないようにメモ。
エラーまでの手順
1.keystoreファイルを作成する
keytool -genkey -v -keystore ~/test.keystore -alias test -validity 10000
※組織名等指示に従いすべて入力するパスワードはキーストア、エイリアス共に「password」として設定しておく
2.ant.propertiesファイルへ下記を記載
key.store=test.keystore key.store.password=password key.alias=test key.alias.password=password
3.ant release コマンド実行でエラー
BUILD FAILED android-sdks/tools/ant/build.xml:1139: The following error occurred while executing this line: android-sdks/tools/ant/build.xml:1151: Cannot recover key
ここでエラーがでてしまう
エラー改善
build.xmlで起きる「Cannot recover key」はant.propertiesの設定が間違えている場合に起きる
つまりパスワードあたりが間違えているはず。
ただ今回の原因は半角スペースが入っていた事が原因だった・・・
良くあるミスだけどまた起きたらこわいので一応メモ。。。
Android開発のgitignoreついてメモ
.gitignoreの設定をすぐに移行できるように残しておく
※環境はMAC OS でも Windowsでも不要なものは排除しておく
.gitignore
# Mac不要ファイル .DS_Store # Windows不要ファイル Thumbs.db # Java class files *.class # built application files *.apk *.ap_ # files for the dex VM *.dex # generated files bin/ gen/ # Local configuration file (sdk path, etc) local.properties # eclipse settings .classpath .project .settings/
.gitignoreをプロジェクトへ反映
.gitignoreはアカウント直下に設定しておく事とする
git config --global core.excludesfile $HOME/.gitignore
MACでフィンガープリントを取得する方法をメモ
Google Maps API V2を使用するときにSHA1が必要になるため取り方を忘れないようにメモ
フィンガープリントを取得
keystoreから取得
keytool -v -list -keystore ~/.android/debug.keystore
apkファイルから取得
keytool -list -printcert -jarfile app.apk
パスワードは指定なしでエンターで表示される。
文字化けしたらshift-jisあたりに変更すると良い。
※フィンガープリント番号は文字化けしないので問題ないかも
Google play ServiceでGoogle mapを使用するときにでたエラー解決法をメモ
「Google Maps APIの基本」を説明してくれているサイトを参考に作成していると例外が発生したので解決法。
http://codezine.jp/article/detail/7440
java.lang.IllegalStateException: The meta-data tag in your app's AndroidManifest.xml does not have the right value. Expected 4030500 but found 0. You must have the following declaration within the <application> element: <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
meta-dataの定義をマニフェストファイルに追加する
Google Play Servicesのどこかのバージョンから以下を追加しないといけなくなった模様。
上記のエラーに書いてある通りに「You must have the following declaration within the」(必要な宣言がたりないよ)とでているのでその通りに追加してあげると良い
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
Androidでサービスからダイアログを表示する方法をメモ
AlertDialogでサービスからは、アクティビティから呼び出すような呼び方でダイアログを表示することはできない。実行するとエラーとなる。
例えば、GCMのプッシュ処理でプッシュをキャッチするのはAndroidのサービスになる。このときにユーザにキャッチした事を知らせるダイアログを表示する時など、サービスからダイアログを表示する用途は多々ある。
サービスから実行できないのはAndroidの仕様で、ダイアログを表示する場合にはActivityのContextを使用しなければいけない。なので、呼び方に工夫が必要となる。
サービスからActivityを呼び出し、呼び出されたActivity内でダイアログを表示する作りとすれば解決する。
ダイアログ表示用のActivityを用意する
まずはダイアログを呼び出すActivityを作成する
import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; public class CallDialogActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Title").setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); finish(); } }); AlertDialog alert = builder.create(); alert.show(); } }
マニフェストへActivityを設定
マニフェストファイルへActivityを設定する。このときlaunchModeはsingleInstanceとしておくと良い。
これはActivityがバックで動作している場合(ホームボタン押下してアプリをバックにした)に、ダイアログを呼び出した場合、現在バックで保持されているActivityが表示され、その上にダイアログが表示される状態になる。挙動としてダイアログのみを表示したい場合にはsingleInstanceとしておく。
<activity android:name="CallDialogActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar" android:launchMode="singleInstance"> </activity>
サービスからActivityを呼ぶ
あとはサービス内からActivityを呼び出す事で完了。
intentにはFLAG_ACTIVITY_NEW_TASK、Intent.FLAG_ACTIVITY_CLEAR_TOPを付加しておく。
FLAG_ACTIVITY_NEW_TASK:タスクがスタックに存在しても新しいタスクとして起動
FLAG_ACTIVITY_CLEAR_TOP:スタックをクリアしてからActivityを起動
参考:http://it-trick-java.appspot.com/android/c9001/page7151.html
例)今回はGCMのonMessage(サーバからpush実行時に呼び出し)で処理を実行する。
@Override protected void onMessage(Context context, Intent intent) { // ポップアップダイアログ表示(pushキャッチ時) Intent i = new Intent(context,CallDialogActivity.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); context.startActivity(i); }
ちょっと面倒だけど、これでダイアログがサービスから呼び出す事が可能
実機デバッグでdata/dataの中身を確認する手順をメモ
エミュレータの場合はDDMSで確認できるが実機の場合確認する事が出来ないので方法をメモ
※端末によりアクセスできない端末もある
android付属のshellを使用する
•接続
adb shell
•パッケージフォルダの中身にアクセス
run-as [パッケージディレクトリ指定]
上記の実行でディレクトリを確認できる。
あとは通常のshell同様にlsコマンドでディレクトリ中身確認、cdコマンドで移動が可能
Android端末のインストールしているapkファイルを取得する方法をメモ
sdkに組み込まれているadb.exeを使う
APKファイル取得方法
1. 端末をUSBデバッグモードにする
2. 端末をUSBで接続する
3. APKファイルパスを取得
adb shell pm list packages -f | grep [パッケージ名一部でよい]
4. APKファイル取得
adb pull [上記取得したパッケージpath]
端末全体のシステムログを取得するためのコードをメモ
システムログを取得するためにはマニフェストファイルにandroid.permission.READ_LOGSパーミッションが必要
端末内のインストールされている標準出力のログも出力するため、アンドロイドのセキュリティチェックに使える
アプリを作るときも標準出力が読み取られることをセキュリティとして知っとく必要あり
try { Process process = Runtime.getRuntime().exec("logcat"); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line = reader.readLine(); //1出力毎にループ while(line != null) { } } catch (Exception e) {}
Androidの各アプリに割り当てるヒープ領域を拡大する方法をメモ
androidで各アプリが割り当てられているメモリ(ヒープ領域)は端末により違いがあるが、3.0(ハニカム)以降のバージョンの場合、最大割当領域を上げる事が可能 ※これも端末により最大領域は違う
Androidはとりあえずメモリが低く、画像やカメラを使うと落ちるのでとりあえず設定しておいたほうがよさそう。
最大割当メモリ量を拡大する
Manifestファイルのapplicationタグ内で「android:largeHeap」をtrueにする
android:largeHeap="true"
最大メモリ量を確認する方法
ActivityManager am = ((ActivityManager)getSystemService(Activity.ACTIVITY_SERVICE)); int largeMemory = am.getLargeMemoryClass();
メモリの確認
adbシェルコマンドで確認可能
メモリ全体表示
adb shell procrank
VSS(Virtual Set Size) 仮想メモリの消費量
RSS(Resident Set Size) 物理メモリの消費量
PSS(Proportional Set Size) プロセスのヒープ所有サイズ
USS(Unique Set Size) プロセスのヒープ利用サイズ
メモリ詳細表示
adb shell dumpsys meminfo パッケージ名
ActivityA,B間でA画面からB画面を立ち上げB画面をfinish()しA画面を再読み込みする方法をメモ
いままではA画面からB画面を立ち上げるときにA画面をfinish()してB画面からA画面を改めて呼んでいたけど、
こんな非効率じゃない方法があった。
onRestort()メソッドで再読み込みメソッドreload()をコール
public void reload() { Intent intent = getIntent(); overridePendingTransition(0, 0); intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); finish(); overridePendingTransition(0, 0); startActivity(intent); }
coffee-break
Don't write code that useless.
1日5杯はコーヒー、カフェオレ飲みます。狭心症のため安静にします☆松本 雄貴
Kotlinでサービスリリース目指す!
iOSでチャットアプリ作成中。自然言語解析LSIを習得中
Mac / Android・iOS / Rails / Oracle
2017年 Lpic L2取得
2012年 Android技術者資格取得
2010年 OracleMasterGold10g取得
2008年 CCNAQiitaもたまに投稿
https://qiita.com/y-matsumoto東京近郊で常駐開発探してる方はこちらよりご連絡ください
SES企業でパートナー会社を探している企業様はこちらよりご連絡ください
スプリットカメラ iOS / Android
音声認識で聞いた日付から曜日当てアプリ Android
ソーシャルタイマー Android
カテゴリー
- ActiveRecord (2)
- Android (52)
- AndroidStudio (10)
- Ansible (1)
- AWS (1)
- Bash (18)
- Blog (7)
- BootStrap (1)
- CentOS (16)
- Chef (1)
- css (2)
- Eclipse (5)
- error (1)
- Facebook (2)
- Firebase (1)
- FuelPHP (16)
- Git (22)
- GitHub (3)
- Gradle (2)
- GraphAPI (1)
- Grunt (1)
- heroku (2)
- illustrator (1)
- iOS (17)
- Java (4)
- Jenkins (1)
- jQuery (3)
- Kotlin (2)
- Mac (22)
- nginx (1)
- Node.js (3)
- peco (1)
- php (5)
- Python (1)
- Rails (16)
- Ruby (11)
- shell (1)
- SNS (1)
- Swift (2)
- tmux (2)
- Vagrant (6)
- Vim (6)
- windows (2)
- WordPress (3)
- zsh (4)
- フリーランス (1)
- ライブラリ (1)
- 勉強会 (2)
- 宣伝 (1)
- 未分類 (2)
最近の投稿
- [MAC]HighSierraでgitプッシュエラー「Unable to negotiate with xxx.xxx.xxx.xxx port xx: no matching cipher found. Their offer: aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se fatal: Could not read from remote repository.」
- [iOS]iOS11からFacebook,Twitter連携(シェアなど)廃止の対応方法
- [iOS]速報2017AppleSpecialEventのiOS11、iPhone8など発表内容について
- [iOS][Firebase]The default Firebase app has not yet been configured. Add `[FIRApp configure];
- [iOS]2017年9月リリースのiOS11で開発者が対応するべきこと
- 今人気の現金化サービスCASH(キャッシュ)を使ったレビュー
- [Pandoc][Mac]pandocでmarkdownからwordファイル作成
- [Android]映画サマーウォーズの聞いた日付(誕生日)から曜日当てをアプリ音声認識で簡単に実現
- [Android]起動しているActivityを取得するadb shell コマンド
- [Android][Kotlin]kotlin学習で参考になるサイト一覧
2024年4月 月 火 水 木 金 土 日 « 5月 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 アーカイブ
- 2018年5月
- 2017年9月
- 2017年8月
- 2017年7月
- 2017年6月
- 2017年5月
- 2017年2月
- 2017年1月
- 2016年12月
- 2016年7月
- 2016年6月
- 2016年1月
- 2015年12月
- 2015年11月
- 2015年10月
- 2015年9月
- 2015年8月
- 2015年7月
- 2015年6月
- 2015年5月
- 2015年4月
- 2015年3月
- 2015年2月
- 2015年1月
- 2014年12月
- 2014年11月
- 2014年6月
- 2014年5月
- 2014年4月
- 2014年3月
- 2014年2月
- 2014年1月
- 2013年12月
- 2013年11月
- 2013年9月
- 2013年8月
- 2013年7月
- 2013年6月
- 2013年5月
- 2013年4月
- 2013年3月
- 2013年2月
- 2013年1月
- 2012年12月
- 2012年10月
- 2012年5月
- 2010年6月
エントリ