SharedPreferenceの変更時に警告アラート表示
アプリの設定(SharedPreference)を変更した際、スマホの画面解像度(画面サイズdp)が小さいとWebViewが表示崩れが発生する恐れがでてきた。
表示崩れが発生する可能性がある設定に変更した時、警告アラートを出すことにした。
まず、基準となる解像度を調査。以下のようなQiita記事を参考。
2015年発売Android端末のdp解像度まとめ
http://qiita.com/nein37/items/0a622f7ebbbb92db93d5#_reference-05eb2ffe676dfafa464c
んで画面サイズを取得
Androidでデバイスの大きさをdpで取得する
http://aroundthedistance.hatenadiary.jp/entry/2015/03/16/122827
(一部引用)
DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
それで調べた通り、PreferenceFragmentなクラスに実装
public static class SampleFragment extends PreferenceFragment { ︙ //設定変更された時に呼ばれる @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if(key.equals(対象の設定[])){ //画面解像度(横幅)をdbで取得 DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); float dpWidth = displayMetrics.widthPixels / displayMetrics.density; if(dpWidth <= 基準サイズ){ int screenSize = sharedPreferences.get(key, null); //画面サイズ最大のときのみ警告を出す } } } }
参考:
http://u64178.blogspot.jp/2014/07/android-preferencefragment-preference.html
AlertDialogでネストしたい時
アプリでダイアログ表示した後、ユーザーが特定のボタン(NeutralButton)を選択して押した時に更に新しいダイアログを表示するようにした。
ここではまったのは新しいダイアログの方のnew AlertDialog.Builder(this)の引数。Contextを指定してほしいと言われたので
new AlertDialog.Builder(this)
とか
new AlertDialog.Builder(getApplicationContext())
とか色々試したけどダメ。結果、どこかのstackOverFlowで見たMainActivity.thisを指定してあげたら動いたよ。
thisってインスタンスじゃないの?クラス名.で呼び出せるのってstaticなクラスだけじゃないんだっけか?
private void showAlert(){ new AlertDialog.Builder(this) .setTitle("title") .setMessage("message") setNeutralButton("NeutralButton"), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { new AlertDialog.Builder(MainActivity.this) ︙ } }) .create().show(); }
AdMob実装で大いにハマった備忘録
AdMobに関係あるのからないのまで。
何日もハマった上にいろんな設定を色々いじって何やったか忘れてしまったので、雑な感じですが備忘録的な感じでなにとぞ。
1).AdMobの実装を一通り終えてbuildしようとしたら以下のエラーが出た。
java.lang.ClassNotFoundException: Didn't find class "com.google.firebase.provider.FirebaseInitProvider" on path: DexPathList[[dex file "/data/data/[パッケージ名].debug/files/instant-run/dex/slice-com.google.firebase-firebase-iid-9.6.1_17f9eed5e9c1fe52c568855cb2090871a90f4031-classes.dex", dex file "/data/data/[パッケージ名].debug/files/instant-run/dex/slice-com.google.android.gms-play-services-ads-9.6.1_1aa317fdb75c8fb2b8ae8bfdfb55c4013d6bc40a-classes.dex"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64, /vendor/lib64, /system/lib64]]
よくわからないけどDexファイルがなんとか?
メモによると以下のとおりMultiDexを設定ファイルに書き加えたらエラー解消したらしい。
build.gradle
android { compileSdkVersion 21 buildToolsVersion "21.1.0" defaultConfig { ... minSdkVersion 14 targetSdkVersion 21 ... // Enabling multidex support. multiDexEnabled true } ... dependencies { compile 'com.android.support:multidex:1.0.0' }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.multidex.myapplication"> <application ・・・ android:name="android.support.multidex.MultiDexApplication" ・・・ >
参考:
http://qiita.com/nshmura/items/c7e8faa05c5ad4a66b3d#_reference-91cadc916c4dc5fe7d87
https://developer.android.com/studio/build/multidex.html?hl=ja#dev-build
2.)メソッド数が64k(65536)を超えるとビルドエラーになる
具体的なログはロストしてしまったが、65536という数字が出たらきっとこのエラー。
以下のとおり対処を調べた。このうちの1,2,4を実施。
どれかでエラーが解消された。(4かな)
[対処1]. メソッド数の確認
以下、リンク先より抜粋
http://qiita.com/konifar/items/d98c78facbaae63badca
実際どのくらいのメソッド数なのかを確認します。dex-method-countというツールを使うと、簡単にapkのメソッド数を確認できます。
$ git clone https://github.com/mihaip/dex-method-counts.git $ ./gradlew assemble # ビルド $ ./dex-method-counts path/to/app.apk # or .zip or .dex or directory こんな感じで出力されます。まずは出力してみると、節約できるところが見つかるかもしれません。 Read in 60366 method IDs. <root>: 60366 : 8 android: 10815 accessibilityservice: 6 accounts: 8 animation: 2 app: 351 bluetooth: 2 content: 303 ...(略)... com: 39448 ...(略)... google: 18513 ads: 165 mediation: 134 admob: 24 customevent: 40 jsadapter: 38
[対処2].google playSDKのインストールはやめる
以下、リンク先より抜粋
http://qiita.com/garlicG/items/fac54cf96d66cfcb4b8d
play-service全体のライブラリは少し巨大なので、AdMobだけが必要であれば以下のような記述でおKです。
build.gradle(AndroidStudio利用時)
compile 'com.google.android.gms:play-services-ads:7.3.0'
[対処3].ProGuardを導入する
もうしてました。(デフォルトでそうなってる?)
[対処4]. gradleでjumboModeオプションを有効にする
また以下のリンク先のとおりに修正。
http://qiita.com/konifar/items/d98c78facbaae63badca
3).support-appcompat-v7のFile size 0 byteエラー
buildも通るようになったので、Android Studioからエミュレータ(ADV)起動して確認しようとしたらエラーった。
10-28 22:38:19.568 2306-2306/[パッケージ名].debug E/System: Unable to load dex file: /data/data/[パッケージ名].debug/files/instant-run/dex/slice-com.android.support-appcompat-v7-23.3.0_e72ec210e17d195522eaa56b35521a9733e3c94a-classes.dex 10-28 22:38:19.569 2306-2306/[パッケージ名].debug E/System: java.io.IOException: Failure to verify dex file '/data/data/[パッケージ名].debug/files/instant-run/dex/slice-com.android.support-appcompat-v7-23.3.0_e72ec210e17d195522eaa56b35521a9733e3c94a-classes.dex': Bad file size (32768, expected 550080d) at dalvik.system.DexFile.openDexFileNative(Native Method) Caused by: java.io.IOException: Failed to find dex file 'x-classes.dex' in oat location 'x': Failed to find existing oat file at x: File size of 0 bytes not large enough to contain ELF header of 52 bytes: '/data/data/[パッケージ名].debug/cache/slice-com.android.support-appcompat-v7-23.3.0_e72ec210e17d195522eaa56b35521a9733e3c94a-classes.dex'
原因不明。Android Studioの設定から見なおしたけど一向に治らなかった。
AVDを新規作成したらこのエラーが出なくなった。(ソースとかのせいとかじゃなかった。)
こんなのに2日も振り回されて私ってホント馬鹿。
4.)AdMobの実装エラー
やっとまともに起動したAVDで出たエラー。
java.lang.IllegalStateException: The ad size can only be set once on
ad size がなんたら。
以下のとおり、content_main.xml(active_main.xml)とソース内両方でAdsizeを指定したのがまずかった。
content_main.xml
<com.google.android.gms.ads.AdView ・・・ ads:adSize="SMART_BANNER" //これと ・・・
MainActivity.java
MobileAds.initialize(this, getString(R.string.banner_ad_unit_id)); adView=(AdView) findViewById(R.id.adView); adView.setAdSize(AdSize.SMART_BANNER); //これ ・・・
ソースの方をコメントアウトしたら表示できたよ!
http://stackoverflow.com/questions/23337802/ad-size-and-ad-unit-id-must-be-set-before-loadad-is-called
広告表示でここまで大変なんだなー。AdMob仕様変わらないでほしいな。。。もうやりたくない。。。
AndoroidアプリにAdMobバナー広告を設定するときにハマった
AdMobを設定するために以下のサイトを参考にbuild.gradleを実装したり、google-services.jsonを設置したりした。
https://firebase.google.com/docs/admob/android/quick-start?hl=ja
すると例のR.が読めなくなるエラーとともに以下のエラーが出力された。
エラー :Execution failed for task ':app:processDebugGoogleServices'. > No matching client found for package name '[パッケージ名].debug'
原因は先日追加した開発用モジュールdebugが原因らしい。
そこで、以下のとおり修正したgoogle-services.jsonを/debug/配下に設置した。
"client": [ { "client_info": { "mobilesdk_app_id": "1:209109689792:android:463e3def0de05f38", "android_client_info": { "package_name": "[パッケージ名].debug" }
するとR.が読み込めなくなる例のエラーは解消された。
WebView内で通信エラーでエラー画面表示さす
WebView内で通信エラーになった場合(net::ERR_CONNECTION_TIMED_OUT)、エラーページを表示さすようにハンドリング
#WebViewClient生成時に定義してあげる
○準備(既にassetsディレクトリがある場合は不要)
HTMLを置くassetsディレクトリを作成する。
AndroidStudioのプロジェクトのappを右クリック→[新規]→[New]→[Folder]→[Assets Folder]を選択。
app/src/main/asestsディレクトリが作成される。
また、build.gradleに以下のとおり追記する。(自動挿入されることもあるので、既にあったら編集不要)
android { sourceSets{ main{ assets.srcDirs=["src/main/assets"] } } ・ ・ ・
app/src/main/asestsにエラー画面のHTML(network_error.html)を配置して準備終了
○WebViewクラスにコーディング
次のとおりWebView生成時にオーバーラードして実装する。
WebView webView = (WebView) findViewById(R.id.webView); webView.setWebViewClient(new WebViewClient() { @Override public void onReceivedError(WebView webview, int errorCode, String description, String failingUrl) { if(errorCode < 0){ // 自作のエラーページを表示 webView.loadUrl(“file:///android_asset/network_error.html”); } }
参考URL
http://www.hangout.co.jp/blog/archives/148
http://stackoverflow.com/questions/4997677/android-webview-onreceivederror
http://growsic.com/blog/androidlocalhtml/
Andoridアプリの開発と本番の取扱をGradleでどうにかする
参考にしたサイトは以下。
https://firespeed.org/diary.php?diary=kenz-1824
Andoroidアプリ界隈で開発と本番は
開発=debug、本番=release
っぽいので以下はそれに則って記載する。
○一つの端末にデバッグバージョンアプリとリリースバージョンアプリを共存させたい
Module内にあるbuild.gradleを以下のとおり修正する。
buildTypes { debug{ applicationIdSuffix ".debug" } release { ・ ・ ・
ビルド時にデバッグバージョンアプリの時は、アプリIDに.debugがつくので、アプリバージョンIDがリリースバージョンと被らない=共存できる
○開発と本番で設定ファイルを切り替えたい。
以下のとおり設定ファイルを切り替えられる。
- 本番用定数
/src/main/res/values/strings.xml
<resources> <string name="app_name">Sample application</string> <string name="url">http://gati.net</string> </resources>
- デバッグ用定数
/src/debug/res/values/strings.xml
<resources> <string name="url">http://uso.net</string> </resources>
Javaのソースコード内で参照する際は普通にR.string.urlでOK。
WEBアプリのようにENVで切り替えられないのは少し不便。