ねこトラッカー3.0.0
2015/04/26 22:32:38Noranekoです。
そんで、ねこトラッカーを更新しました。
トラッキング中にバックグラウンドにして、ナビとか重い処理のアプリを動かしたりして、
テストしましたが大丈夫そうです。
Activityが死んでも復旧ロジックを入れてあるので、
ちゃんとトラッキングの開始から現在のトラッキングまで見れるようになっています。
実はデバッグでちゃんと動いてても、リリース用コンパイルで動かなくて困ってました。
いやほんと社畜やってた時もこの本番でしか出ないバグって言うのは、
想定外すぎて当たりがつけづらく、ログから辿るしかないですね。
ということで、なんとかゴールデンウィークに間に合いました。
大昔に書いたかもしれませんが、圏外でもトラッキングは可能なので、
旅行に行った際に『肉球アイコン』を押して、『バックグラウンド』するだけで
行った場所を記録できます。
※建物とかトンネルなどのGPSが届かないところは記録できません。
てことで来月くらいに現在のトラッキングを共有できる機能を
アップデートしたいと思っております!
サーバ死ぬかな・・・
気に入ったら押してね
~こんなアプリ出してます~
AndroidのServiceについて
2015/04/25 23:50:32Noranekoです。
『これから英語は必要だ!』とか、
『これからは国際社会、海外に目を向けろ!』とか言う人に限って、
海外滞在とか全くなくて、パスポートすら持ってないのが現実だょ^ω^
でファストフードマスターの私に言わせれば、
IN-N-OUTしか認めません!
今秋に『Carl's Jr.』も来るみたいだけど、また行列するんだろうな・・・
でもCarl's Jr.はメニューが多くて、LAで滞在してた近くにあったので、
しょっちゅう行ってました^ω^
一応タバコと比較してます。
ということで、アメリカのファストフードとかのお話はまた今度にしましょう。
前回のお話の続きになります。
バックグラウンドで常駐させたい
↓
いつのまにか死んでる
↓
Serviceにすればいいよ!
と、ここまで理解してて、その後サンプルソースから大改造してみました。
できました。
重要なところをまとめてみます。
①Activity等からServiceを起動させる為にAIDLを作成する。
②Serviceからの戻り値をBroadcastReceiverで取得する。
③BroadcastReceiverからさらにActivityへ値を戻す。
①について、前回ほんのり書いてますが、
ActivityからServiceを独立させて呼び出す為に、AIDLファイルという物を作って
そこからServiceを呼びます。
下準備として、
MainService.java
public class MainService extends Service{
}
}
IService.aidl
interface IService {
}
}
AndroidManifest.xml
<service android:name=".MainService">
<intent-filter>
<action android:name="net.hoge.IService" />
</intent-filter>
</service>
<intent-filter>
<action android:name="net.hoge.IService" />
</intent-filter>
</service>
自分の目的では、Activityが死んでもServiceを継続させたい為、
『onStartCommand』を使います。
直接使えないので、下記のようにします。
public class Hoge extends Activity{
public void test(){
// Serviceを実行
Intent intent = new Intent(IService.class.getName());
startService(intent);
}
}
public void test(){
// Serviceを実行
Intent intent = new Intent(IService.class.getName());
startService(intent);
}
}
もう一つのやり方は、
『ServiceConnection』を用いて、『bindService』を使うやり方です。
public class Hoge extends Activity{
private IService service = null;
private ServiceConnection con = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = IService.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName className) {
}
 };
 public void test(){
  // サービス実行
  Intent intent = new Intent(IService.class.getName());
  // バインド
  bindService(intent, con, Service.BIND_AUTO_CREATE);
 }
}
private IService service = null;
private ServiceConnection con = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = IService.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName className) {
}
 };
 public void test(){
  // サービス実行
  Intent intent = new Intent(IService.class.getName());
  // バインド
  bindService(intent, con, Service.BIND_AUTO_CREATE);
 }
}
後者は、Activityが死ぬとServiceも死んでしまいます。
ただ、サービスのいろいろなメソッドにアクセスできるので、
前者とは異なる使い方が可能です。
多分ここまでで???の方も多いと思いますが、
実行したいサービス(MainService.java)
と
実行したいサービスを起動するためのインターフェイス(IService.aidl)
があって、Activityから2パターンの呼び出しが可能で、
呼び出し方によりできることとできないことに分かれます。
うむ。
これは難しい。
とりあえず先に進もう。
②について、これは①の後者を選択してバインドした人には
あまり意味がないのかもしれません。
public class MainReceiver extends BroadcastReceiver{
}
}
MainReceiver.java
<receiver
android:name=".MainReceiver"
android:exported="false">
< /receiver>
AndroidManifest.xml
例によってこれを前提とします。
先程の①の前者を
public class Hoge extends Activity{
private MainReceiver receiver = null;
public void test(){
// Serviceを実行
Intent intent = new Intent(IService.class.getName());
startService(intent);
// レシーバ―登録
IntentFilter filter = new IntentFilter("hoge");
receiver = new MainReceiver();
registerReceiver(receiver, filter);
}
}
private MainReceiver receiver = null;
public void test(){
// Serviceを実行
Intent intent = new Intent(IService.class.getName());
startService(intent);
// レシーバ―登録
IntentFilter filter = new IntentFilter("hoge");
receiver = new MainReceiver();
registerReceiver(receiver, filter);
}
}
これだけです。
次に、MainServiceの何かを返すメソッドに
public void payBack(){
Intent intent = new Intent("hoge");
intent.putExtra("test", "test");
intent.putExtra("suji", 99);
sendBroadcast(intent);
}
Intent intent = new Intent("hoge");
intent.putExtra("test", "test");
intent.putExtra("suji", 99);
sendBroadcast(intent);
}
最後にMainReceiverに
public class MainReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent){
// 値を取得
String s = intent.getStringExtra("test")
int i = intent.getIntExtra("suji", 0)
System.out.println("this is broadcast @" + s + "@" + String.valueOf(i));
}
}
public void onReceive(Context context, Intent intent){
// 値を取得
String s = intent.getStringExtra("test")
int i = intent.getIntExtra("suji", 0)
System.out.println("this is broadcast @" + s + "@" + String.valueOf(i));
}
}
比較的わかりやすいですね。
③ここで悩みました。みんな②でToastで表示して終了が多いです!
ではなくて、私みたいにActivityに返したい人の方が多いはずです!
で、どっかのブログがひっかかり、無事、事なきを得ました。
先程のMainReceiverを改造します。
public class MainReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent){
// コンテキストを取得
HogeActivity activity = (HogeActivity) context;
// メソッドに渡す
activity.getValue(
intent.getStringExtra("test"),
intent.getIntExtra("suji", 0)
)
}
}
public void onReceive(Context context, Intent intent){
// コンテキストを取得
HogeActivity activity = (HogeActivity) context;
// メソッドに渡す
activity.getValue(
intent.getStringExtra("test"),
intent.getIntExtra("suji", 0)
)
}
}
なるほど。
流れを掴めば理解できると思いますが、やりたいこと以外の情報が多すぎるのと、
その先の情報がぶちぶち切れてて、結構時間がかかりました。
またServiceは生きたままでActivityが死んで、
再度アプリを立ち上げた際のロジックも考えて作らないと、
データに不整合が出る可能性もあるので、
結構頭を使います。
てことでちょっとテストしてみて、大丈夫ならGW中に更新したいと思っております!
気に入ったら押してね
~こんなアプリ出してます~
ZenFone 2 ~後記~
2015/04/21 12:52:23Noranekoですぅ。
結局日本でのラインナップは、
http://shop.asus.co.jp/zenfone/list/ZenFone%202/
台湾でのラインナップ
http://www.asus.com/tw/Phones/ZenFone_Products/
私が注目してた、ZE500CLが見事にありませんね。
それよりも何も、urlにスペースを使うとか
ZenFone 5の時もそうでしたが、日本の正規販売だと下位機種は販売されません。
悲しいですね。
一応amazonには存在してますね。
ASUS ZenFone 2 ZE500CL 2GB RAM 16GB ROM (5inch/4G LTE) [並行輸入品] (White ホワイト 白) 新品価格¥27,200から(2015/4/21 12:25時点) |
正直、5.5インチの携帯自体がスマートじゃないです。
5インチでもゆるされないレベルです。
小さいAndroid出して欲しぃ・・・
SO-03C、SO-05Dという手にフィットする後継機まだか・・・
|
|
【価格.com中古携帯プラザ】
で中古を物色・・・。
携帯の解像度なんて800*480、メモリ1GB、速度なんかも3Gで十分なんですよ。
ということで、
Studio nekoが厳選した結果、
priori2
freetel フリーテル SIMフリー スマートフォン priori2 (Android 4.4.2/4.5inch/標準・micro SIM/ホワイト)FT142A-Pr2-WH 新品価格¥10,778から(2015/4/21 12:40時点) |
圧倒的なコストパフォーマンス!
バッテリ取外し可能、更に!予備電池も販売してます。
メールとナビができるデバイスが1万円で手に入ります!!
これの初代だと標準でルートが取れてる状態だったとか、オープンすぎる。
とりあえず今の携帯が完全に死ぬまで使い込みたいと思っております。
気に入ったら押してね
~こんなアプリ出してます~
ねこトラッカー2.0.1
2015/04/18 20:34:19Noranekoです。
最近、Bライフブログ読んでます。
大昔、会社で暇でネット漁りしてる時に出会ったデイリーポータル Z以来のヒットで面白いです。
非常に人間らしい生き方をしてて良いと思います。
斯く言う私も昔から
『Work to Live』
という考えがあるので、
金額計算して割に合う残業はしてたけど、基本残業はしませんでしたね。
残業するより、知り合いから仕事もらってやった方がお金が良かったり、
プログラマという職業上、いろんな言語をやった人の方が遥かに優位なので、
会社でMS系、帰宅後にOpen系ということもやったりしてたので、
ほんと幅広くいろんな言語を触ってきたと思います。
ということで、ねこトラッカーを更新しました。
前回、googleマップへのリンクを入れましたが、
消しました!
私の持ってるメモリが少ない2.3.4端末だと、googleマップを立ち上げていろいろすると
ねこトラッカーがバックグラウンドで死んでしまっていました。
これはちょっと痛かったので、今回のでリンクを消させていただきました。
それとは別に、タスクバーへの通知(常駐型)を入れて、
ねこトラッカーへ簡単に戻れるようにしてみました。
が、はやり何かのきっかけで死んでしまうことがあります。
ですので、
調べてみたのですが、どうやらServiceという物を作って常駐させないとダメみたいです。
今回のバージョンで、通知を出したのですが
// NotificationBuilderを作成
NotificationCompat.Builder nc =
new NotificationCompat.Builder(this);
bla bla bla
// 通知する
NotificationManager nfm =
(NotificationManager)getSystemService(Service.NOTIFICATION_SERVICE);
nfm.notify(4649, nc.build());
↓
startForeground(4649, nc.build());
こんな感じにstartForegroundでやれば行けるみたいです。
が、私の今のやり方だと地図表示と現在地取得ロジックが同じクラスでかつ、
extends FragmentActivity
されております。
このstartForegroundするには、
extends Service
しなくてはいけません!
なんてこったい・・・
大規模仕様変更余儀なしですね。
今考えてるのが、現在地取得のところをServiceクラスで持たせて、
DB処理もここで呼んでやろうかなと。
そんで、Activityが死んでトラッキングをしていた場合、
今動いてるトラッキングServiceがあるかどうかの判別をして、
地図にトラッキング情報を再表示しなくてはいけませんね。
どこかに同Serviceは複数呼べない?みたいなことを書いてあったので対策はできるのかなと。
というかこの常駐方法としては、
①Serviceクラスを用いて、startForegroundする
②AIDLを用いてServiceと連携
という方法があるらしいです。
②をちょっと書いてみたけど理解しないままコピペしたので、よくわかんないので消しました。
が、
AIDLの消し方がよくわかんなくてエラーが出てコンパイルできなくなりました。
binの中にあるやつを消して再起動したらいけた気がします。
ということで次のアップデートは常駐を目標にします。
てか常駐型の通知出してて、onDestroy()通らないで死ぬってことに問題があるようなないような・・・
気に入ったら押してね
~こんなアプリ出してます~
ねこトラッカー2.0
2015/04/11 17:43:33なってねぇええええ!
めっちゃ寒いわ。
ということで、ねこトラッカーを更新しました。
A-GPS対応とGoogle Mapsへのリンクを追加です。
本当は、ナビ画面にしたかったのですが、
Android 2.3.4で不具合が発生したため、Mapsへのリンクにしました。
それで今回のGoogle Mapsへのリンクの仕方というか、
Google Mapsの起動の仕方はこちらに載ってました。
Android特有(?)のIntentを用います。
載ってるサンプルをコピって使えますね。
Uri gmmIntentUri = Uri.parse("geo:緯度,経度");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
下の方にはナビとストリートビューの立ち上げ方も書いてありますね。
2.3.4では上記のパラメータとしてzoomを追加しただけでエラーになりました。
そろそろ私のAndroidちゃんも限界がきてるので、
買い換えたら2.3.4への対応は切ろうかなと思っております。
気に入ったら押してね
~こんなアプリ出してます~