著者アーカイブ asaba

asaba 著者:asaba

【android】機内モードを使って消失した現在地アイコンを復活させた話

gpsを使って現在地を読み取るアプリを作っていたのですが、今まで普通に映っていた現在地アイコンが急に消えてしまう事案に

遭遇しました。プロジェクトクリーンやリビルドも何回かしたのですが依然アイコンは消えたまま・・・!

ここまでコードをロールバックしても動かなかったので、視野を広げて飛行機ちゃんこと機内モードに白羽の矢を立てました。

機内モードにするとbluetoothやwi-fiといった通信機能が一時的に使えなくなります。こいつをタップして一度全てリセットした状態でも

う一回起動してみようと思い試してみました。が変わらず・・・。さてどうしましょうと考えていたらなんといきなり現在地アイコンが復活しました!

読み込みに時間がかかっていただけのようで、その後何回か再起動したのですが問題なく現在地アイコンを出すことができました。

iphoneユーザーですからっていい訳は死んでも使いたくないのでここで解決できて本当に助かりました。

設定方法→①まずホーム画面に戻ります。②上から下にスワイプすると、下のような画面が出てきます。③左下にある機内モード(飛行機のマーク)を押します。すると、wi-fi、bluetooth、位置情報といった通信手段が一斉遮断され、アプリなどの連携を断ち切ります。

ここで、もう一回機内モードを押して停止させましょう。すると、今までオフだった通信手段が全部白色になりオンの状態に

なります。とりあえずこれで解決・・・・。

 

 

コードやライブラリ周りを見てもまだ現在地が出てこなかった場合は、こちらが怪しいと目をつけてみてください。

asaba 著者:asaba

【android WebView】webViewに被せたアクションバーに処理を実装する方法

最近になってまたWebViewを触り始めました。webViewってjavascriptとかのイメージが強いですがandroidでも頑張れば実装できるみたい

ですね。しかもこっちはネイティブだから処理速度も安定しているときたので使いこなせれば開発の引き出しが増えそうですね。

今回はそのwebviewを使っていて、アクションバーの中のアイコンをタップしたときに何らかの処理をするメソッドを載せていきます。

 

タップしたアイコンに応じて処理を切り分けるには、onOptionsItemSelected(MenuItem item)メソッドを使う必要があります。

このメソッドは、ヘッダーに当たるアレ。即ちアクションバーに配置したアイコンに応じて処理をswitchで分岐させる役割を

担っています。

例えば、switchの引数idの中身がhomeだった場合は、finish();で終了させてホームボタンにバックさせます。

 

<pre>@Override
public boolean onOptionsItemSelected(MenuItem item) {
    
    int id = item.getItemId();
    WebView webView = (WebView) findViewById(
            R.id.webView);
    switch (id) {
        case android.R.id.home:
            finish();
            break;
        case R.id.menu_share:
            ShareCompat.IntentBuilder builder = ShareCompat.IntentBuilder.from(this);

            String url = webView.getUrl();
            
            builder.setText(url);
            builder.setType("text/plain");
            
            builder.startChooser();
            break;
        case R.id.reload:
            webView.clearCache(true);
            webView.reload();
            break;
    }
    return super.onOptionsItemSelected(item);
}</pre>

 

このように、一般的なアプリのアクションバーにあるページ更新やシェア機能も切り分けて実装することができます。

 

asaba 著者:asaba

【androidJava】ads.MobileAdsInitProvider(ADMOB)を使おうとしてはまったこと

MobileAdsInitProviderは、アプリに広告を表示させることができるライブラリで、ブログやショッピングサイトを取り扱うアプリではよくお目にかかります。

今回はこのライブラリが必要になったので導入してみたのですが、下のエラーを出した後に落ちてしまいました。

 


java.lang.RuntimeException: Unable to get provider com.google.android.gms.ads.MobileAdsInitProvider: java.lang.IllegalStateException

 

どうやら、今までのライブラリと違い単にグレイドルにいれただけでは使えないもよう。

調べてみるとMobileAdsInitProviderを使うには、マニフェストへの記述が必要みたいです。アプリケーションタグを閉じる前に

こんな感じでいれてあげれば解決できます。

 


<meta-data
android:name="com.google.android.gms.ads.AD_MANAGER_APP"
android:value="true"/>

 

こちらの記事のurlを参考にしました

グレイドル関係のエラーが出るたびにこのブログに載せている気がします。ですがグレイドル関係の記事は数が少ないのに対して同じよう

なエラーで困っている人が多くいるので少しでも助けになれたらなと思っております。

なお、日本語版の公式ではこの記事の対策方法が書いていないので注意してください。(見るなら英語版で)

asaba 著者:asaba

【ButterKnife】バターナイフは明示的にgradleに書くべき

viewのメソッドを簡潔にかくことが出来るライブラリです。一般的なviewを使いたい時は、findViewByIdで紐付けるだけで使うことが

できますが、これが複数のviewとなると、同じようなコードができてしまいこれでは可読性に欠けてしまいます。

バターナイフは、このダブつくview定義を事前に定義させることでsetContentViewの下からviewの操作を可能にしてくれるので、複数の

ビューを使いたいけど管理が大変なエンジニアさんには重宝されています。こんな感じ↓

class ExampleActivity extends Activity {
@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(R.id.footer) TextView footer;

@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}

 

今自分が開発しているアプリもバターナイフを使って管理しているのですが、グレイドル(また出たなお前)のバージョンを上げたら

やっぱりというべきかエラーに通せんぼされてしまいました。

 


Error:Execution failed for task ':app:javaPreCompileDebug'.
&gt; Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
- butterknife-6.1.0.jar (com.jakewharton:butterknife:6.1.0)
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.

訳してみました。

プロセッサは明示的に宣言されなければなりません。次のコンパイルクラスパスへの依存関係に、注釈プロセッサが含まれています。 annotationProcessor設定にそれらを追加してください。

 

どうやらバターナイフはグレイドルのバージョンに合わせてannotationProcessorとして定義しなければいけないみたいです。グレイドル

アップデート前は普通に定義しなくても使えていたのに・・・。

まあもうできたのが6年前なので仕様が変わっていても不思議じゃないですよね。という訳でannotationProcessorにバターナイフを定義してあと残り

なく解決です。

 

annotationProcessor "com.jakewharton:butterknife:6.1.0"
compileOnly "com.jakewharton:butterknife:6.1.0"

このライブラリに変わるものがすでに出てきているか分かりませんが、ライブラリとしては書くことが少なく学習コストも低いので

いとまがあれば使ってみたいと思います。

asaba 著者:asaba

【javaScript fetch】fetchApiで素のデータを送っても何も返ってこない罠にはまったお話

fetchApiは、通信が成功した際にはpromise型で値を返します。が、スコープで囲んで変数に入れて飛ばすと、サーバーに要求した

値が返ってこない事態にハマってしまいました。ajaxだとdata:{“key”,value}みたいにまとめてからプロパティに入れて取ってくることが

できるのですがこっちでは仕様のせいか受け取ってくれません。

調べてみると、そのままbodyに入れるのではなくformDataというfetchから新しく使えるようになったApiを使って送り込むみたいです。

ajaxではdocumentというxmlを取り扱うことができるオブジェクトがあったのですが、こっちではそれが使えないのでこちらを代わりに

使ってくださいということだと思います。

fetchってもうリリースされてから数年経つのですが、国内の記事を探しても全然見つからないのでみんなまだajax使ってるのかなと

思ってしまいます。

ajaxと違いdomをいちいち掘削しないので、通信速度の向上は期待してもいいと思います。ですが、取ってきたxmlから各タグを取り出すメソッド

とかがめんどくさい感じでしたので、そこらが原因で手が出にくいのかなと思いました。前述の処理だけはjqueryに任せて通信だけ

fetchで賄うことができますが、試していないので速さの保証は実装してみないと分からないです。


var formData = new FormData() ;
var id = this.props.match.params.id;
var followMember = window.localStorage.getItem("member_no");
formData.append( "name", "asaba" ) ;
formData.append( "location", "shizuoka" );
formData.append( "gender", "male" );

var url = 'https://hottomotto';
fetch(url,
{ body: formData,
method: "POST",
})
//通常のレスポンスを返す
.then(function (response) {
return response.text();
})
.then(function(text) {
var xml = new DOMParser().parseFromString(text, "text/xml");
console.log(xml);
});


asaba 著者:asaba

Atomを使っていてメニューバーが消えてしまったときの対処法

いつも通りにソースファイルを立ち上げて作業を始めようとしたのですが、何かの拍子でメニューバーがごっそり消えてしまいました。

メニューバーにはファイルを開いたり保存したりなど普段の作業に必須な項目が入っています。さすがにこのままでは気持ち悪いし

効率が落ちるので元に戻そうと決めたのですが、英語表記なのでわかりにくくかなり苦労してしまいました。

方法としましては、まず今回の目的であるメニューバーを手っ取り早く探すためにCtrl + Shift + pコマンドを押してモーダルを出します。

そこで、toggleと検索します。すると、下の画面のようになると思います。

この画面の一番下のWindow Toggle Menu Barという項目をクリックしてみましょう。すると、上からメニューバーがにゅっと出てくる

のが確認できると思います。

何もなければこれでいつも通りにメニューバーを使うことができます。余談ですが、ファイルを開くと、開いたファイルの一覧が

見ることができるバーも同じように復元しようとしたのですがこちらは元に戻りませんでした・・・。

厳密に言うと形だけは直ったのですが、ファイルの一覧が見れなくなってしまい非常に不便な思いをしています。こちらはツイッターやgit

などで情報収集して修正の目途が立てばまたアップしていきたいと思います。

 

asaba 著者:asaba

【javaScript】fetchApiでレスポンスをxmlに変換する方法

ajaxのように手軽に書けつつ早いapiであるfetchApiでxmlを取ってくる方法を探していたのですが、中々見つからなかったので

こんな感じで仕立ててみました。基本的な書き方はJqueryのajaxと変わらないので、ajaxを使ったことのある方ならばすぐに要領を掴め

そうですね。


postfetch() {

//通常のレスポンスを返す
.then(function (response) {
console.log(response);
})
//xmlに変換
//.then(function (response) {
//const text = new DOMParser().parseFromString(response, "text/html")
//console.log(text);
//})
}

レスポンスで受け取ったデータを即座にDOMParserでxmlで変換するだけなので、コンソールで確認できたら後は自由に使うことが
できます。
最後に言うのもアレなのですが、fetchでxmlを扱う場合は、速度にこだわらない場合はajaxでも代用が利きます。

asaba 著者:asaba

【androidJava】BroadcastReceiverを試しに使ってみる

BroadcastReceiverとは、何かのタイミングで端末に特定の処理を通知するときによく使われる便利なライブラリです。

軽い機能であればfirebaseよりも手軽に実装することができるので、息抜きにミニアプリを作ってみたいと思ったときに試してみて

ください。

自分が書いたコードはこんな感じに仕上がりました。まずボタンを押すと、pickerがでてきます。そのpickerを使って時間を指定して、その時間になったらトーストで時間ですよ~とお知らせするシンプルなものになっております。お休みのときにささっと書いたので情報少しが古い&コードが乱雑ですがご容赦くださいまし。

MainActivity↓

</pre>
<pre>public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TimePicker();
            }
        });
        }
        public void TimePicker(){
            final Calendar calender = Calendar.getInstance();
            int hour = calender.get(Calendar.HOUR_OF_DAY);
            int minute = calender.get(Calendar.MINUTE);

            TimePickerDialog dialog = new TimePickerDialog(
                this,
                new TimePickerDialog.OnTimeSetListener() {
                    @Override
                    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                        System.out.println(hourOfDay);
                        calender.setTimeInMillis(System.currentTimeMillis());
                        calender.add(Calendar.SECOND, 5);

                        Intent intent = new Intent(getApplicationContext(),
                                AlarmBroadcastReceiver.class);
                        PendingIntent pending = PendingIntent.getBroadcast(
                                getApplicationContext(), 0, intent, 0);
                        // アラームをセットする
                        AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
                        if (am != null) {
                            am.setExact(AlarmManager.RTC_WAKEUP, calender.getTimeInMillis(), pending);

                            Toast.makeText(getApplicationContext(),
                                    "Set Alarm ", Toast.LENGTH_SHORT).show();
                        }
                    }
                },
                hour,minute,true) ;
            dialog.show();
        }
}</pre>
<pre>

今回のお題であるBroadcastReceiverです。

</pre>
<pre>public class AlarmBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // ここに端末に対してしたい処理を書きます。例ではトーストになっているので変えても構わないです。
        Toast.makeText(context, "Received ", Toast.LENGTH_LONG).show();
    }
}</pre>
<pre>

マニフェストには、パーミッションでWAKE_LOCKを設定しておきます。

その後に、applicationタグのすぐ上に”AlarmBroadcastReceiver”を定義しておきます。これがないとBroadcastReceiverが反応しない

ので忘れないでくださいね。

</pre>
<pre><uses-permission android:name="android.permission.WAKE_LOCK"/></pre>
<pre><application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
    <receiver android:name=".AlarmBroadcastReceiver"
              android:process=":remote" />
</application></pre>
<pre>

レイアウトのほうはボタンだけなので割愛させていただきました。コードの量も少なめで実装できるので、メンテナンスにも苦労しなさそうです。おすすめです。

asaba 著者:asaba

【androidGradle】minSDKVersionの重要性

前にも似たような話題を振ったような・・・グレイドル系の記事って何回出したか分からないので記憶が曖昧になっております。

問題のエラーはこちらです。↓


Error:Execution failed for task ':processDebugManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 1 cannot be smaller than version 8 declared in library [com.twitter.sdk.android:twitter:1.4.0] C:\Users\swift0910\.gradle\caches\transforms-1\files-1.1\twitter-1.4.0.aar\54bb48e8e15821fe4455ab493a1ff43e\AndroidManifest.xml as the library might be using APIs not available in 1
Suggestion: use a compatible library with a minSdk of at most 1,
or increase this project's minSdk version to at least 8,
or use tools:overrideLibrary="com.twitter.sdk.android" to force usage (may lead to runtime failures)

 

見かたはシンプルで、今のままではminSdkVersionのレベルが1になっており、バージョン8以上のライブラリを使うことはできませんという感じです。

もしmisSDKVersionが現存のライブラリよりバージョンが低かった場合は、そのライブラリより上の数字で設定するとビルドできると

思うので試してみてください。何も設定していない場合はデフォルトでnullになるので当然ライブラリも使えません。なので

minSDKVersionは、仕様が変わってくるAndroid5.0・API21辺りで設定しておきましょう。

 

参考サイトー>http://y-anz-m.blogspot.com/2015/09/minsdkversion.html

 

asaba 著者:asaba

【npm】cordovaでうまくcordova platforms add browserできない時の対処法

cordova platforms add browserでブラウザを追加しようとしたらAdding browser project…Project already exists! Delete and recreate

で返されてしまいました。あぁ既に追加したブラウザがあったのかと思いcordova platforms rm browserをしたのですが今度はそんなファイルないよ!とエラーを吐き続ける始末・・・。

platformsディレクトリを見ましたが、browserフォルダは存在しなかった。(存在してこのエラーが出るのが普通)ということは

何かの手違いでbrowserフォルダが存在していることになっている。似たようなファイルのplatformフォルダに追加していると思ったの

ですが探してみても該当フォルダはなし。ダメもとでキャッシュを全て消してからビルドしてみようと思いnpm cache verify –forceで

キャッシュを削除したあとにnpm installを実行。その後にさっきのcordova platforms add browserを実行。すると上手くいきました・・・!!

よく考えるとnpm installはただnode_moduleにパッケージをインストールしているだけですよね・・・・今回の事象とは関係ないのでは

と思いましたが、よく考えたらこちらでもパッケージを入れ直せとエラーがでていたので手間が省けました。

コルドバにおいてnpmのパッケージを新しく追加したいけどエラーが出て先に進めないという時はキャッシュを消してみると景色が

晴れてくるかもしれませんね。存在しないファイルも、見えないキャッシュ上で残っている場合があるのでプラットフォームの追加/削除

は計画的に実行するべきですね~。