- 投稿日:2020-01-16T23:55:14+09:00
いまさらFragmentを試してみる
はじめに
Androidのプログラムを初めて何年も経つけどFragmentを触ったことがほとんどないというちょっと恥ずかしいかもしれない告白w
まぁ、SurfaceViewに描画してゲーム作る程度なのでFragment無くてもよかったというのもあるけど。
最近、お仕事でもAndroidのコードに触れる機会もあり、そろそろちゃんと分かっておかないと、やばい!
というわけで、ネットで何かないかな?と探してたらあったので試してみる。参考にしたのはこちら
Android はじめてのFragmentいや、ほんと初めてみたいなものなのでw
上記のページを参考にしたところ、LegacyになってるRelativeLayoutを使てたり、知識の足りないせいで思うようにいかないところがあったりと、久々にAndroidのコード書いてよいウォーミングアップになりました。とりあえず、参考サイトの内容をなぞるように書くなら、参考サイトを見てもらえばいいので、個人的に調べたことを追加しつつ、適当に端折りながら書いていきます(自分が後で参考にできればいいくらいの気持ちで)
Androidのプロジェクトの作成
今のトレンドならKotlinがいいと思いますが、Javaを選んでやりました。
Fragmentのレイアウトとクラスの作成
で、作ったレイアウトを開いて、TextViewとButtonを追加します。
あと、LinerLayoutのlayout_widthをmatch_parent、layout_heightをwarp_contentにします。
こんな感じになっていればOK
クラスができたら、onCreateView()メソッドとonViewCreated()メソッドをオーバーライドして、中身を実装します。
参考元そのまんまですが、MainFragment.javapublic class MainFragment extends Fragment { private TextView mTextView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saveInstanceState) { super.onCreateView(inflater, container, saveInstanceState); return inflater.inflate(R.layout.fragment_main, container, false); } @Override public void onViewCreated(View view, Bundle saveInstanceState){ super.onViewCreated(view, saveInstanceState); mTextView = view.findViewById(R.id.textView); view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { mTextView.setText(mTextView.getText() + "!"); } }); } }onCreateView()メソッドは、Fragmentが最初にUIを描画するときにシステムから呼び出されるメソッドになります。
なので、ここで、FragmentにViewを設定しています。
ちなみに、FragmentクラスのコンストラクタにリソースIDを指定したり、@ContentViewアノテーションで指定できるらしいのですが、今回試したSDKのバージョン(26)ではできなかった。
どこかでこの辺は調べて明確にしておきたいところ。onViewCreated()メソッドは、公式のフラグメントのサイトのライフサイクルの図には登場しませんが、onCreateViewメソッドの後にシステムから呼び出されるメソッドです。
初期化処理はonCreateView()ではなくonViewCreated()でやってねと公式の(Fragmentのリファレンス)[https://developer.android.com/reference/kotlin/androidx/fragment/app/Fragment.html#oncreateview]に書いてあります。
なので、onViewCreated()メソッドで初期化処理を行っています。ActivityにFragmentを追加する
レイアウトに追加してもいいんですが、コードで追加する方法が好みなので、コードでFragmentをActivityに追加します。
Activityのコードはこんな感じ。MainActivity.javapublic class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MainFragment fragment1 = new MainFragment(); MainFragment fragment2 = new MainFragment(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(R.id.container, fragment1); transaction.add(R.id.container, fragment2); transaction.commit(); } }同じフラグメントを追加したかったのでこんな感じになっています。
参考元だと、transaction.add(R.id.container, fragment1);上記をもう一度呼び出せばいいように読めますが、上記を2回呼び出すと、落ちます。
なので、MainFragmentクラスのインスタンスはそれぞれ作る必要があります。これで、ActivityにFragmentを追加することができました。
さてさて、今回はここまで。
もう少し、Fragmentを使うシーンを考えて実装したいところ。
何か考えよう。参考
Android はじめてのFragment
Fragmentの初期化はonViewCreatedかonActivityCreatedで
知らずに作って大丈夫?Androidの基本的なライフサイクルイベント31選
- 投稿日:2020-01-16T19:46:58+09:00
Mobile Blazor Bindings は「Xamarin.Forms アプリ生成器」でした
BlazorでiOS/Androidネイティブアプリケーションを開発可能にする「Mobile Blazor Bindings」、マイクロソフトが発表 - Publickey
これなんですけど。「ざまりん乙」的な声が今回もチラホラ聞かれたので「マジか!それはすごい」と思って試してみました。
サンプルアプリを動かしてみた
こちらの手順の通りで、簡単に試すことができます。1
まあ、ソリューションを見てみただけで Xamarin(Xamarin.Forms アプリ) なんですけども。
inspect してみた
続いて、Android 向けのプロジェクトをエミュレータで実行し、Android Studio 付属の Device Monitor で inspect してみました(もしかしてガワネイティブ?という可能性もあったので)。
FrameLayout や RelativeLayout などの Android ネイティブ部品が並んでいるので確かに "ネイティブ" でした。
また、PlatformRenderer とか ButtonRenderer、これらは Xamarin.Forms アプリを inspect した時と同じ感じです。Mobile Blazor Bindings のソースコードを見てみた
ソースコードはこちらです(Open by default 素晴らしい)。
ここらへん に、それっぽい記述を見つけることができます。
using XF = Xamarin.Forms; namespace Microsoft.MobileBlazorBindings.Elements { public class Button : View { static Button() { ElementHandlerRegistry .RegisterElementHandler<Button>(renderer => new ButtonHandler(renderer, new XF.Button())); } (以下略)サンプルアプリに Razor テンプレート(
*.razor
) に記述した<Button>
という要素は、上記の処理でXamarin.Forms.Button
にマップされるように見えます。つまり
「Razor の仕組みを使って Xamarin.Forms アプリを作ることができるのが Mobile Blazor Bindings」
ということのようです。 UI用DSLから Android/iOS 向けには Xamarin.Forms が使われる点は、Uno Platform にも近いと思います。
なにがおいしいの?
Blazor は「We B Assembly + Razor」の造語だっと記憶してますが、昨日の .NET Conf Focus on Blazor のまとめを見ると、
「WebAssembly 使う使わん関係なく、とにかく Razor 技術から様々なプラットフォーム向けアプリを生成するフレームワークが Blazor」
という事になったようですね(Mobile Blazor Bindings に wasm 技術の欠片は見当たりませんでした)。という事で、
.razor
テンプレートやそれが属するプロジェクトに記述された UI や C# コードは、Webアプリ/モバイルアプリ/デスクトップ向けアプリとしても再利用できますよ、という目論見のようです。Razor は、ASP.NET を使ってWebフロントエンドを開発するための技術として普及している(と思う)ので、その流れでカバー範囲を広げたい人には刺さるでしょう(一方 XAML を主戦場とする人には前述の Uno Platform の方が刺さるでしょうか)。
「「「ネイティブAndroid のラッパーである Xamarin.Android」、をラップした Xamarin.Forms」をさらにラップした Mobile Blazor Bindings」、、、というゴテゴテ感、個人的にはキライじゃないし、それなりに基盤がしっかりしていないとさすがに崩れ落ちるので、.NET基盤 ってすごいなあ、と思います。
簡単に動かせたのは Xamarin.Forms アプリ開発環境は既に構築済みだったこともありw ↩
- 投稿日:2020-01-16T17:26:34+09:00
[Android] ServiceとIntentServiceの違い
Serivce
Serviceについては以前触れたので、こちらの記事を参照願いたい。
・Service
https://qiita.com/QiitaD/items/5c313076b7b99823ce1a・IntentService
https://qiita.com/QiitaD/items/96e70cd189d0c4385393終了方法
Serviceは終了するときにStopService()かstopSelf()を明示的に書かなければ終了しない。しかし、IntentServiceの場合はそれをする必要がなく、処理が終わったら自動的に終了してくれる。
スレッド
ServiceはActivityと同じUIスレッド(メインスレッド)で動いているが、IntentServiceはメインスレッドとは別のスレッド(内部のHandlerThread)で動いている。
そのため例えば、HTTP通信をServiceに任せる時、IntentServiceは非同期処理に向いているので通信できる。しかしServiceクラスで行おうとすると「NetworkOnMainThreadException」が発生する。
またIntentServiceはUIスレッドで動いていないので、Viewを操作できない。(BroadcastReceiverやCallBackを使わなければならない。)
ネットに転がっているサンプルにはToastをプログラム内に組み込んでいるものもあったが、Toastも出なかった。(Handler使えば可能になるという記事もあった https://qiita.com/wakwak/items/5a03127aba3effa845f8)感想
非同期処理関連はService以外にもAsyncTaskがあるのでかなり厄介に感じた。向いてないクラスを使うと、品質を落としかねないので気を付けたい。
参考URL
・Android 非同期処理についてまとめるメモ
https://qiita.com/tk_daze/items/bc83c69750e5f2e4015c・IntentService と Serviceの違い
https://oc-technote.com/android/intentservice%e3%80%80%e3%81%a8%e3%80%80service%e3%81%ae%e9%81%95%e3%81%84/
- 投稿日:2020-01-16T17:18:59+09:00
flutter 全面にローディングを表示させるサンプル
実現したいこと
なにか処理中で、操作を受け付けれないような状態の時に、
全画面でローディングを表示させるやりかたについて書きたいと思います。動作の様子
ボタンを押すとローディングが表示。2秒後に自動的に閉じます。
動作コード
こちらに一式用意しています。
https://github.com/quqjp/flutter-testコード箇所はこちら。
https://github.com/quqjp/flutter-test/tree/master/lib/sample1構成
ローディング表示のWidget OverlayLoadingMolecules を作成。
組み込む側メインのコードにて、Stack Widget を用いて最前面に配置します。ローディングWidget OverlayLoadingMolecules
表示の状態 visible プロパティを持ち表示を外部から制御できるようになっています。
非表示時は、空のContainer()が表示されます。
くるくるローディング表示自体は、CircularProgressIndicator Widget を用いた。import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // // 全面表示のローディング // class OverlayLoadingMolecules extends StatelessWidget { OverlayLoadingMolecules({@required this.visible}); //表示状態 final bool visible; @override Widget build(BuildContext context) { return visible ? Container( decoration: new BoxDecoration( color: Color.fromRGBO(0, 0, 0, 0.6), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ CircularProgressIndicator( valueColor: new AlwaysStoppedAnimation<Color>(Colors.white)) ], ), ) : Container(); } }
組み込む側メインのコード
//dart package import 'package:flutter/material.dart'; //third party package //my package //same package import "overlay_loading_molecules.dart"; // // 全面にローディングを表示させるサンプル // class Sample1Page extends StatefulWidget { Sample1Page({Key key, this.title}) : super(key: key); // タイトル final String title; @override _State createState() => _State(); } class _State extends State<Sample1Page> { //ローディング表示の状態 bool visibleLoading = false; @override void initState() { super.initState(); } // // // ボタンハンドラ onPressMyButton() async { //ローディングを表示 setState(() { visibleLoading = true; }); //2秒待つ await Future.delayed(const Duration(milliseconds: 2000), () {}); //ローディングを非表示 setState(() { visibleLoading = false; }); } /// /// /// @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), // body: ClipRect( child: Stack( fit: StackFit.expand, overflow: Overflow.clip, children: <Widget>[ Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ // //ローディングを表示させるためのボタン RaisedButton( onPressed: onPressMyButton, child: Text('ローディングを表示', style: TextStyle(fontSize: 20)), ), ], ), // //ローディング OverlayLoadingMolecules(visible: visibleLoading) ], ), ), ); } }まとめ
flutter で全面にローディングを表示させる方法をまとめました。
flutter初学者のため、アドバイスなどいただけると嬉しいです。
- 投稿日:2020-01-16T11:08:28+09:00
【未解決】Samsung端末だとFlutterの文字入力がバグる案件
どういうバグなんですか?
入力してない文字がガンガン入ってくる
ソース元Q.一般開発者に出来る対応は? A.ほぼ無い
マジで勘弁してください(白目
バグの発生原因
Samsung端末の 予測変換 機能に問題があるとのこと。
OS周辺のブラックボックスに起因しているのがキツい英数字限定のTextFieldにだけ使える対応
予測変換がバグの温床なんだから、予測変換使わなきゃいいじゃん?
ということで、そういう設定の仕方があるみたいです。1.まず device_info ライブラリをインストールします
https://pub.dev/packages/device_info2.こういう感じでサムスン端末判定を行う
bool samsungKeyboard = false; if (Platform.isAndroid) { var info = await DeviceInfoPlugin().androidInfo; samsungKeyboard = (info?.manufacturer?.toLowerCase()?.contains("samsung") ?? false); } else { samsungKeyboard = false; }3.サムスン端末判定で keyboardType の設定を変える
TextField( keyboardType: samsungKeyboard ? TextInputType.visiblePassword : TextInputType.emailAddress, autoFocus: false, )この対応が根本的な改善にならない理由
- 全部の TextField にこれ対応するの単純にキツイし漏れやすい
- 予測変換の禁止強制、ユーザビリティ最悪ですよねこれ
- 複数行入力に対応しようとすると
TextField( keyboardType: TextInputType.multiline, maxLines: null, )を設定する必要がある(引用元)ので、keyboardTypeが重複して駄目
という感じで、現実的にどうにもならないです。
Flutter公式側の動向
https://github.com/flutter/flutter/issues/42273
対応自体は行ってくれているみたいですが、2020/01/16現在、
対応マイルストーンは2020年の2月および5月とそれなりに長めの設定。
微妙に遠いなぁ……(遠い目
- 投稿日:2020-01-16T02:04:12+09:00
【Unity】[Serializable]なSoundPlayerという名前のクラスを作るとビルドは通るがAndroid実機で落ちる
はじめに
タイトルままです。
調べても対処法が出てこず、2時間ぐらい詰まったのでメモ。環境
開発環境
Unity 2019.2.17f1
Windows 10
確認Android環境1
FireHD 10(Fire OS 5.3.7.0)
確認Android環境2
BlueStacks4(OnePlus 5)エラー本文
logcatで怪しかったところ.txt01-15 01:46:13.567: E/Unity(15508): The file '/data/app/com.XXX.XXX-2/base.apk/assets/bin/Data/level0' is corrupted! Remove it and launch unity again! 01-15 01:46:13.567: E/Unity(15508): [Position out of bounds!]解決法
[System.Serializable]なSoundPlayerというクラスの名前を別のものにする(今回はSoundProviderという名前にリネームして解決)
Before
SoundPlayer.csnamespace Hoge { [System.Serializable] class SoundPlayer{ [SerializeField] AudioClip hogehoge; ~~中略After
SoundProvider.csnamespace Hoge { [System.Serializable] class SoundProvider{ [SerializeField] AudioClip hogehoge; ~~中略原因
正直よく分からないですが、元々System.Media名前空間にSoundPlayerというクラスがあります。
SoundPlayer クラス (System.Media) | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/api/system.media.soundplayer?view=netframework-4.8おそらくですが[Serializable]ではない同名のクラスが存在するとこのエラーが発生すると考えられます。apk起動時にシーン内のオブジェクトに紐付いたHoge名前空間のSoundPlayerをSystem.Media名前空間内のSoundPlayerでデシリアライズしようとしているとか。
おまけ:解決に至るまで試したこと
上記のエラーをググるとエディタ関係のエラーで参照が切れていると発生するといった記事が出てきます。
が、検索結果に出てきた「LibraryとTempフォルダを削除」、「Reinportする」をしてビルドしても症状は変わらず。この時点で完全に手詰まりで頭を抱えました。
Previewの「2D Pixel Perfect」パッケージを外してみたりしたものの改善せず。
音を付ける前は起動できていたので最近追加した音周りが怪しいということで音周りのコードを確認しました。
で、SoundPlayerという名前のクラスが別にあったので、自作のSoundPlayerの方の名前を変えたら解決しました。当てずっぽうだったので、あんまり褒められたものではありませんが、なんとか前に進むことができました。