Slide 1

Slide 1 text

やさしい 画像ギャラリー改善tips @kaelaela

Slide 2

Slide 2 text

   まえかわ ゆういち(kaelaela) ● Github: kaelaela ● Twitter: kaelaela31 ● 755というSNSを作っています

Slide 3

Slide 3 text

注意 画像ギャラリー ≠ 画像一覧 画像ギャラリーとは端末内の画像を選択する画面のこと

Slide 4

Slide 4 text

対象としている人 ● 画像ギャラリーよくしたかったんだよね ● いろいろ調べたけど諦めた ● スケジュール的に泣く泣くある程度のものにしてた

Slide 5

Slide 5 text

対象じゃない人 ● 画像ギャラリー作成は一通り悩んだ ● うちには画像ギャラリーが必要ない

Slide 6

Slide 6 text

話さないこと ● Intentの概念、使い方など ● ContentResolverの説明など ● 画像キャッシュに関すること ● APIからリストを取得し表示すること

Slide 7

Slide 7 text

ゴール 「簡単そうだな」 「画像選択画面のパフォーマンスを改善しました」リリース

Slide 8

Slide 8 text

画像ギャラリー苦しみあるある ● スクロールするとカクつく ● ローディングが終わらない or 何度も呼び出される ● キャッシュが効くまでは遅い ● Android標準のギャラリーが開く (Storage Access Framework)

Slide 9

Slide 9 text

Storage Access Framework ● MIME typeで指定できるが、関係のないフォルダの参照などもある ● デザインの変更ができない ● 公式ドキュメント https://developer.android.com/guide/topics/providers/document-provider.html //Build.VERSION.SDK_INT >=Build.VERSION_CODES.KITKA Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); //画像のみの場合 startActivityForResult(intent, YOUR_REQUEST_CODE);

Slide 10

Slide 10 text

Storage Access Framework ● MIME typeで指定できるが、関係のないフォルダの参照などもある ● デザインの変更ができない ● 公式ドキュメント https://developer.android.com/guide/topics/providers/document-provider.html //Build.VERSION.SDK_INT >=Build.VERSION_CODES.KITKA Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); //画像のみの場合 startActivityForResult(intent, YOUR_REQUEST_CODE); デザイナーが 許してくれない

Slide 11

Slide 11 text

こんな画像ギャラリーにしたい ● 読み込みとスクロールが早い ● デザインが自由にできる ● 自分たちのアプリで必要な機能に絞る

Slide 12

Slide 12 text

改善のポイント3つ ● 画像管理方法を理解する ● 適切なサイズの画像を使う ● 使い方に合わせて表示する

Slide 13

Slide 13 text

ポイント1: 画像の管理方法を理解する ● 保存されている画像について ● MediaStoreのイメージ図 ● 画像へのアクセス方法

Slide 14

Slide 14 text

保存されている画像について 形式: 基本は撮影したjpgやダウンロードしたpng MediaStore:端末内データのメタ情報を提供している Audio, Files, Images, Video, MediaColumns https://developer.android.com/reference/android/provider/MediaStore.html#

Slide 15

Slide 15 text

MediaStoreのイメージ図 Files - FileColumns - MEDIA_TYPE - MIME_TYPE - TITLE ... その他、有象無象 Audio - Media - Alubms - Artists ... Images - Media - Thumbnails - ImageColumns Video - Media(本体) - Thumbnails - VideoColumns

Slide 16

Slide 16 text

画像を取得 Files - FileColumns - MEDIA_TYPE - MIME_TYPE - TITLE ... その他、有象無象 Audio - Media - Alubms - Artists ... Images - Media - Thumbnails - ImageColumns Video - Media(本体) - Thumbnails - VideoColumns ここから取得 MediaStore.Images.Media

Slide 17

Slide 17 text

画像と動画を取得 Files - FileColumns - MEDIA_TYPE - MIME_TYPE - TITLE ... その他、有象無象 Audio - Media - Alubms - Artists ... Images - Media - Thumbnails - ImageColumns Video - Media(本体) - Thumbnails - VideoColumns ここから取得 =MediaStore.Filesで MEDIA_TYPE_IMAGE,MEDIA_TYPE_VIDEOを指定

Slide 18

Slide 18 text

画像へのアクセスの方法 ContentResolverでアクセス https://developer.android.com/reference/android/content/ContentResolver.html Cursorで取得 SQLでいう「CURRENT OFカーソル名」のカーソル

Slide 19

Slide 19 text

画像へのアクセスの方法 ContentResolver r = context.getContentResolver(); Cursor c = r.query(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, null, null, null, null); if (c != null) { c.moveToFirst(); while (!c.isAfterLast()) { String data = c.getString(c.getColumnIndex(MediaStore.Images.Thumbnails.DATA)); String imageId = c.getString(c.getColumnIndex(MediaStore.Images.Thumbnails.IMAGE_ID)); thumbnailPaths.add(data); thumbnailIds.add(imageId); c.moveToNext(); } c.close(); }

Slide 20

Slide 20 text

画像へのアクセスの方法 ContentResolver r = context.getContentResolver(); Cursor c = r.query(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, null, null, null, null); if (c != null) { c.moveToFirst(); while (!c.isAfterLast()) { String data = c.getString(c.getColumnIndex(MediaStore.Images.Thumbnails.DATA)); String imageId = c.getString(c.getColumnIndex(MediaStore.Images.Thumbnails.IMAGE_ID)); thumbnailPaths.add(data); thumbnailIds.add(imageId); c.moveToNext(); } c.close(); }

Slide 21

Slide 21 text

ポイント2: 適切なサイズを使う たいていの記事では MediaStore.Images.Media.EXTERNAL_CONTENT_URI を使っているので、もとのサイズのイメージを読み込んでいる MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI を使いましょう Thumbnailのサイズ ● MINI_KIND: 512 x 384 ● MICRO_KIND: 96 x 96

Slide 22

Slide 22 text

MediaStoreのイメージ図 Files - FileColumns - MEDIA_TYPE - MIME_TYPE - TITLE ... その他、有象無象 Audio - Media - Alubms - Artists ... Images - Media - Thumbnails - ImageColumns Video - Media(本体) - Thumbnails - VideoColumns

Slide 23

Slide 23 text

注意 ● Thumbnailは回転情報がなく、横向きで表示されるものもある 「 CursorJoinerを使ってMediaStore.Images.Thumbnailsに回転情報を追加する」 tomoima525さん http://qiita.com/tomoima525/items/762a55a86b3decf05d55 ● Thumbnailをそのまま使用しないように気をつける MediaStore.Images.Thumbnails.IMAGE_IDとMediaStore.Images.Media._IDが等しいことを利用

Slide 24

Slide 24 text

MediaStoreのイメージ図 Files - FileColumns - MEDIA_TYPE - MIME_TYPE - TITLE ... その他、有象無象 Audio - Media - Alubms - Artists ... Images - Media - _ID - Thumbnails - IMAGE_ID - ImageColumns Video - Media(本体) - Thumbnails - VideoColumns 等しい

Slide 25

Slide 25 text

ポイント3: 使い方に合わせて表示する ● メッセージやSNSなど: 今撮ったsnowの写真がほしい → 撮影した写真が上に来るように → 選択したらすぐに送信できるように ● 画像加工など: プレビューしてから選ぶかもしれない → 拡大縮小できるプレビューを挟む → サムネイルじゃだめ(えっ

Slide 26

Slide 26 text

サンプルつくりました ● 普通の3カラムサンプル ● Facebook Messengerサンプル ● InstagramのDMサンプル https://github.com/kaelaela/AndroidImageGallerySample ※API level 16以上

Slide 27

Slide 27 text

ありがとうございました!