端末のアップデートでAndroid 4.4にすると、
昔作っていたカメラアプリが画像保存時に強制終了するようになりました。
会社勤め時代に作ったアプリなので、今はもう手元にソースコードはありませんが、
アプリ自体は普段から使っているので大変困りました。
なので、後任者の方に直してもらいたいと思い、原因の調査に乗り出してみました。
強制終了時にLogCatで確認したら、下記のエラーが出ていました。
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.MEDIA_MOUNTED from pid=XXXXX, uid=XXXXX
むむむっ。どうやらAndroid 4.4からメディアをマウントするためのBroadcastの送信が使えなくなったみたいですね。
Android 4.3端末では正常に動いていました。
画像ファイルを外部ストレージに保存する場合、物理的に保存するだけではギャラリーアプリなどが認識してくれないので、
下記のようにマウントのBroadcastを送信してギャラリアプリに認識させていました。
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse ("file://" + Environment.getExternalStorageDirectory())));
ずいぶん昔の話ですが、当時はギャラリーアプリが認識してくれる魔法のコードとして、
どこかのサイトで紹介されていたのをそのまま使っていたのをふと思い出しました。
それがどうやらAndroid 4.4から使えなくなったみたいです。
対策として、メディアをマウントし直すのではなく、MediaScannerConnectionを使って
保存したファイルをMediaContentProviderに登録(スキャン)する方法なら回避できるみたいです。
テストコードを書いたところ、ギャラリーアプリなどにすぐに反映されるのも確認しました。
String[] filePath = {targetFIleName};
String[] mimeType = {"image/*"};
MediaScannerConnection.scanFile(context, filePath, mimeType, null);
アプリを作った当時からこのコードを書けていたら、今頃こんな調査は必要なかったのでしょうが……(^^;;
Share your thoughts
8月8日(金)〜8月10日(日)にかけて開催された「Startup Weekend Kyoto」というイベントに参加してきました。
3日間の時間を使って、起業に必要なプロセスを経験し、メンターと呼ばれる先輩たちに指導してもらい、プロダクトをブラッシュアップしていくイベントになります。
僕らのチームは、日々の情報を色で残していく「カラーログ」というプロダクトを提案し、僕はAndroidアプリの開発の担当をさせていただきました。
開発中のデモ用画像です。
いろんな失敗もあって、追い詰められたりもしましたが、参加できてとても楽しかったです。
願わくば、製品を世に出すところまで頑張りたいと思うのでした。
Share your thoughts
Google I/O報告会の「DevFest Japan 2014 Summer」の京都会場に参加してきました。
各会場の人たちとGoogle ハングアウトでつなぎます。
京都会場にいるAPI Expertのお二人のセッションを始め、いろんな方々のセッションを聞くことができました。
新しい技術を学ぶのはワクワクしますね(^^)
尚、会場の提供は、京都リサーチパーク様でした。
いつもお世話になっております(^^)
Share your thoughts
久しぶりにGeek Bearへ行ってきました。
普段は平日の木曜日にやっているのですが、
今回は三周年記念イベントということで土曜日に開催されていました。
大阪に用があって行ったついでに、ふらっと行ってみました。
あまり長居できませんでしたが、久しぶりに楽しく飲めました。
また機会をみて行ってみたいです。
Geek Bear 公式サイト
Share your thoughts
既存のビュークラスを継承してカスタムビューを作成することができます。
最小限のレイアウトとソースコードで、カスタムビューを作成してみました。
完成図
ソースの構成
下図にて、赤枠で囲んだ部分がカスタムビューになります。
そのカスタムビューを縦に3つ並べました。
今回のカスタムビューは、LinearLayoutで囲ったButtonとTextViewにて構成しています。
まず、カスタムビューのxmlファイルについて記述します。
カスタムビューとして、作りたいパーツで構成します。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/btnTestButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<!-- 区切り線 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="---------------------------------"
android:layout_marginBottom="30dp"
/>
</LinearLayout>
次に、LinearLayoutクラスを継承して、独自のカスタムビュークラスを作成します。
クラス名は任意の名前でいいですが、とりあえず「CustomLayout」としておきます。
そして、コンストラクタ内でレイアウト用のxmlを読み込みます。
package com.example.custom;
import com.example.customviewtest.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
/** カスタムレイアウト .*/
public class CustomLayout extends LinearLayout {
/** 通常のコンストラクタ .*/
public CustomLayout(Context context) {
super(context);
}
/** xml配置用のコンストラクタ .*/
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
/** カスタムビューのxmlからのlayoutの情報を読み込む. */
View layout = LayoutInflater.from(context).inflate(
R.layout.custom_layout, this);
/** カスタムビューのボタンに任意の文字を表示する例. */
Button btn = (Button)layout.findViewById(R.id.btnTestButton);
btn.setText("カスタムビューのボタン");
}
}
これにて、カスタムビュー側の処理は完了です。
※通常のコンストラクタの方は今回使わないので、xmlの読み込みは省略しています。
次にメインActivityのxmlファイルにカスタムビューを配置します。
今回はカスタムビューを3つ縦に並べてみます。
パッケージ名を含むクラス名で記述。
今回の例の場合は、「com.example.custom.CustomLayout」となります。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<!-- カスタムビューを配置 -->
<com.example.custom.CustomLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<com.example.custom.CustomLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<com.example.custom.CustomLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
最後に、何も中身がないですが、メインActivityのソースはこちらです。
package com.example.customviewtest;
import android.app.Activity;
import android.os.Bundle;
/** カスタムビュー用のメインActivity.*/
public class CustomViewTestMainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
}
}
こんな感じで、カスタムビューを作ることができます。
あとはカスタムビューを自分好みに作り込むだけです。
Share your thoughts