まちがいだらけ

スマホやガジェットについて、android開発メモ、その他メモなど。

AccountManagerに登録するアプリで、設定アプリに設定項目を表示させる時の注意

Androidで、他のアプリとかにアカウントを使って欲しい時に、
AccountManagerを使うと思います。

そのためにはAbstractAccountAuthenticatorを実装したりmanifestに宣言したりしますが、、
tappli blog: [Android] アカウント管理を行う


詳しい話は他の人に任せます。
すみません。


それでauthenticator.xmlなどでaccountPreferenceの項目にxmlリソースを設定することで設定アプリ(com.android.settings)に設定画面を表示させることができます。
f:id:wasnot:20140704134423p:plain
でもその指定するxmlリソースは普通のpreferenceをxmlに書くよりすこし注意が必要だったので自分用にメモします。



注意点

  • keyを設定してCheckBoxPreferenceを指定したりしても、設定アプリのpreferenceに保存されるので参照できない
  • ちなみにListPreferenceをつかうとタップした後クラッシュしたりするらしい

android - Account preferences crashes on ListPreference - Stack Overflow

  • なので基本的にintentタグで自分の知ってるアプリなどにIntentを飛ばして、そのActivityなりで設定変更してもらう。つまりリンクを置ける場所。
  • intentタグを含むPreferenceScreenをPreferenceCattegoryの中に置いたりすると

 Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
 って怒られる。
 なのでCategoryは同一階層に何も入れずに並べる
android - PreferenceScreen - <intent .../> - Exception - FLAG_ACTIVITY_NEW_TASK - Stack Overflow

  • key使えないんだからkey入れなくていいだろ!とか思って抜いていたら、PreferenceScreenのTitleに設定アプリのテーマが適応されなくて、テーマが白い端末とかでも文字が白いままで見えなくなった。keyをいれたらtitleは黒くなりました(summaryはグレーの薄いまま。。。)

ということで、模範解答としてGoogleLoginServiceのを参考にしました。

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
  xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory android:title="プライバシー" />
    <PreferenceScreen android:title="Googleマップ&Latitude" android:key="key1">
        <intent android:action="com.google.android.apps.maps.LOCATION_SETTINGS" />
    </PreferenceScreen>
    <PreferenceScreen android:title="検索" android:key="key2">
        <intent android:action="com.google.android.googlequicksearchbox.action.PRIVACY_SETTINGS" />
    </PreferenceScreen>
    <PreferenceScreen android:title="現在地情報" android:key="key3">
        <intent android:action="com.google.android.gsf.GOOGLE_LOCATION_SETTINGS" />
    </PreferenceScreen>
    <PreferenceScreen android:title="Google+" android:key="key4">
        <intent android:action="com.google.android.apps.plus.PRIVACY_SETTINGS" />
    </PreferenceScreen>
    <PreferenceScreen android:title="広告" android:key="key5">
        <intent android:action="com.google.android.gms.settings.ADS_PRIVACY" />
    </PreferenceScreen>
</PreferenceScreen>

intentタグにはtargetPackageやtargetClassなども指定できるので、明示的Intentも発行できます。

<intent
   android:targetPackage="com.example.myapp"
   android:targetClass="jcom.example.myapp.SettingsActivity"/>

RadioButtonのレイアウトをいじりたい

AndroidのRadioButtonを、標準の設定画面とかにあるみたいに
設定ボタンとか右っかわにおきたくなったんです。
f:id:wasnot:20140421113642p:plain

こんな風に。
これは4.2からついたスクリーンセーバの画面ですが。

RadioButtonってRadioGroupに囲んで使うじゃないですか。
だから素直にこうしてみたんです。

<RadioGroup
    android:id="@+id/settingRadio"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <RadioButton
        android:id="@+id/radio0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="true"
        android:text="いち" />


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <RadioButton
            android:id="@+id/radio1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="に" />

        <ImageView
            android:id="@+id/settings"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:src="@drawable/ic_sysbar_quicksettings"
            android:background="@drawable/clear_button_bg" />
    </LinearLayout>
</RadioGroup>

レイアウト自体は、まあ細かいことはさておき、
思った通りにできそうでした。
でも、RadioGroupがちゃんと動かない。。

どっちもチェックできちゃったり、イベントとしてradio1の方は拾えていないみたいです。

ちょっと調べると

android - Custom layout for RadioButton - Stack Overflow

の答えでRadioGroupをカスタムしないといけないよ、らしいです。
うーん。

Y.A.M の 雑記帳: Android TableLayout, RelativeLayout で RadioButton を使う

yanzmさんみたく簡単にできるかと思ったんですが、
ちょっとhideなメソッドとか呼んでいて面倒だったので、

android - How to group RadioButton from different LinearLayouts? - Stack Overflow

を参考にOnClickListenerをセットしてみたらとりあえずそれっぽく動きました。
ちょっとださいやり方ですが。。
時間あったらもうちょっと試したいですね。

RadioButton r0 = findViewById(R.id.radio0);
RadioButton r1 = findViewById(R.id.radio1);
r0.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        r0.setChecked(true);
        r1.setChecked(false);
    }
});
r1.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        r0.setChecked(false);
        r1.setChecked(true);
    }
});

RadioButtonってCompoundButtonを継承しているから
OnCheckedChangeListenerでもいいじゃないかと思いましたが、
onCheckedChangedでCompoundButtonがnullできちゃいました。。
なんででしょう。。。

あと、とりあえずLayoutもRadioGroupの機能使えないんで
わかりやすくLinearLayoutにしちゃいました。

<LinearLayout >
    <RadioButton />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <RadioButton />
        <ImageView />
    </LinearLayout>
</LinearLayout>

Galaxy NexusにKitKatを入れてみた

Galaxy Nexusが4.1.2で開発用に使ってたんですが、最近重いなーと思いまして。

Nexus5が安いから買ってもいいんですが、いまいち大きさとか形が好きになれないません。

512MBのRAMでも動く?っていうKitKatをいれたらはやくなるんじゃないかと思って調べて入れてみました。

きっかけ

きっかけはJCROMの人がGNex用にビルドしていたのをみて、入れてみよう!ってとこでした。
sola : Galaxy Nexus 向けに Android 4.4 ( KitKat ) をビルドする

すごい!
ってことでそのままビルドしてもらったものを入れようとしたんですが、やり方がまずかったみたいで、うまくいきませんでした。、

いつも通り。。

で、全部消してJBをさらから入れなおしたんですが、ちょっとあきらめきれなくて。。
いつも通りXDAから探すと、AOSPをビルドしている人がいました!
[ROM] [4.4] [KRT16M] A taste of KitKat [Alpha] - xda-developers
すごい!
ってことでこのROMをCWMで焼き焼きしたらうまくいきました!
gAppsとsuもガイドにあるように入れました!

wifiのバグとかもなおってるみたいですね!

でもこのROMにはOS標準アプリが入ってないみたいでほとんど何も変わらず。。
気持ちサクサクになった気がします!
JB入れた時のヌルサクってヌルサクだったんだなぁ、と思いました。

設定アイコンがダサくなったり、ステータスバーのアンテナピクトがちゃんと白くなってネットにつながってるんだかないんだか。。

しかもAOSPのAndroidキーボードが落ちまくる。。
そのせいでwifi設定がなかなかできない!ってなりましたが、なんとかできました。

KitKatぽくしたい!

これじゃつまらないので、Nexus5のホームアプリを入れてみました。
これでやっとKitKat風ですね!(ホームアプリだけですが。。)

f:id:wasnot:20131115113752p:plain
システムバーとステータスバーが半透明に!
これでやっと全画面つかえている感覚!
どこかiOS7っぽい。

f:id:wasnot:20131115113756p:plain
ランチャー画面の後ろにも壁紙が透けてます。
いままで真っ黒で殺風景でしたよね。。

f:id:wasnot:20131115113805p:plain
左にスワイプするとGoogle Nowが!
iOS6までのSpotlight風に出てきますw
iOS7で捨てたものをGoogleがもってくるというww

f:id:wasnot:20131115113747p:plain
widget配置も2.3系みたく長押しでの設定に戻りましたね。。
どこかXperiaのhome画面風ですね。

f:id:wasnot:20131115114735p:plain
lock画面もちょっと変わりました。
右下のカメラアイコンがめっちゃiOSっぽい!!

f:id:wasnot:20131115114740p:plain
ただし、このアイコンはiOSのように上に引き上げるのではなく左にスワイプです。
4.2からついたロック画面widgetの機能なのかな。
widgetオフでも表示されました。


まだiOS7のbeta版を入れて使ってるみたいに不安定ではありますが、
JBの時よりもだいぶ使いやすい気がします!
標準ブラウザとかたぶん古いのが残っててまともに動かなかったり。。
Nexus5のアプリいろいろ入れてみようかと思ってます!

AndroidiOSが互いに歩み寄ってどっちも似たり寄ったりになってしまっているのが
ちょっとつまらないですが、、
最新OS楽しいですね!!

Nexus5よりちいさくて持ちやすい端末、ほしいですねー。
そういうのが出るまでは全然いけますね!!

サービスにバインドしようとしたらjava.lang.classcastexception: android.os.BinderProxy

今まで動いてたアプリがServiceとのBindで急に

java.lang.classcastexception: android.os.BinderProxy cannot be cast to MyBinder

がでて動かなくなったのでメモ。

結論は、同じ名前のServiceのアプリがあると、
後からいれたアプリのプロセスのServiceが呼ばれるのかも。

やっていたこと

まずテストアプリを作ってServiceとActivityのバインド、やり取りをしてました。
うまく動いたので元々のアプリとマージして動作チェック。
ちょっと不満とか不具合が出てきたのでテストアプリで試し始めたら
急にバインドでキャストエラー。

Android ClassCast exception when binding to service - Stack Overflow

ここをよんでて気づいたのが、ただintentでバインドしてるだけなので、
同じpackage,クラスのままだと後のアプリの方が呼ばれてるんじゃないか?

そう思ってマージした後のアプリを動かしたら普通に動きました。
そのアプリを消したら元のテストアプリでもServiceにバインドできました!

教訓

デバッグ中でも違うアプリとしていれるならパッケージ名とかクラス名はかえた方がいいにきまってますね!
(当たり前のことができていないですね。。)

FragmentにFragmentをつけるときはActivityのFragmentManagerじゃない方がいい

今日、とても悩んで時間を無駄にしてしまいました。。。

Fragmentの下にFragmentをつけるとき、
tab切り替えなどでonCreateViewが毎回呼ばれる気がします。

Fragmentの二段重ね

だいぶ前のはやりに追いつこうと、
今日、タブの下にViewPagerをつけてさらにFragmentを切り替えしようと思いました。

  • FragmentActivity(親)
  • Tab(ActionBarの)
    • Fragment(子)
    • ViewPager (FragmentPagerAdapter)
      • Fragment(孫)

そうするとFragmentActivityの下でのFragmentの切り替えは普通にonAttachからonDetachまで呼ばれるのですが、その下のFragmentの切り替えはonCreateが全然呼ばれません。。。
これはタブとViewPagerの階層が違うってViewPagerやFragmentPagerAdapterがちゃんと消せていないせいかと思いました。
結果的にはその通りっぽいのですが…

ViewPagerのせい?

ViewPagerが何やっているのか分からず、しかも普通に①階層で操作していても
たまにしか子FragmentのonCreateViewが呼ばれません。

いろいろ調べると
FragmentPagerAdapterとListFragmentを使ったらはまった - りふぉんろぐ。
のようにどうやら隣のFragmentも一度にonCreateViewしてくれてるみたいです。
そしてある程度離れてからじゃないとdestroyされない様です。

Fragmentのせい?

今回はまだsavedInstanceなどViewPagerの位置を保存する機構を入れていませんでした。
このタイミングだし実装しよう、とおもって
MyFragmentに

@Override
public void onSaveInstanceState(Bundle outState) {
    Log.e(TAG, "onsaveinstancestate");
     outState.putInt("position", mViewPager.getCurrentItem());
}

見たく書いてみました。

でも、いつまでたってもonSaveInstanceStateが呼ばれません。
で、調べてみると、、、
Fragments | Android Developers
にはちゃんと呼ばれるっぽいことが書いてありますが、
android - savedInstanceState when restoring fragment from back stack - Stack Overflow
みたく、呼ばれていなくて困っているひともいるみたいです。
↑のリンク先での回答をみると
「FragmentはActivityみたいに後ろにいてまってるわけじゃないから切り替えたらもう一回作り直しますよ。
だから状態保存はonSaveInstanceStateじゃなくてメンバー変数使いなさい」
みたいに書いてあります。

おー確かに。。

でも位置を保存せずに毎回0のpositionにするようにしても一階層だとうまく動くのに
二階層だと孫FragmentのonCreateViewが呼ばれません。。

やっぱりViewPagerやFragmentPagerAdapterのせい?

ViewPagerとFragmentPagerAdapterの組合せはFragmentを
View見たくキャッシュしてくれちゃうのでやっぱりこれのせいかなと思いました。
android - support FragmentPagerAdapter holds reference to old fragments - Stack Overflow
のように手動での更新がされなくて困っているひとがいるみたいでした。

それでいろいろOverrideしたり無理やりキャッシュをみたり見なかったりしたり
一番最初のリンクにあるようにsetAdapterでnull入れてクラッシュしたり。。

さらに子FragmentのonAttachで親Activityをrecreateしたら無限ループしたりw(楽しいですね)
ここでもしかしたらActivityが生きてるせいじゃないかと思いました。。

良く見たらActivityのインスタンスからAdapterつくってた。

Adapterのポインタが毎回新しくなってるのに
ViewPagerで移動しても一回破棄されたことにならないとFragmentがnewされない。。
ということに気がつきました。
そもそもViewPagerも子FragmentもPagerAdapterもnewされてるのに
孫Fragmentだけnewされないところがおかしいそうです。。
孫FragmentをnewしてるのはPagerAdapterだ、自分の実装がいけないのかな。
うまいわけはないけれどPagerAdapterのgetItemがそもそもよばれていませんでした。

そこでPagerAdapterってどうやってnewしてるんだっけ?と思ってみてみました。
といっても
Android Tips #31 ViewPager で Fragment を使う | Developers.IO
のをFragmentに置き換えただけでした。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Log.i(TAG, "oncreateview," + mViewPager + ", " + mPagerAdapter);
    super.onCreate(savedInstanceState);

    View view = inflater.inflate(R.layout.viewpager_fragment, container, false);
    MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getActivity().getSupportFragmentManager());
    ViewPager pager = (ViewPager) view.findViewById(R.id.myViewPager);

    // PagerAdapterにいろいろつっこんで

    pager.setAdapter(adapter);

    return view;
}

子FragmentもPagerAdapterもViewPagerも新しいのに。。。
でもFragment#getActivity()で帰ってくるActivityっていっつも同じ。。。!!
そしたら、、もしかして、、getFragmentManagerがかえすFragmentManagerもおんなじ。。。?
っ!。。。。

そこでFragment#getChildFragmentManager()にかえてみました。。
こんなものあるんですね。
ちゃんと読んでいないのがばればれ。。

View view = inflater.inflate(R.layout.viewpager_fragment, container, false);
mPagerAdapter = new MusicPagerAdapter(this.getChildFragmentManager());
mViewPager = (ViewPager) view.findViewById(R.id.musicPager);

これでうまくいきました!

ここまで時間かかりました…

まとめ

  • 参考にしたものはそのままコピペではなく状況に合ってるかチェック。。
  • 誰かのせいにしないでちゃんとReferenceよもう

そもそも使ってるAdapterとかちゃんと理解していないのが
問題に気付くのに時間がかかった原因ではないかと。。

Androidの開発で最近やったこと、を書こうと思いました。

Androidの開発で最近やったこと、を書こうと思いました、が
リンクをメモしておこうと思ったのですが、どこかにやってしまって・・・

しかもそれを探しているうちに bookmarkの整理になってしまい。。。
全然ブックマークの整理ができません。
最近は検索機能がしっかりしていてよかったので気を抜いてしまったのかもしれません。

ブックマークの同期

僕は職場と自宅でPCそれぞれ2台ずつ無駄に起動させていますが
(開発はmac, 職場のサイトやただのブラウジング、skypeやofficeはwindowsなど)
そのときブックマークを4台のPCで同期させています。
困ったことに全部chromefirefoxをメインで使っている訳ではないので
OS横断のSyncだけでなくブラウザ横断のSyncもしたいのです。

僕が使っているのはXmarksというアプリです。
http://www.xmarks.com/
これは4種類のブラウザに対応していてとても便利です。
いいところは
クロスプラットフォーム
・終了時などをトリガーに同期(明示的に同期もできる)ので常に重くはない
・履歴やタブも記録しておける
ですかね。
一時期サービス終了のアナウンスがされたらしいですが、
どこかに買収されてとりあえず使えています。
自前のwebdavサーバーをたてればそちらを同期サーバーにできるっぽいです。
そしたら自分で管理できるのでさらに安心ですね!

実際、ここまでwebの文化が進んでるのに
ブックマークの整理/同期の問題って10年前とあまり変わってない気がします。
(自分が知らないだけの気がしますが。。。)
dropboxとかそういうサービスとの連携アプリもあった気がしますが、
なんかもう少しユーザビリティーとか意識するととてもいいサービスが生まれそうですけどね。。

ブラウザ。。。

実はgoogleがすごく便利になったので、検索すればすぐに見つかるから
自分のローカルにブックマークを持つ必要がなくなってきてる気もしますがw
実際、僕自身もブックマークを使う習慣は5年くらいなくて、この一年で復活しました。
タブブラウザがでてきてそれをブックマークの代わりに使ってしまうのでw

そういうひどい使い方のせいでchromeがあまり実用的に使えません
(タブを開きすぎるとかなり重くなる。。設定やアドオンで改善しそうですが。。。
 マルチプロセスってこういうこと?blinkに期待!)
結構好きなブラウザですが、現在は基本firefoxですね。

firefoxgoogleと違って個人情報を収集とかしないし、
プライバシーにはかなり気を使っていてユーザーの味方っぽくて好きです。
最近はめっぽうmozillaに票が傾いてますw

でもこんなひどい使用状況でも快適なfirefoxcssレンダリングがひどいっぽいですね。。
最近webの開発のひとからききました。
かなりひいきしているし、html5の未来を担うブラウザだと思っているので
ユーザーにとって大切そうな部分で、開発の優先順位が下がってそうなので
ちょっとこれからどうなるのか不安です。
firefox osもまだまだって感じで、リリースは2月とかいっていたのが6月になっているっぽいし、
これからもがんばってほしいです。

僕ができることが何かあればいいんですが。。。

さっきまでやってたことのメモ <はてなブログ、はてなブックマーク、Ubuntuのvnc設定。。。>

なかなか書けないですが、とりあえずやったことをメモリます。

はてぶ

拡張機能入れてみました。
というかchrome拡張機能とアプリって別なんですね。。しらなかった。。
どこまで活用できるかわかりませんが、いろいろいじってみます。
ブックマーク系の拡張機能がxmarks、pocket、はてぶと三つも並んでしまいました。。
使い分けしているつもりが整理がつかなくなってますね。。

でもchromeがちょっと重くなった気がします。。pocketのほうがつかいやすいですね。


ソースコードの書き方。。。

プログラムのメモを取ろうと思ったのに、ソースコードの乗せ方が分からなかったので、
はてなブログにソースコードを貼り付ける方法 - くりにっき
はてなブログでソースコードを貼る方法 - 柳亭の真似とて大路を走らば
を参考にしました。

はてな記法にして、
>||
test
||<
ってうてば

test

ってなるんですね!すごい。。。

うえの、記法の効果を無効にしてるのは、スペースではさめばいいんですね!
ちなみに見出しの書き方も今学びました。

なんかwikiの記法っぽいですね、全然知らないんですが。。。

public void test(String str){
  System.out.println(str);
}

いまいちハイライトしないですね。。。

Ubuntuいれてみた。

ふるくってたぶんハードがいかれて時々再起動しまくるFMVにUbuntuを入れてみました。
もちろん勉強用です。
公式?の日本語サポートと
ubuntuをUSBメモリからインストール | ARTS NET
をたよりにインストール。
とてもうまくいきました。

その後

sudo apt-get install ssh

だけしてsshで入れるようにしてそのまま何日も放置していました。

今日はvncで入れるようにしてみよう!ということで
Ubuntu 12.04 LTS - デスクトップ環境 - VNCサーバーインストール : Server World
をたよりにやってみましたがなぜかUnityのメニューが出てこない。。

UbuntuでVNC使えるようになるまでメモ - i_aose(旧polaroidoon)の日記
であるように ~/.vnc/xstartupを修正しないといけないようです。
最後の方を

#x-window-manager &
exec gnome-session &

に修正してみましたが、だめですね。。
CMLog :: VNCをUbuntu Server 12.04で使う
にも設定があったので試してみましたが、gnome-classicが見つからないと言われてしまい、うまくいかず。。

もう一度ググったら
12.04 - Unity launcher doesn't appear in VNC session - Ask Ubuntu
のような質問があるっぽいですね。同じ現象です。
RealVNCを使ってたせいもありそうですね。

リンク先を見てみると
Knowledge Base :: VNC Server in Virtual Mode does not start correctly on Ubuntu 12.04
でいろいろ方法があるみたいでしたが、
gnome-classicではなくて2d-gnomeとかubuntu-2dというセッション?があるみたいですね。
自分で探せばよかったのかも。。。
ubuntu-2dというのに直したらうまく表示されるようになりました!


原因はUbuntuの12.04かもしれないですね。
firefox osをビルドしたくて、半年前くらいにもチャレンジしたんですが、
公式のおすすめに12.10はうまく動かないかも!ってあったので
12.04にしたんですが。。。
macだとなぜかうまくビルドできなかったのでubuntuなら!
まえはvirtual boxでかなり遅かったのですが、
実機に入れたので、もしかしたらだいぶ快適になるかもしれません。

今日はここまで!
今度はFirefox osのビルド環境を整えないと。

…やっぱりchrome重くなった。。