- 投稿日:2021-03-22T23:16:43+09:00
Activityを保持しない場合のonActivityResult
はじめに
Activityを保持しない場合も動作するように修正しようとしたら、ハマってしまい苦労したので備忘録として書きます。
Intentで他のアプリを起動した場合など、Activityがバックグラウンドに移動した時にメモリが足らなくなると、
もともと起動していたアプリ(Activity)を終了してメモリを確保するみたいです。
この時、アプリが復帰する動作が通常とは異なる動きをするので注意が必要です。
ただ、裏ですごいリッチでグラフィカルなゲームを起動してるとか、動かしてるアプリがめちゃめちゃメモリ喰うとか、端末が古くてすごい非力な場合とかの少し特殊な場合でしか起こり得ないことなので気づきにくいかもしれません。結論
onActivityResultとonStartの呼び出し順が変わるので注意!!
再現方法
開発者向けオプションから「アクティビティを保持しない」の項目をONにすることで、Activityがバックグラウンドに移動した場合に常に終了するようにできます。
ライフサイクル
Activityを保持する/しないの両方共動くようにしようとしたら、思ったように動かせなくてActivityのライフサイクルの動作を確認したら次のようになっていました。
Activityを保持する場合(通常動作)
onCreate
→ onStart
→ onResume
→ (アプリを操作、startActivityForResult)
→ onPause
→ onStop
→ (Intentで他のアプリを起動) ※ここまでは一緒
→ onActivityResult
→ onStart
→ onResumeActivityを保持しない場合
onCreate
→ onStart
→ onResume
→ (アプリを操作、startActivityForResult)
→ onPause
→ onStop
→ (Intentで他のアプリを起動) ※ここまでは一緒
→ onDestroy
→ onCreate
→ onStart
→ onActivityResult
→ onResume上記の両者を比較すれば分かると思いますが、
onStartとonActivityResultの順番が変わっています。Activityを保持しないのでonDestroyとonCreateが増えるのは想定通りでしたが、ライフサイクルの実行順が変わるのは想定外でした。
(ライフサイクルをちゃんと理解できていないだけ?)
とりあえずonStartで設定する内容は気をつけないといけない。。。
- 投稿日:2021-03-22T22:35:55+09:00
Kotlinで文字列を選択できるドラムロールをシンプルに実装
NumberPickerを使ってドラムロールを実装する
Kotlinならドラムロールはわりと簡単に実装できます。
ドラムロールを実装
レイアウトにドラムロールとなるNumberPickerを追加します。
activity_main.xml<NumberPicker android:id="@+id/picker" android:layout_width="wrap_content" android:layout_height="wrap_content"/>onCreateメソッドでNumberPickerに文字列をセットしていきます。
MainActivity.ktoverride fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //ドラムロール表示用の配列作成 val fruits = arrayOf("りんご", "いちご", "みかん") //NumberPickerを取得 val picker = findViewById<NumberPicker>(R.id.picker) //配列のインデックス最小、最大を指定 picker.minValue = 0 picker.maxValue = fruits.size - 1 //NumberPickerに配列をセットする picker.displayedValues = fruits値の取得
決定ボタンのクリックリスナーなどで値を取得します。
MainActivity.kt//選択されている項目のインデックス番号を取得 val index = picker.value //フルーツの配列からインデックス番号を指定して取得 val fruit = fruits[index]
- 投稿日:2021-03-22T22:28:00+09:00
[Android/Java] Jetpack LiveData (Jetpack ViewModel MVVM+Repositoryパターン)
Android Studio 4.1.3(windows版) での流れとなります
ここではMutableLiveDataをRepositoryで持ち単純なデータのModelを扱うだけの
シンプルな構成で一連の流れを説明します以下の記事のプロジェクトベースでの説明となります
Android DeveloperのJetpack LiveData/MVVM+Repositoryパターンの説明は以下です
Layoutの準備
ここではViewBindingを使用して実装します
ViewBindingの設定方法を知りたい方は以下を参照してください
MainFragmentのテンプレートにあるTextViewはidが指定されていないため
ここではtextViewを指定しますデータのModelを作成
ここでは単純なString Nameだけを持つUserModelを用意します
UserModel.javapublic class UserModel { public String Name; }Repositoryを作成
ここではUserModelを扱うMutableLiveDataとそのgetterとNameをセットするメソッドを用意します
※ データの更新を行うためMutableLiveDataを使用します
setValue()/postValue()の違いを詳しく知りたい方は他の方の記事でいくつか説明がありますので探してみてくださいMainRepository.javapublic class MainRepository{ final MutableLiveData<UserModel> user = new MutableLiveData<>(); public MutableLiveData<UserModel> getUser() { return user; } public void setName(String name) { UserModel userModel = user.getValue(); if (userModel == null) { Log.d("MainRepository", "user = null"); userModel = new UserModel(); } userModel.Name = name; // setValue()はメインスレッドから呼び出す必要があります //user.setValue(userModel); user.postValue(userModel); } }ViewModelの実装
Repositoryのインスタンスを生成
Repositoryのメソッドの呼び出し用のメソッドを用意しますMainViewModel.javapublic class MainViewModel extends ViewModel { // TODO: Implement the ViewModel final MainRepository repository = new MainRepository(); public MutableLiveData<UserModel> getUser() { return repository.getUser(); } public void setName(String name) { repository.setName(name); } }Fragmentの実装
Fragmentの新規作成時に自動生成されたコードにViewModelの処理を追加します
Nameに値を設定するとobserveのonChanged()が呼び出されTextViewの内容が書き換えられますMainFragment.java@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mViewModel = new ViewModelProvider(this).get(MainViewModel.class); // setを実行するとobserveのonChanged()が呼び出されます mViewModel.setName("test"); mViewModel.getUser().observe(getViewLifecycleOwner(), new Observer<UserModel>() { @Override public void onChanged(UserModel user) { Log.d("MainFragment", user.Name); binding.textView.setText(user.Name); // getValue()で値の取得もできます Log.d("MainFragment", "getValue: " + mViewModel.getUser().getValue().Name); } }); }
- 投稿日:2021-03-22T22:28:00+09:00
[Android] Jetpack LiveData (Jetpack ViewModel MVVM+Repositoryパターン)
Android Studio 4.1.3(windows版) での流れとなります
ここではMutableLiveDataをRepositoryで持ち単純なデータのModelを扱うだけの
シンプルな構成で一連の流れを説明します以下の記事のプロジェクトベースでの説明となります
Android DeveloperのJetpack LiveData/MVVM+Repositoryパターンの説明は以下です
Layoutの準備
ここではViewBindingを使用して実装します
ViewBindingの設定方法を知りたい方は以下を参照してください
MainFragmentのテンプレートにあるTextViewはidが指定されていないため
ここではtextViewを指定しますデータのModelを作成
ここでは単純なString Nameだけを持つUserModelを用意します
UserModel.javapublic class UserModel { public String Name; }Repositoryを作成
ここではUserModelを扱うMutableLiveDataとそのgetterとNameをセットするメソッドを用意します
※ データの更新を行うためMutableLiveDataを使用します
setValue()/postValue()の違いを詳しく知りたい方は他の方の記事でいくつか説明がありますので探してみてくださいMainRepository.javapublic class MainRepository{ final MutableLiveData<UserModel> user = new MutableLiveData<>(); public MutableLiveData<UserModel> getUser() { return user; } public void setName(String name) { UserModel userModel = user.getValue(); if (userModel == null) { Log.d("MainRepository", "user = null"); userModel = new UserModel(); } userModel.Name = name; // setValue()はメインスレッドから呼び出す必要があります //user.setValue(userModel); user.postValue(userModel); } }ViewModelの実装
Repositoryのインスタンスを生成
Repositoryのメソッドの呼び出し用のメソッドを用意しますMainViewModel.javapublic class MainViewModel extends ViewModel { // TODO: Implement the ViewModel final MainRepository repository = new MainRepository(); public MutableLiveData<UserModel> getUser() { return repository.getUser(); } public void setName(String name) { repository.setName(name); } }Fragmentの実装
Fragmentの新規作成時に自動生成されたコードにViewModelの処理を追加します
Nameに値を設定するとobserveのonChanged()が呼び出されTextViewの内容が書き換えられますMainFragment.java@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mViewModel = new ViewModelProvider(this).get(MainViewModel.class); // setを実行するとobserveのonChanged()が呼び出されます mViewModel.setName("test"); mViewModel.getUser().observe(getViewLifecycleOwner(), new Observer<UserModel>() { @Override public void onChanged(UserModel user) { Log.d("MainFragment", user.Name); binding.textView.setText(user.Name); // getValue()で値の取得もできます Log.d("MainFragment", "getValue: " + mViewModel.getUser().getValue().Name); } }); }
- 投稿日:2021-03-22T20:04:09+09:00
backgroundとbackgroundTintの違い
android:background背景として使用するドローワブルで、描画可能なリソース(PNG画像、9パッチ1、 シェイプドローワブル2、色を指定します。
色の形式は「
#rgb、#argb、#rrggbb、#aarrggbb」があります。
android:backgroundTintbackgroundにカラーフィルターをかけて色を変化させることが出来ます。
例えば、
android:background="#FF0000"(赤)で、android:backgroundTint="#00FF00"(緑)を指定すると、#FFFF00(黄色)になります。色の形式は
android:backgroundと同じく、「#rgb、#argb、#rrggbb、#aarrggbb」があります。
backgroundTintには、android:backgroundTintModeというものがあり、色合いの「ブレンディングモード」を設定することが出来ます。
android:backgroundTintMode
android:backgroundTintMode="add"色合いと描画可能なカラーおよびアルファチャネルを組み合わせて、結果を有効なカラー値にクランプ(合わせるみたいな意味?)します(S + D)
android:backgroundTint="multiply"ドローアブルのカラーチャンネルとアルファチャンネルに色合いのチャンネルを掛けます。 [Sa * Da、Sc * Dc]
android:backgroundTint="screen"[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]
android:backgroundTint="src_atop"色合いはドローアブルの上に描画されますが、ドローアブルのアルファチャネルが結果をマスクします。 [Da、Sc * Da +(1-Sa)* Dc]
android:backgroundTint="src_in"色合いは、ドローアブルのアルファチャネルによってマスクされます。ドローアブルのカラーチャンネルは破棄されます。 [Sa * Da、Sc * Da]
android:backgroundTint="src_over"ドローアブルの上に色合いが描かれています。 [Sa +(1-Sa)* Da、Rc = Sc +(1-Sa)* Dc]
- 投稿日:2021-03-22T12:45:58+09:00
UnityでFacebookSDKのAndroidでログインエラーの解決方法
概要
UnityでFacebookSDKを使用してAndroidでログインエラーが出てしまう問題の解決方法
問題点
KeyStoreの作り方がFacebookで紹介されているものと別であったため、Unity上で表示されたキーハッシュが間違っていた
解決方法
確実なキーハッシュの取得方法はIResultのRawResultの中に記載されている
// 初期化等は割愛 FB.LogInWithReadPermissions(・・・, OnLogin); void OnLogin(IResult result) { // こいつを確認する!!! Debug.Log($"Raw:[{result.RawResult}]"); }その他エラー解消のための参考文献
- 投稿日:2021-03-22T12:44:21+09:00
[Android] Jetpack Navigation 画面遷移とFragment間のデータ受け渡し
Android Studio 4.1.3(windows版) での流れとなります
以下の記事のプロジェクトベースでの説明となります
Android DeveloperのJetpack Navigationの画面遷移とFragment間のデータ受け渡しの説明は以下です
SafeArgs を追加する
※ 現時点ではandroidx.navigation:navigation-safe-args-gradle-pluginをimplementationでは動作しないようです
※ androidx.navigationのバージョンに合わせて設定してくださいbuild.gradle(Project)buildscript { dependencies { def nav_version = "2.3.4" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }build.gradle(Module)apply plugin: "androidx.navigation.safeargs"画面遷移の準備
+ボタンを押してここではNextFragmentを追加します
MainFragmentのActionsの+ボタンを押して画面遷移を追加します
DestinationでnextFragmentを指定してAddボタンで追加します
Actionが追加されました
MainFragmentに画面遷移実行用のボタンとボタンイベントを追加します
ボタンイベントの設定方法を詳しく知りたい場合は以下を参考にしてください
ここではMainFragmentにonClickButtonメソッドを追加しJetpack Databindingでボタンイベントの紐づけをします
画面遷移処理の実装
MainFragment.javapublic void onClickButton() { final View view = binding.getRoot(); // MainFragmentDirectionsはsafeargsを有効にすることで自動生成されます NavDirections directions = MainFragmentDirections.actionMainFragmentToNextFragment(); Navigation.findNavController(view).navigate(directions); }Fragment間でデータを受け渡す場合
NextFragmentのArgumentsの+ボタンを押します
ここではName:Text Type:String とします
Action(やじるし)のArgument Default Values のdefault value に値を設定します
ここではnoneを設定 ※default valueを設定しないとActionクラスが自動生成されません
NextFragmentに渡したい値(ここでは"xxx")をsetします
MainFragment.javapublic void onClickButton() { final View view = binding.getRoot(); // MainFragmentDirections.ActionMainFragmentToNextFragment/setText()は自動生成されます MainFragmentDirections.ActionMainFragmentToNextFragment action = MainFragmentDirections.actionMainFragmentToNextFragment(); action.setText("xxx"); Navigation.findNavController(view).navigate(action); }値を受け取ります
※ ここでは説明を簡略化してますが、実際はJetpack View/DataBindingを使用して値を設定してくださいNextFragment.java@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.next_fragment, container, false); // NextFragmentArgsは自動生成されます String text = NextFragmentArgs.fromBundle(getArguments()).getText(); TextView tv = view.findViewById(R.id.textView); tv.setText(text); return view; }
- 投稿日:2021-03-22T12:44:21+09:00
[Android/Java] Jetpack Navigation 画面遷移とFragment間のデータ受け渡し
Android Studio 4.1.3(windows版) での流れとなります
以下の記事のプロジェクトベースでの説明となります
Android DeveloperのJetpack Navigationの画面遷移とFragment間のデータ受け渡しの説明は以下です
SafeArgs を追加する
※ 現時点ではandroidx.navigation:navigation-safe-args-gradle-pluginをimplementationでは動作しないようです
※ androidx.navigationのバージョンに合わせて設定してくださいbuild.gradle(Project)buildscript { dependencies { def nav_version = "2.3.4" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }build.gradle(Module)apply plugin: "androidx.navigation.safeargs"画面遷移の準備
+ボタンを押してここではNextFragmentを追加します
MainFragmentのActionsの+ボタンを押して画面遷移を追加します
DestinationでnextFragmentを指定してAddボタンで追加します
Actionが追加されました
MainFragmentに画面遷移実行用のボタンとボタンイベントを追加します
ボタンイベントの設定方法を詳しく知りたい場合は以下を参考にしてください
ここではMainFragmentにonClickButtonメソッドを追加しJetpack Databindingでボタンイベントの紐づけをします
画面遷移処理の実装
MainFragment.javapublic void onClickButton() { final View view = binding.getRoot(); // MainFragmentDirectionsはsafeargsを有効にすることで自動生成されます NavDirections directions = MainFragmentDirections.actionMainFragmentToNextFragment(); Navigation.findNavController(view).navigate(directions); }Fragment間でデータを受け渡す場合
NextFragmentのArgumentsの+ボタンを押します
ここではName:Text Type:String とします
Action(やじるし)のArgument Default Values のdefault value に値を設定します
ここではnoneを設定 ※default valueを設定しないとActionクラスが自動生成されません
NextFragmentに渡したい値(ここでは"xxx")をsetします
MainFragment.javapublic void onClickButton() { final View view = binding.getRoot(); // MainFragmentDirections.ActionMainFragmentToNextFragment/setText()は自動生成されます MainFragmentDirections.ActionMainFragmentToNextFragment action = MainFragmentDirections.actionMainFragmentToNextFragment(); action.setText("xxx"); Navigation.findNavController(view).navigate(action); }値を受け取ります
※ ここでは説明を簡略化してますが、実際はJetpack View/DataBindingを使用して値を設定してくださいNextFragment.java@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.next_fragment, container, false); // NextFragmentArgsは自動生成されます String text = NextFragmentArgs.fromBundle(getArguments()).getText(); TextView tv = view.findViewById(R.id.textView); tv.setText(text); return view; }
- 投稿日:2021-03-22T12:43:32+09:00
android:translationX(translationY)とは
android:translationX(translationY)は、「座標」を使ってViewを位置を指定する属性です。android:translationX(translationY)共に、画面中央を0として「X座標」「Y座標」を指定します。
リファレンスによると、「px/dp/sp/in/mm」を指定出来るとのことです。
使い方
まずは、何も設定していない状態です。
android:translationX="100dp"を指定すると、右側に「100dp」だけ移動します。もし左側に移動させたい場合は、
android:translationX="-100dp"のようにマイナスを指定します。次は、Y座標で移動させるために
android:translationY="100dp"を指定します。上に移動させたいときはX座標のときと同様に、
android:translationY="-100dp"にマイナスを指定します。
- 投稿日:2021-03-22T12:35:37+09:00
【Kotlin 初心者】アプリにロゴを設置する方法
- 投稿日:2021-03-22T12:10:38+09:00
【Kotlin 初心者】カメラ、ローカルの画像を表示するには
Androidアプリでカメラ、ローカルから画像を表示する方法
シンプルにファイル or カメラのどちらかを選択し画像を表示してみます
イメージサンプル
- カメラを機能を有効にする
<manifest> <uses-feature android:name="android.hardware.camera" android:required="true" /> </manifest>activity_main.xml<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/upload_image" android:layout_width="300dp" android:layout_height="300dp" android:background="@color/teal_700" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>MainActivity.ktpackage com.example.myapplication import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory import android.os.Bundle import android.provider.MediaStore import android.widget.ImageView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val uploadImage = findViewById<ImageView>(R.id.upload_image) uploadImage.setOnClickListener { selectPhoto() } } companion object { private const val READ_REQUEST_CODE: Int = 42 } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) val uploadImage = findViewById<ImageView>(R.id.upload_image) if (resultCode != AppCompatActivity.RESULT_OK) { return } when (requestCode) { READ_REQUEST_CODE -> { try { data?.data?.also { uri -> val inputStream = contentResolver?.openInputStream(uri) val image = BitmapFactory.decodeStream(inputStream) uploadImage.setImageBitmap(image) } } catch (e: Exception) { Toast.makeText(this, "READ_REQUEST_CODEのエラーが発生しました", Toast.LENGTH_LONG).show() } } } } private fun selectPhoto() { val documentIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "image/*" } val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent -> } val target: List<Intent> = listOf(documentIntent,cameraIntent) val intent = Intent(Intent.ACTION_VIEW) if(intent.resolveActivity(getPackageManager()) != null) { val chooser = Intent.createChooser(documentIntent,"写真を選択").apply { putExtra(Intent.EXTRA_INITIAL_INTENTS , target.toTypedArray()) } startActivityForResult(chooser, READ_REQUEST_CODE) } } }
- 投稿日:2021-03-22T11:36:15+09:00
国外のPlayストアのランキングを見る方法(クエリ使うだけ)
以前アフリカのザンビアに住んでいたことがあるのですが、ふと、「ザンビアでの今のGooglePlayストアのランキングってどうなってるんだろ?」と気になりました。
ググるとプロキシ変える方法やApp Annieを使う方法が出てきましたが、PlayStoreのURL( https://play.google.com/store/apps/top )にクエリ(
?hl=ja&gl={2文字の国コード}1)を加えるだけでもできるようです。
※国コードである根拠はないのですが、挙動見る限り合ってそう。例
- US
- ザンビア
- ロシア
- 中国
余談ですが、中国では有料アプリをPlayストアからインストールできない2ので、無料アプリのランキングしかないですね。
参考
国コード検索
- https://www.iso.org/obp/ui/#search (Alpha-2 codeを使う) ↩Google Play ユーザーへの配布がサポートされている国や地域 | 購入者の現地通貨と価格帯
- https://support.google.com/googleplay/android-developer/table/3541286 ↩
- 投稿日:2021-03-22T11:36:15+09:00
海外のPlayストアのランキングを見る方法(クエリ使うだけ)
以前アフリカのザンビアに住んでいたことがあるのですが、ふと、「ザンビアでの今のGooglePlayストアのランキングってどうなってるんだろ?」と気になりました。
ググるとプロキシ変える方法やApp Annieを使う方法が出てきましたが、PlayStoreのURL( https://play.google.com/store/apps/top )にクエリ(
?hl=ja&gl={2文字の国コード}1)を加えるだけでも国外のPlayストアの情報を見ることができるようです。
※国コードである根拠はないのですが、挙動見る限り合ってそう。例
- US
- ザンビア
- ロシア
- 中国
余談ですが、中国では有料アプリをPlayストアからインストールできない2ので、無料アプリのランキングしかないですね。
参考
国コード検索
- https://www.iso.org/obp/ui/#search (Alpha-2 codeを使う) ↩Google Play ユーザーへの配布がサポートされている国や地域 | 購入者の現地通貨と価格帯
- https://support.google.com/googleplay/android-developer/table/3541286 ↩














