20190226のAndroidに関する記事は9件です。

Kotlin用ドキュメント生成ツール「dokka」のセットアップ&操作方法

「dokka」とは?

Kotlin用のドキュメント自動生成ツールです。
Kotlin公式が提供しています。

環境

  • OS:macOS Mojave 10.14
  • Kotlin:1.3.21
  • Gradle:5.2.1
  • dokka:0.9.17

セットアップ

appフォルダ配下の「bundle.gradle」にdokkaのプラグインと設定を追加します。

/app/build.gradle
apply plugin: 'kotlin-android'
+ apply plugin: 'org.jetbrains.dokka-android'
+ dokka {
+     outputFormat = 'html' 
+     outputDirectory = "$buildDir/javadoc"
+ }

ルート直下の「bundle.gradle」にdokkaのバージョンとクラスパスを追加します。

/build.gradle
buildscript {
    ext.kotlin_version = '1.3.21'
+     ext.dokka_version = '0.9.17'
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+         classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:${dokka_version}"
    }
}

実装

ドキュメント化したいメソッドやプロパティにドキュメンテーションコメント(KDoc)を付けます。

MainActivity.kt
package com.example

import android.os.Bundle
import android.support.v7.app.AppCompatActivity

/**
 *  メインアクティビティ
 */
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    /**
     *  2つの数字を足す
     *
     *  @param x 数字1
     *  @param y 数字2
     *  @return 数字1 + 数字2
     */
    fun add(x: Int, y: Int): Int {
        return x + y
    }

}

ドキュメントの生成・閲覧

Android Studioのターミナルで ./gradlew dokka を実行すると、 outputDirectory で指定したフォルダ(/app/build/javadoc/)内にドキュメントが生成されます。

「…javadoc/app/index.html」をWebブラウザで開くとドキュメントを閲覧できます。

スクリーンショット_2019-02-26_23_59_18.jpg
スクリーンショット_2019-02-27_0_01_45.jpg
スクリーンショット_2019-02-26_23_46_37.jpg

非常にシンプルなデザインです。

おわりに

ここでは簡単にしか紹介していません。
dokkaの使い方についてもっと詳細に知りたい場合は参考リンクなどをご参照ください。

KDocについては以下のページが参考になります。
https://kotlinlang.org/docs/reference/kotlin-doc.html
https://qiita.com/opengl-8080/items/fe43adef48e6162e6166

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ARCore01-HelloAR

專案位置

gitlab:https://gitlab.com/kangyueLuo/helloar

起源

對於擴增世界應用的喜愛,在加上 Google ARCore 降低了使用擴增實境技術的門檻,及 Youtube 上許多教學影片,幫助我推開了 AR世界的門。

參考資料

https://www.youtube.com/watch?v=EWXGaypl2ms&index=2&list=PLsOU6EOcj51cEDYpCLK_bzo4qtjOwDWfW&fbclid=IwAR3lJFYH9b_MptZHkTkbSA3Ri1Cqr7Tuq1XqAkTSHxQef3K_X2wHImoFTNU

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dynamic Feature Moduleに対応したアプリを、単一apk化する

Dynamic Feature Moduleに対応すると、

./gradle assembleDebug

とかの実行時、apkが複数作られるようになります。
AndroidStudioでビルドするときは ▶ ボタンで動くけれど、コマンドラインからのインストールだと

adb install-multiple app.apk feature.apk

みたいにしないといけない。
何より、複数apkだとDeployGateとかでの社内配布で困る…(というか無理)
という場合、以下のようなコマンドでuniversalなapkを作成できます

./gradle packageDebugUniversalApk

apkファイルは、

/app/build/outputs/universal_apk/${variant.name}/app-${variant.baseName}-universal.apk

とかあたりに作られます。
${variant.name}${variant.baseName} は、gradleでの実行時のvariantのパラメータです。 flavordevbuildTypedebug だとすると、それぞれ devDebug , dev-debug という感じになります。

なお、本件対応時、CIにて

Program type already present: android.databinding.layouts.DataBindingInfo

のようなエラーがでたのですが、 com.android.tools.build を最新(本記事執筆時点では 3.3.1)まで上げると解消しました。
こちらの内容ですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Toastには通知元アプリを識別する情報を表示した方が良いという話

概要

AndroidでToastを表示した際、通知元のアプリを識別してもらうために、Toastに何かしらのアプリ情報を表示した方が良いと思う、という開発者向けの話です。

Toastについて

Androidで簡易なメッセージをユーザに表示するには、Toastを使うことが多いと思います。Toastはダイアログと異なり、Activityが無くても表示することができます。具体的には、ServiceやBroadcastReceiverなどのバックグラウンドで動作するクラスでも、Contextが参照できれば呼び出すことができます。つまり、次のように別のアプリの上やホーム画面にToastを表示することができてしまいます。

Toastの問題

ここで問題になるのは、このToastを表示している元のアプリを識別することが出来ないという点です。

自分の端末では一時期、「Account has not been authenticated」という内容(うろ覚え)のメッセージが不定期に表示されるという事象が発生していました。恐らく何れかのアプリが何らかのイベントをトリガーにしてToastを表示していたのだと思いますが、そのアプリが何か分からず、面倒で放置してたらいつの間にか出なくなってしまったので、結局どのアプリだったのかは分からず仕舞いでした。

こうした、どのアプリが出したメッセージなのかが分からない状況は、ユーザにとって決して好ましい状態ではありません。実際自分は、表示されたメッセージに対応することができなかったどころか、正体不明のメッセージが表示されて気味が悪いという印象を持ちました。ユーザに対して配慮したつもりが、まったくの逆効果となっています。

想定される状況

画面を表示していない状態でToastが表示される場合、次のようなタイミングでToastを表示するアプリの存在が考えられます(他にもあると思いますが)。

  • 起動中のService(Android 8.0以降はForegroundService)からの実行
  • JobScheduler実行時
  • BroadcastReceiver受信時(参考:暗黙的なブロードキャストの例外)
  • プッシュ通知受信時
  • 非同期処理を動かしたまま画面を閉じ、かつプロセスが生きたままの状態

対応

この状況に対して、開発アプリにはToastにアプリを識別する情報を表示するのが望ましいのではないかと考えました。この場合、次の2パターンがあるかと思います。

1. Toastにアプリ名を表示する

Toastにアプリ名を表示します。メリットとしては、通常のToast表示でも対応可能なことです。デメリットとしては、長い名前だとメッセージの邪魔になります。

2. Toastにアイコンを表示する

アプリを識別できるアイコンを表示します。メリットはメッセージ表示領域の邪魔にならないこと、デメリットはToastは標準で画像を表示することはできないので、別途Viewを作成するか、ライブラリを使用する必要があることです。
次の画像はDynamic Toastsライブラリを使用した場合の表示です。

最後に

個人的には、アイコンを表示するのが適当かと考えています。
注意点としては、いくらアイコンを付与したところで、ユーザがそのアイコンから元アプリを識別できなければ意味がないので、ランチャーアイコンや通知アイコンなど、ユーザが普段目にするアイコンを使用するのが適切かと思います。

こうした「ユーザがToastの表示元を識別できない」問題を考えると、今後Toastの表示に何らかの仕様変更が加えられるような気はします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityPurchasing: InitializationFailureReason.PurchasingUnavailable

The official document says that when this error happens it means

IAP may be disabled in security settings: iOS devices only
The system purchasing library may be outdated

My case did not fall into any of the above but simply because I have not logged into my Google account on the test device yet.
If you encounter the above error on Android, it may help to check if the Play Store has been set up properly before trying anything else.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pageViewにscaleType="fitXY"を適用する方法

通常のimageViewならXMLファイルにscaleType="fitXY"を入れるだけで縦横比を無視して画面いっぱいに表示することができるかと思います。
しかし、pageViewの場合は何やらうまくいかなかったので。
何も手を加えなければ画像の縦横比を保ってしまうので画像が切れてしまいます。

今回は、画像がページ全体を覆っている場合を想定しています。
tinderのスワイプ画面なんかがまんまこれですね。
アンドロイドで複数の実機で試したところ、画像のサイドが切れてしまったので対策しました。

①最初に試したこと(失敗)
Glideを使う前のimageViewの段階で、setScaleType(ImageView.ScaleType.FIT_XY)を用いる

ImageView imageView = new ImageView(getActivity());
RequestOptions options = new RequestOptions()
                .placeholder(R.drawable.hoge1)
                .error(R.drawable.hoge2));
String link = ServerConfig.hoge3;
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
Glide.with(getContext()).load(link).apply(options).into(imageView);

無反応でした。

②optionsにcenterCrop()を追加してみる(失敗: 原因不明)

ImageView imageView = new ImageView(getActivity());
RequestOptions options = new RequestOptions()
                .centerCrop()
                .placeholder(R.drawable.hoge1)
                .error(R.drawable.hoge2);
String link = ServerConfig.hoge3;
Glide.with(getContext()).load(link).apply(options).into(imageView);

なぜか無反応

③ optionsにfitCenter()を追加してみる(成功)

ImageView imageView = new ImageView(getActivity());
RequestOptions options = new RequestOptions()
                .fitCenter()
                .placeholder(R.drawable.hoge1)
                .error(R.drawable.hoge2);
String link = ServerConfig.hoge3;
Glide.with(getContext()).load(link).apply(options).into(imageView);

fitCenter()でできてcenterCrop()でダメなのはなぜなのか。
ちょっと調べましたが出てこないので結果だけ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

巨大なファイルを含んだリポジトリの履歴を改変して GitHub にインポートする方法

概要

GitHub.com には巨大なファイルを含んだコミットに対して push 制限があります。

具体的には push をする際、 次のようなメッセージが表示されます

  • コミットに 50MB を超えるファイルが含まれている場合は warning が表示されます
    • warning は表示されるものの、リモートへの転送自体は成功します。(ただし非推奨)
remote: warning: Large files detected.
remote: warning: File big_file is 55.00 MB; this is larger than GitHub's recommended maximum file size of 50 MB
  • コミットに 100MB を超えるファイルが含まれている場合は error が表示されます
    • リモートへの転送に失敗します
remote: warning: Large files detected.
remote: error: File giant_file is 123.00 MB; this exceeds GitHub's file size limit of 100 MB

上記の問題は、以下のいずれかの対応をすることで解決できます。
1. 対象ファイルが必要な場合は、Git-LFS を利用する Versioning large files
2. 対象ファイルが不要な場合は、リポジトリから取り除く Removing files from a repository's history

この記事では、後者の巨大なファイルをリポジトリから取り除く 2 通りの手順について紹介します。

具体例

プロジェクトで利用するために、外部で構成管理されているリポジトリを GitHub.com にインポートするケースについて考えてみます。

例えば Android オープンソースプロジェクト(以下 AOSP)は android.googlesource.com で公開されていて 1,000 を超える Git リポジトリから構成されています。これらのリポジトリの中には、「巨大なファイルが含まれている、または過去に含まれていた」リポジトリがあり、GitHub.com でそのままインポートすることができません。

  • 実際、見つかった巨大なファイルの多くは、通常のソースコードではなくビルド済みバイナリであったりテストデータであったりします。

次のステップでは、実在する外部管理のリポジトリを GitHub.com にインポートする処理を行います。

Step0 インポート時に git-push が失敗することの確認

巨大なファイルが含まれていることがあらかじめ判明している AOSP の platform/system/core.git を題材として、GitHub.com へのインポートに失敗することを確認します。

まずは以下の手順でインポートを試みます。

$ git clone --mirror https://android.googlesource.com/platform/system/core
$ git remote add github $YOUR_GITHUB_URL
$ git push --mirror github

remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
remote: error: Trace: be6e0a48b32da493f6a767241ba85e9b
remote: error: See http://git.io/iEPt8g for more information.
remote: error: File libunwindstack/tests/files/offline/jit_debug_x86_32/libartd.so is 219.06 MB; this exceeds GitHub's file size limit of 100.00 MB

 ! [remote rejected] android-9.0.0_r16 -> android-9.0.0_r16 (pre-receive hook declined)

ここで上記のエラーが出ました。エラー内容から 200MB を超える共有ライブラリ libartd.so がコミットされていたため push に失敗したことがわかります。

次のステップでは、巨大なファイルの正体を特定します。

Step1 対象ファイルの特定する

200MB を超える共有ライブラリがコミットが含まれていたため、 GitHub.com への push に失敗しました。ところが実際は、この共有ライブラリは指定のパスには既に libartd.so は存在しません。

$ test -e libunwindstack/tests/files/offline/jit_debug_x86_32/libartd.so

次に、既に削除済みファイルであることを確認します

$ git log --diff-filter=D --summary -- libunwindstack/tests/files/offline/jit_debug_x86_32/libartd.so

delete mode 100644 libunwindstack/tests/files/offline/jit_debug_x86_32/libartd.so

つまり、例え削除済みであっても、巨大ファイルを含んだコミットがあったことには変わりないため、push に失敗したことがわかりました。このように push に失敗する前に、リポジトリの中に含まれた巨大なファイルをあらかじめ確認するためには、Atlassian の Reduce repository size で紹介されている git_find_big.sh を活用すると良いことが知られています。このスクリプトでは Git 内部の パックファイル を走査して、巨大なファイルのサイズ順に表示してくれます。今回扱う platform/system/core.git リポジトリを対象に git_find_big.sh を実行すると次の結果が得られます。

All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file.
size    pack   SHA                                       location
224312  60015  70352dbb7a51e338096bb1305ea63641a39200cd  libunwindstack/tests/files/offline/jit_debug_x86_32/libartd.so
28051   7497   e72e673ad74ff69060291ddab1a3989a7c6a8c07  libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so
10380   3225   92ed9915d4f9ea96a4accfcad82c657ff72f17fd  libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
8127    3048   ef1a6a1857bc2613a9ae162dd56f2cb67858eb3a  libbacktrace/testdata/arm64/libskia.so
5968    2422   05278936be5fda0f62b5bd37b6951bcdbb5e8cd2  libunwindstack/tests/files/offline/jit_debug_arm/libart.so
5952    2401   09ba49532205981ff638c6935436cbb09d678aba  libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so
5400    2175   bed8e3595aa8cab7f381cfcb7aa05d10f010e687  libbacktrace/testdata/arm/libart.so
5294    2610   855905655e4c822794b6d66657c657b5307f17c9  libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
5076    1392   092fc3aec90445662e23c2fdca8207e031602793  libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
4134    1369   871f6dc89e9fb88b8758f5ef2deb2224295f8411  libbacktrace/testdata/arm/libGLESv2_adreno.so

上記の結果から、 50MB を超える巨大なファイルは libartd.so だけであることが明らかになりました。

したがって、
1. 過去に管理されていた巨大なファイルが参照できなくても問題ないこと
2. 対象コミット以降のすべてのコミットハッシュ(SHA-1)が変わっても問題ないこと

上記のポイントを理解したうえで、それでも問題がなければ、次のステップで、対象コミットを削除するためにコミット履歴を書き換えます。

Step2 コミット履歴の書き換え

Step2a コミット履歴の書き換え: git-filter-branch を用いた場合

git-filter-branch コマンドを用いることで、コミット履歴を書き換えることができます。
すべてのブランチ・タグから対象の巨大なファイルを rm する場合は、次のコマンドで実現できます

$ time git filter-branch --index-filter 'git rm --ignore-unmatch libunwindstack/tests/files/offline/jit_debug_x86_32/libartd.so' --tag-name-filter 'cat' -- --all

オプションの説明:

  • --index-filter <command>
    • 各コミットハッシュに対して <command> を実行します
  • --tag-name-filter <command>
    • コミット履歴の書き換えに際し、新しいコミットハッシュに対してタグを上書きするオプションです
    • <command> の規則にしたがってタグ名を上書きします
    • 元のタグ名のままタグを上書きする場合
      --tag-name-filter 'cat'
    • すべて大文字でタグを上書きする場合
      --tag-name-filter 'cat | tr [:lower:] [:upper:]'
    • タグを上書きしても元のメッセージやタイムスタンプ、Tagger は変化しませんが、 タグにつけられた GPG 署名はストリップされます
  • -- --all
    • git-filter-branch の対象とするコミットハッシュを取得する際の git-rev-list に渡すオプションです
    • 今回の目的はすべてのブランチ・タグから巨大なファイルを削除したいので --all とします

ファイル削除の確認手順

上記 git-filter-branch を実行後、 libartd.so の削除が正しく行われたことを確認します。

$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
  • git-filter-branch によって退避された refs/original のすべての参照を git-update-ref で削除します
$ git reflog expire --expire=now --all
  • アクセスできないすべての無効な reflog エントリを削除します
$ git gc --prune=now
  • git-gc で GC を実行し、古いオブジェクトを削除して、パックファイルを更新します

その後 git_find_big.sh を再実行します

All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file.
size   pack  SHA                                       location
28051  7497  e72e673ad74ff69060291ddab1a3989a7c6a8c07  libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so
10380  3200  92ed9915d4f9ea96a4accfcad82c657ff72f17fd  libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
8127   3048  ef1a6a1857bc2613a9ae162dd56f2cb67858eb3a  libbacktrace/testdata/arm64/libskia.so
5968   2417  05278936be5fda0f62b5bd37b6951bcdbb5e8cd2  libunwindstack/tests/files/offline/jit_debug_arm/libart.so
5952   2401  09ba49532205981ff638c6935436cbb09d678aba  libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so
5400   2170  bed8e3595aa8cab7f381cfcb7aa05d10f010e687  libbacktrace/testdata/arm/libart.so
5294   2607  855905655e4c822794b6d66657c657b5307f17c9  libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
5076   1391  092fc3aec90445662e23c2fdca8207e031602793  libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
4134   1362  871f6dc89e9fb88b8758f5ef2deb2224295f8411  libbacktrace/testdata/arm/libGLESv2_adreno.so
3695   1604  7a30bfa440efc24d651b544163e5574d6b027a63  libunwindstack/tests/files/offline/offset_arm/libunwindstack_test

上記のとおりようやく 50MB を超える libartd.so が存在しなくなっていることが確認できました。

ところがここで一つ課題があります。

今回の作業は Azure D2V2 (Core=8, RAM=28GB, SSD=400GB) インスタンスで行いましたが、実行時間は real 15m48.335s と 15 分以上要しました。実行時間をより短くするために、次のステップでは、 BFG という機能を絞ったシンプルかつ高速なツールを紹介します。

Step2b コミット履歴の書き換え: BFG を用いた場合

BFG は Scala 製でシンプルかつ高速なツールです。 git-filter-branch ほど複雑な処理はできませんが、今回の目的に最も適した --strip-blobs-bigger-than <MB> という便利なオプションがあります。再度取得し直した platform/system/core.git にこのツールを適用してみます。

$ java -jar bfg.jar --strip-blobs-bigger-than 50M platform/system/core.git

オプションの説明:

  • strip-blobs-bigger-than 50M
    • 50MB より大きなすべての blob を削除します

実行結果

Scanning packfile for large blobs: 140503
Scanning packfile for large blobs completed in 1,009 ms.
Found 1 blob ids for large blobs - biggest=229696508 smallest=229696508
Total size (unpacked)=229696508
Found 1897 objects to protect
Found 687 tag-pointing refs : refs/tags/afw-test-harness-1.5, refs/tags/afw-test-harness-2.1, refs/tags/android-1.6_r1, ...
Found 190 commit-pointing refs : HEAD, refs/heads/master, refs/remotes/origin/HEAD, ...

Protected commits
-----------------

These are your protected commits, and so their contents will NOT be altered:

 * commit f80c326d (protected by 'HEAD')

Cleaning
--------

Found 45661 commits
Cleaning commits:       100% (45661/45661)
Cleaning commits completed in 4,047 ms.

Updating 89 Refs
----------------

    Ref                                                     Before     After   
    ---------------------------------------------------------------------------
    refs/heads/master                                     | f80c326d | 9a90afc4
    refs/remotes/origin/master                            | f80c326d | 9a90afc4
    refs/remotes/origin/master-cuttlefish-testing-release | fd088948 | 9c55624d
    refs/remotes/origin/nougat-iot-release                | 044e0276 | 52cd619d
    refs/remotes/origin/o-mr1-iot-preview-7               | 2b49abe4 | 8ff6ed0b
    refs/remotes/origin/o-mr1-iot-preview-8               | 22dc27b9 | 219cb8c9
    refs/remotes/origin/oreo-mr1-1.2-iot-release          | c53a0e91 | 8e1c9575
    refs/remotes/origin/oreo-mr1-iot-release              | f307efcf | 9ee5bb5f
    refs/remotes/origin/pie-cts-dev                       | 2ef5c2ef | 1be06911
    refs/remotes/origin/pie-cts-release                   | bfe37429 | 0710a778
    refs/remotes/origin/pie-cuttlefish-testing            | 17b9e8e0 | 7135e773
    refs/remotes/origin/pie-dev                           | 820ef150 | c9998b31
    refs/remotes/origin/pie-dr1-dev                       | 93d837f3 | bfe27d17
    refs/remotes/origin/pie-dr1-release                   | 47e38865 | 92fcac25
    refs/remotes/origin/pie-gsi                           | afc32531 | 788ecf39
    ...

Updating references:    100% (89/89)
...Ref update completed in 55 ms.

Commit Tree-Dirt History
------------------------

    Earliest                                              Latest
    |                                                          |
    .....................................................DDmmmmm

    D = dirty commits (file tree fixed)
    m = modified commits (commit message or parents changed)
    . = clean commits (no changes to file tree)

                            Before     After   
    -------------------------------------------
    First modified commit | 150db124 | ecbcdafc
    Last dirty commit     | e242a97d | cd89e6b1

Deleted files
-------------

    Filename     Git id             
    --------------------------------
    libartd.so | 70352dbb (219.1 MB)

BFG run is complete! When ready, run: git reflog expire --expire=now --all && git gc --prune=now --aggressive

上記のような実行レポートのサマリーが得られます。

  • Deleted files から何が削除されたかも明らかになりました。

より詳細な実行レポートはリポジトリ脇のディレクトリ配下に次の形式で残されています。

  • cache-stats.txt
  • deleted-files.txt
  • object-id-map.old-new.txt

そして実行結果はわずか real 0m9.403s で、 git-filter-branch よりも 100 倍前後高速に結果が得られました。また git_find_big.sh の内容も Step2a と同一でした。

Step3 インポート成功確認

最後に GitHub.com にインポートできることを確認します。

$ git push --mirror github

今度は無事成功しました。

上記 Step2a, Step2b のどちらの手法を用いても巨大なファイルは削除され、 git-push できるようになったことが確認されました。

削除できない巨大なファイルが含まれている場合は

今回の例では、見つかった巨大なファイルが不要なため削除できるケースでしたが、削除できない場合はどうでしょうか。まずは Git LFS を利用するのが最も素直な解になります。それでもプロジェクトの都合で Git LFS が利用できない場合は巨大なファイルを分割したり、圧縮したりする回避策もあるかもしれません。

管理方法

$ md5sum $LARGEFILE > $LARGEFILE.md5
$ split $LARGEFILE -b 10M $LARGEFILE-
  • 元ファイルのチェックサムと数 MB ごとに分割したファイルとして管理します

復元方法

$ cat $LARGEFILE-* > $LARGEFILE
$ md5sum -c $LARGEFILE.md5
  • githookspost-merge やビルドシステムなどで fetch 後に復元処理と元ファイルとの完全性を確認します

ただし what-is-my-disk-quota にもあるように GitHub ではリポジトリのサイズは 1GB 以下を推奨されているため、分割管理をしたとしてもサイズの総和の制約は回避できません。

まとめ

この記事では、不要かつ巨大なファイルが含まれたリポジトリを GitHub.com にインポートする手順についてまとめました。git-filter-branch でも BFG でも不要なファイルを扱ったコミットを除去できることが確認できました。単純に巨大なファイルを削除するだけが目的なら BFG を用いて、タグを一意の命名規則に沿って上書きしたり、ブランチ別に処理を分ける等、より複雑な操作をするときは git-filter-branch を用いると良いと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【ImageView】ScaleTypeを変更したときの内部処理

ScaleTypeと表示画像の対応を整理するために作成したサンプルアプリで、ScaleTypeFIT_STARTFIT_XYMATRIXと切り替えたときにFIT_STARTMATRIXのときの画像表示が同じになる現象が発生したので、備忘録を兼ねてその際に調査した内容をまとめました。

ScaleTypeを変更したときの内部処理

ImageView.javaのソースはこちらにあります。

まず、ScaleTypeを切り替えるためにsetScaleType()を呼び出します。
引数に指定されたScaleTypemScaleTypeに代入されます。

ImageView.java#LL.827-838
public void setScaleType(ScaleType scaleType) {
  if (scaleType == null) {
    throw new NullPointerException();
  }

  if (mScaleType != scaleType) {
    mScaleType = scaleType;

    requestLayout();
    invalidate();
  }
}

  
このmScaleTypeconfigureBounds()内で分岐条件として使われます。
以下、今回の調査に必要な条件のみを抜粋します。

mScaleType == MATRIXのとき、以下のような処理が行われます。

ImageView#LL.1253-1257
if (mMatrix.isIdentity()) {
  mDrawMatrix = null;
} else {
  mDrawMatrix = mMatrix;
}

mMatrixMatrixの参照を持つ変数です。mDrawMatrixmMatrixの参照を代入するための変数です。この2つの変数によってMatrixによる画像変換を行うか否かを制御しています。
mMatrixが単位行列(変換前後で画像の状態を変化させないMatrix)の場合、mDrawMatrixにnullを代入しています。

mScaleType == FIT_CENTER、FIT_END、FIT_STARTのとき、以下のような処理が行われます。

ImageView#LL.1302-1306
mTempSrc.set(0, 0, dwidth, dheight);
mTempDst.set(0, 0, vwidth, vheight);

mDrawMatrix = mMatrix;
mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));

ネイティブコードを呼び出していたので詳細は確認できなかったのですが、最後のsetRectToRect()によってmScaleTypeに対応したMatrixを計算しているようです。
この処理によってmDrawMatrixの参照先の内容が更新されることがEvaluate Expressionでトレースすることによって分かりました。

mScaleType == FIT_XYのとき、以下のような処理が行われます。
vwidthvheightはそれぞれImageViewの幅と高さです。

ImageView.java#LL.1244-1245
mDrawable.setBounds(0, 0, vwidth, vheight);
mDrawMatrix = null;

  
そして、mDrawMatrixonDraw()内で分岐条件として使われています。
mDrawMatrixがnullでないときのみMatrixによる画像変換が行われます。

ImageView.java#LL.1350-1383
@Override
protected void onDraw(Canvas canvas) {
  ...
  if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
    mDrawable.draw(canvas);
  } else {
    ...
    if (mDrawMatrix != null) {
      canvas.concat(mDrawMatrix);
    }
    mDrawable.draw(canvas);
    canvas.restoreToCount(saveCount);
  }
}

  
以上を踏まえ、改めて状況を整理します。

ScaleTypeFIT_STARTFIT_XYMATRIXと切り替えたとき、

  • FIT_START
    • ②の処理が行われるので、mMatrixの参照先のMatrixの内容はFIT_STARTに対応した値になる
    • mDrawMatrixはnullでないので、Matrixによる画像変換が行われる
  • FIT_XY
    • ③の処理が行われるので、mMatrixの参照先のMatrixの内容はFIT_STARTに対応した値のままになる
    • mDrawMatrixはnullなので、Matrixによる画像変換は行われない
  • MATRIX
    • ①の処理が行われるので、mMatrixの参照先のMatrixの内容はFIT_STARTに対応した値のままになる
    • mDrawMatrixはnullでないので、Matrixによる画像変換が行われる

となるため、FIT_STARTMATRIXのときの画像表示が同じになっていました。

最後に、この現象を回避するためにScaleTypeを変更する前にsetImageMatrix()を呼び出します。

ImageView.java#LL.871-884
public void setImageMatrix(Matrix matrix) {
  // collapse null and identity to just null
  if (matrix != null && matrix.isIdentity()) {
    matrix = null;
  }

  // don't invalidate unless we're actually changing our matrix
  if (matrix == null && !mMatrix.isIdentity() || matrix != null && !mMatrix.equals(matrix)) {
    mMatrix.set(matrix);
    configureBounds();
    invalidate();
  }
}

setImageMatrix()の引数に新しい単位行列を代入することでmMatrixが初期化されます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Notificationのタイトルに色を付ける方法

こったプッシュ通知(notification)だと色付きのものをよく見るがそれをする方法
意外と調べても出てこなかったので掲載

addColorMethod.kt
private fun addColor(title: String): SpannableString {
    return SpannableString(title).apply {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            return@apply
        }
        setSpan(ForegroundColorSpan(ContextCompat.getColor(context,
                R.color.notification_job_title_text)), 0, title.length, 0)
    }
}
NotificationCompatBuilderでの利用法.kt
NotificationCompat.Builder(yourContext, "yourId")
    .setContentTitle(addColor("your notification title"))
    .set .. // 中略
    .build()

現場からは以上です

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む