- 投稿日:2020-11-25T23:52:13+09:00
ViewBindingに移行していきます
この記事の概要
Viewにアクセスする最新の方法をメモしています。これまでは
findViewById
やKotlin Android Extension
などがViewにアクセスする方法としてありましたが、現在はViewBinding
を使った方法が推奨されております。Android Developers | ViewBinding作るもの
PeerLodgeのオリジナルアプリPeerRadioのAndroid版を作成しています。PeerRadioの開発ブログです。
これまでのViewへのアクセス方法
findViewbyId
を使ってViewにアクセスする方法は以下が例です。val titleInputText = findViewById<EditText>(R.id.title_input_text_view) postTitle = titleInputText.text.toString()また、
Kotlin Android Extension
でViewにアクセスする方法は以下が例です。btn_job_register.setOnClickListener { val intent = Intent(this, MainActivity::class.java) startActivity(intent) }上記は実際に現時点での開発中のAndroid版PeerRadioの中のコードです。他の部分にもまだまだ
findviewById
やKotlin Android Extension
を使ってしまっているところがあるので、少しづつviewBinding
に変えていく必要があります。頑張ります!ViewBindingを使うための前準備
app/build.gradleにviewBindingの利用を記述します。
app/build.gradleandroid { // 省略 viewBinding { enabled = true } }変更できたらsyncしましょう。
ViewBindingでViewにアクセスする(Activity)
前準備ができたらActivityでは以下のようにアクセスします。
やるべきことは以下の3点です。UserRegisterActivity.ktclass UserRegisterActivity : AppCompatActivity() { // TIPS: bindingクラスをlateinit varで宣言する private lateinit var binding: ActivityUserRegisterBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // TIPS: bindingの初期化とついでにsetContentViewも行います binding = ActivityUserRegisterBinding.inflate(layoutInflater) .apply { setContentView(this.root) } // TIPS: アクセスしたいViewのidはロワーキャメルケースにしたものに勝手に代わります binding.btnUserRegister.setOnClickListener { val intent = Intent(this, JobRegisterActivity::class.java ) startActivity(intent) } } }ViewBindingでViewにアクセスする(Fragment)
また、Fragmentでは以下のようにViewBindingを設定します。
RecordFragment.ktclass RecordFragment: Fragment(), RecordAfterCustomViewDelegate, RecordBeforeCustomViewDelegate, RecordNowOnCustomViewDelegate { // TIPS: bindingの変数宣言を行う private var _binding: FragmentRecordBinding? = null private val binding get() = _binding!! // TIPS: onCreateViewではbindingの初期化を行います // TIPS: 逆に言えばbindingの初期化以外の処理は行わず、bindingの初期化以外の処理を記述したい場合はonViewCreatedにします。 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // TIPS: rootViewは不要になります _binding = FragmentHomeBinding.inflate(inflater, container, false) return binding.root } // TIPS: Viewに実際にアクセスしたり、binding以外の処理をここで行います。つまり、bindingの初期化以外の処理をここに記述します。 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Viewの処理 binding.hogehoge.text = "hogehoge" // bindingの初期化以外の処理 callHomeViewModel() } // TIPS: fragmentでは閉じられる(destory)される時にbindingをクリアにする処理が必要になります override fun onDestroyView() { super.onDestroyView() _binding = null }終わりに
何か間違っているよ、という部分等あればコメントよろしくおねがいします!!
- 投稿日:2020-11-25T19:55:22+09:00
Android Studioの設定
初めに
開発をしていく上で役に立ちそうなAndroid Studioの設定をまとめます。
環境
Android Studio 4.1.1
PC Windows 10設定内容
フォントサイズ・字体
File > Settings > Editor > Font
未使用のimportの削除
File > Settings > Editor > General > Auto Import
1. Optimize imports on the fly(for current project)にチェックを入れる
ショートカットの設定・確認
File > Settings > Keymap
キーボード ショートカットLogcatの色の変更
File > Settings > Editor > Android Logcat
1. Inherit values from: Console→Standard outputのチェックを外す
2. Foregroundの色を変更
おまけ
設定内容をエクスポートしてほかの環境でインポートするには以下の方法で可能なので、
ファイル共有できる環境であれば一度設定してしまえば使いまわすことが可能です。
AndroidStudioの設定をエクスポートしてインポートする方法最後に
他にやっておいた方がいい設定あれば、追加していきたいので、
コメントいただければと思います。
- 投稿日:2020-11-25T18:35:08+09:00
10分でHMS Audio Engineを利用してアプリにカラオケ機能を実装
カラオケ機能(エコー機能)のアプリを作りました。
早速HMS Audio Engineを使って、シンプルにカラオケ機能(エコー機能)をアプリで作りました。
◆ Object作成、Object初期化、Callbackの登録
mHwAudioKit = new HwAudioKit(this, callBack); mHwAudioKit.initialize(); // Create KaraokeFeature: mHwAudioKaraokeFeatureKit = mHwAudioKit.createFeature(HwAudioKit.FeatureType. HWAUDIO_FEATURE_KARAOKE); // Create a callback task. IAudioKitCallback callBack = new IAudioKitCallback() { @Override public void onResult(int i) { if (i == 0) { // HwAudioKit initialization is successful. Its APIs can be used, such as mHwAudioKit .getSupportedFeatures(); //Return the list set. mHwAudioKit .isFeatureSupported(FeatureType type); // Return true or false: true indicates supported, while false indicates the product does not support the query function. } if (i == 2) { // The Engine service is not installed and the kit is not supported } if (i == 1000) { // HwAudioKit initialization is successful. Its APIs can be used, such as: // Query whether Karaoke is supported: true indicates supported, while false indicates not. int isSupport = mHwAudioKaraokeFeatureKit.isKaraokeFeatureSupport(); // Turn on or off the headset monitoring function. The value 0 indicates success, 1806 indicates that the product does not support the karaoke function, and 1805 indicates that no headset is inserted. boolean enableSuccess = mHwAudioKaraokeFeatureKit.enableKaraokeFeature(enable); // Set the sound effect and volume. The value 0 indicates success, 1806 indicates that the product does not support the karaoke function, 1805 indicates that no headset is inserted, and 1807 indicates parameter error. int success = mHwAudioKaraokeFeatureKit.setParameter(HwAudioKaraokeFeatureKit.ParameName.CMD_SET_AUDIO_EFFECT_MODE_BASE, value); // Obtain the latency information.The value -1 indicates obtaining failure int latency = mHwAudioKaraokeFeatureKit.getKaraokeLatency(); } } }◆ Object廃棄
mHwAudioKaraokeFeatureKit.destroy(); mHwAudioKit.destroy();完成
START RECORDING、STOP RECORDING、PLAY RECORDINGで自分の音声を録音して再生。
TURN ON KARAOKEで自分の音声をリアルタイムで聞くことができます(エコー機能)。
さらに、KTVモードやTHEATERモードなども変更可能です。参考
HMS Audio Engineについて
https://developer.huawei.com/consumer/en/doc/development/Media-Guides/audio-introduction開発ガイド
https://developer.huawei.com/consumer/en/doc/development/Media-Guides/audio-guide
- 投稿日:2020-11-25T17:36:38+09:00
[ReactNative] ScreenView+Webview refreshControlについての備忘録(Androidのバグ)
最近小さめのReactNativeのプロジェクトにアサインされたワタクシでございます。
全くまだ分かってないんですけど、UI部分の改修案件が来たので対応しています。
その際に直面したバグ対応の備忘録を残します。どのようなバグか
iosでは起きず、Androidのみのバグとなります。
render() { <ScrollView refreshControl={ <RefreshControl refreshing={ this.state.refreshing } style={{ backgroundColor: "#FFFFFF" }} onRefresh={() => { this.onRefresh() }} /> } contentContainerStyle={{flex: 1}} style={{ backgroundColor: "#FFFFFF" }} > <WebView style={{ flex: 1 }} onMessage={this.onMessage} onNavigationStateChange={this.onNavigationStateChange} onLoadStart={this.onLoadStart} onLoadEnd={this.onLoadEnd} ref={webView => {this.webView = webView}} source={{ uri: this.state.url.toString() }} /> </ScrollView> }このようなソースがあります。
webviewを表示しており、このwebviewはスクロールが可能になっています。
スクロールをする際にiosでは起きませんが、Androidではスクロールで下までいってしまったあとに上に戻ろうとすると必ずrefreshControlが走り、上にスクロールが出来なくなるバグが起きてました。
アプリの上部に来た時だけ更新してくれればいいのに、常に上部をひっぱると更新されてしまいます。原因
webview側は問題なくスクロールします。スクロールされているのはScrollViewではなくて、webviewであることがわかり、(ScrollViewにonScrollつけてもイベントが走らなかったため)ScrollViewのscrollYが更新されず0のままでした。
そうすると恐らく、scrollYが0であるとしてAndroidでは常にrefreshControlが走ってしまうのではないか、というところまでたどり着きました。開発環境
- react-native: 0.61.5
- react: 16.9.5
- react-native-webview: 8.0.3
解決方法
const INJECTED_JS = ` window.onscroll = function() { window.ReactNativeWebView.postMessage( JSON.stringify({ scrollTop: document.documentElement.scrollTop || document.body.scrollTop }), ) ` export default class WebViewPage extends React.Component { state = { scrollViewHeight: 0, isPullToRefreshEnabled: false, } onMessage = () => { const { data } = e.nativeEvent try { const { scrollTop } = JSON.parse(data) this.setState({ isPullToRefreshEnabled: scrollTop === 0 }) } catch (err) { // ... } } render () { const { scrollViewHeight, isPullToRefreshEnabled } = this.state return ( <View style={{flex:1}}> <ScrollView refreshControl={ <RefreshControl refreshing={ this.state.refreshing } enabled={ isPullToRefreshEnabled } style={{ backgroundColor: "#FFFFFF" }} onRefresh={() => { this.onRefresh() }} /> } onLayout={e => this.setState({ scrollViewHeight: e.nativeEvent.layout.height })} contentContainerStyle={{flex: 1}} style={{ backgroundColor: "#FFFFFF" }} > <WebView style={{ flex: 1 }} onMessage={this.onMessage} onNavigationStateChange={this.onNavigationStateChange} onLoadStart={this.onLoadStart} onLoadEnd={this.onLoadEnd} ref={webView => {this.webView = webView}} source={{ uri: this.state.url.toString() }} injectedJavaScript={INJECTED_JS} /> </ScrollView> </View> ) } }解説
- ScrollViewでスクロールイベント取れないならwebviewで取るしかないよなということで
injectedJavaScript
を導入。injectedJavaScriptはwebview側にjavascriptのコードを渡す属性で、ここでwebviewのスクロール位置を取得して、window.ReactNativeWebView.postMessage
でReactNative側にその情報を渡してやります。この時、webview側にもonMessageメソッドを定義して、webview側のスクロール位置情報を受け取ります- enabledでいつrefreshControlが走るか定義しておく(onMessage)
- ScrollViewコンポーネントのonLayoutを使って、viewが開いたときの高さを取得して保持しておきます。(初回だけ取得用)
- WebviewコンポーネントにinjectedJavaScriptを突っ込みます。
以上です。これで画面の一番上にスクロールした時にだけ上部を引っ張ればrefreshControlが走る設計になったかと思います。
参考文献