2023年10月2日月曜日

SQL SQLでもビット演算は計算できる

どうも。どっことです。今回はSQLでのビット演算について備忘録を記載します。

SQLでビット演算

SQLでもビット演算することができます。ビット演算は情報系の学生やエンジニアには基礎的な内容ですが、Androidだけで言えば使うことがあまり多くないかもしれません。

しかし、確かにビット演算による機能実装は行われており、例えばIntentに付与するflagの値はこのビット演算により制御されています。

これをもとに考えると、アプリやデータなどの複数の重複した状態を管理するのに向いていそうです。例えばSNSのコメントの「お気に入り」「リブート/リポスト」「いいね」などを管理するとき、booleanで管理するのが一番シンプルな実現方法ですが、最大値7の整数(000〜111)でまとめてしまう、という管理でも実現することができます。これの嬉しいことは、似たようなデータ要素を追加するとき、例えば「ミュート」を追加する場合にも、変数を追加せずに最大桁数を7→15の整数(0000〜1111)に上げることだけで十分実現できるということです。

変数を追加するというのはプログラムのデータ上だけでなくデータベースのテーブルやAPIでのやりとりにも影響してくるので、このようなOn/Offのデータをビット管理するのは拡張性を意識したときに優れていると考えられます。

積(and)

select 1 & 1; 1
select 1 & 0; 0

和(or)

select 1 | 1; 1
select 1 | 0; 1
select 0 | 0; 0

反転(not)

select ~0; -1
select ~1; 0

左シフト

select 1<<2; 4

右シフト

select 4>>1; 2

2023年9月21日木曜日

Android つぶやきながらJetpackComposeのサンプルを覗いてみる その1

巷ではJetpackComposeが流行っているらしい。これまでAndroid開発では xml により画面のレイアウトを実装していたけど、今後は 宣言型UIフレームワーク が主流になってくる様子。xml が慣れている人にとってはまだすこし取っ掛かりにくいけど、画面の構成がより明示的に表現されるのであれば、それはそれで嬉しいと思う。

サンプルを見てみる。

Android Studio>File>New>Import Sample...で、入力フォームにcomposeを入力すると、それっぽいものがフィルタリングされるので、適当に選択する。Androidarchitecture>Architectureを選択してみる。(どうやらTODOアプリのサンプルが見れる様子。SunFlowerも画像表示のサンプルとしては重要だけど、今回はシンプルそうな方を眺めてみる)

とりあえずDLが終わったけどどこを見ればいいのかわからないので、AndroidManifest.xmlを見てみる。TodoActivity というActivityが登録してあるみたい。

TodoActivityを覗いてみる

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContent {
    AppCompatTheme {
      TodoNavGraph()
    }
  }
}

setContentしか実装されていない... AppCompatThemeは名前からなんとなくテーマが設定されているコンポーネントかと予想できるので、その内側に設定されているTodoNavGraph を見てみる。(deprecatedなっていたが、趣旨から外れるのでここでは気にしないことにする。)

TodoNavGraphを覗いてみる

で、初っ端にでてきた実装がこれ。

@Composable
fun TodoNavGraph(
  modifier: Modifier = Modifier,
  navController: NavHostController = rememberNavController(),
  coroutineScope: CoroutineScope = rememberCoroutineScope(),
  drawerState: DrawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
  startDestination: String = TodoDestinations.TASKS_ROUTE,
  navActions: TodoNavigationActions = remember(navController) {
    TodoNavigationActions(navController)
  }
) {
...

fun... メソッドやんけ...しかも戻り値もない...ほんとうにこれでいいんか...?もう少し眺めてみよう。

@Composableアノテーションが付与されたメソッド内の実装を眺めてみる。

どうやらNavHostというコンポーネント内で、必要なものを構成するぽい。

NavHost(
  navController = navController,
  startDestination = startDestination,
  modifier = modifier
) {

んで、その NavHost での実装は composable というコンポーネントで構成されている。

composable(
  TodoDestinations.TASKS_ROUTE,
  arguments = listOf( navArgument(USER_MESSAGE_ARG) { type = NavType.IntType; defaultValue = 0 }
  )
) { ... }
composable(TodoDestinations.STATISTICS_ROUTE) { ... }
composable(
  TodoDestinations.ADD_EDIT_TASK_ROUTE,
  arguments = listOf(
      navArgument(TITLE_ARG) { type = NavType.IntType },
      navArgument(TASK_ID_ARG) { type = NavType.StringType; nullable = true },
  )
) { ... }

で、そのコンポーネントが各画面やサイドメニュー(ドロワー)の要素に対応していそう。

まとめ(所感)

ここまでの所感など

  • TodoDestinations で定義された定数が、このアプリを構成する画面やドロワーに対応していそうに見える。であれば実際に運用する場合この定義は列挙型にしておいて、引数としてはordinalなどを渡してあげたほうが良さそうな。
  • TodoDestinations.ADD_EDIT_TASK_ROUTEcomposable を見ると、どうやら画面に渡すパラメータもここで定義しておく様子。ここでの定義と実際の画面とで乖離が起きないよう、画面側のどこかで管理しておいたほうが良さそう。
  • アプリを構成する画面定義は見えたけど、各画面間での画面遷移や処理結果の戻しなどをどのように実装するかは見えていないので、次にサンプルを眺めるときはこの辺りをフォーカスして確認できれば嬉しい。

とりあえずここまで。

参考

2023年9月17日日曜日

Android ViewのコンストラクタとカスタムView実装に伴うスタイル定義について解説

どうも。どっことです。今回は独自ViewとしてEditTextのカスタマイズクラスを実装したときにハマった問題について、備忘録を載せたいと思います。

Viewのコンストラクタとスタイル定義

ListViewなどを使うために追加する独自View(①)と、TextViewなどのコンポーネントのViewをカスタマイズするView(②)とで、特にコンストラクタの実装方針が異なります。今回はそんなコンストラクタの実装方針とそれに伴うスタイル定義について解説していきます。

コンストラクタについて

そもそもAndroidのView派生クラスには、3つのコンストラクタがあります。

1.Contextのみを引数とするコンストラクタ

constructor(context:Context)

これはコードからViewを生成するときに使われるコンストラクタです。LayoutInflaterを使わない場合は、このコンストラクタでViewを生成するコースがほとんどかと思います。属性値がほぼ初期値なので、ViewGroupaddView()するときに自分で値を設定する必要があります。

2.Context, AttributeSetを引数とするコンストラクタ

constructor(context:Context, attrs:AttributeSet?)

これはxmlからViewを追加したときに呼ばれるコンストラクタです。

3.Context, AttributeSet, defStyleAttrを引数とするコンストラクタ

constructor(context:Context, attrs:AttributeSet?, defStyleAttr: Int)

これもxmlからViewを追加したときに呼ばれるコンストラクタです。「2.と何が違うの?」という疑問はAndroidアプリ開発者なら誰しも一度は思う謎ですが、それはxml内にstyleが指定されているか否かの違いです。xml内でstyleが指定されていれば3.、されていなければ2.が呼び出されます。

コンストラクタの実装方針について

それではコンストラクタを紹介したところで、先ほどの①と②での実装方針の違いについて説明していきます。

①の場合

気にしなくて問題ありません。以下のようなコードをコピペして使います。(以下はLinearLayoutの派生クラスとして定義した時の例です。)

class HogeView(context: Context, attrs: AttributeSet?, defStyleAttrs:Int) : LinearLayout(context, attrs, defStyleAttrs) {
  constructor(context: Context): this(context, null, 0)
  constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0)
  // ...
}

②の場合

こちらは適切なスタイルの定義が必要になります。デフォルトの場合、例えばEditTextはこのような実装になっています。

public EditText(Context context) { // ①のコンストラクタ
    this(context, null);
}
public EditText(Context context, AttributeSet attrs) { // ②のコンストラクタ
    this(context, attrs, com.android.internal.R.attr.editTextStyle);
}
public EditText(Context context, AttributeSet attrs, int defStyleAttr) { // ③のコンストラクタ
    this(context, attrs, defStyleAttr, 0);
}

第4引数については参考を見てもらうとして2.のコンストラクタが3.のコンストラクタをオーバーロードしているのは同じですが、引数が異なっています。①の場合は0 を渡していましたが、こちらはcom.android.internal.R.attr.editTextStyleを渡しています。

EditTextStyleにはEditTextが必要としている各属性の初期値が設定されており、これを渡してやらないと非常に残念な表示になってしまいます。(EditTextなのに、テキストが編集できないとか。1敗。)特に気にしないなら、これと同じように com.android.internal.R.attr.editTextStyleを渡してやれば問題ありませんが、「せっかく独自Viewを追加したのだから、スタイルもいい感じにしたい」ということであれば、追加で以下を実装する必要があります。(今回はEditTextを例として挙げます。)

実装手順

属性の追加

とりあえず何も考えずに attrs.xml に以下を追加します。

名前も適当です。必要に応じて適切な名前にしてください。

<resources>
    <attr name="hogeEditTextStyle" format="reference" />
</resources>

スタイルの追加

続いて何も考えずに styles.xml に以下を追加する。

名前も...(略)

<resources>
    <style name="HogeEditTextStyle" parent="android:Widget.EditText">
    </style>
</resources>

テーマの追加

前項までに追加したものをつなぐために、themes.xml に以下を追加します。

な...(略)


<style name="Theme.AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
    <!-- ... -->
    <!-- Customize your theme here. -->
    <item name="hogeEditTextStyle">@style/HogeEditTextStyle</item>
</style>

コンストラクタでの参照

最後に、「属性の追加」で追加したものを参照します。

class HogeEditText(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
    AppCompatEditText(context, attrs, defStyleAttr) { // ③のコンストラクタ
    constructor(context: Context) : this(context, null, R.attr.hogeEditTextStyle) // ①のコンストラクタ
constructor(context: Context, attrs: AttributeSet?) : this( // ②のコンストラクタ context, attrs, R.attr.hogeEditTextStyle ) //... }

必要な実装は以上です。これでカスタムしたHogeEditTextでも残念な表示にならず、いい感じの表示とすることができます。

余談

第3引数が必要なコンストラクタの変数名が defStyleAttrとなっており、これは default Style Attributeを意味しているものと考えられます。つまり、デフォルトのStyleのattributeが設定されることを想定されているということです。xml上でstyleが設定されていなければ②の、styleが設定されていれば③のコンストラクタが呼ばれる点からもこの想定が正しいものと思われます。独自Viewとして想定しているデフォルトのスタイルなどは、①、②の場合に限らず、無理やりコード上で設定するのではなく今回紹介した方法のdefStyleAttr設定するのがスマートな実装方法のように感じられます。

まとめ

今回はコンストラクタと、カスタムView実装におけるスタイル定義について解説しました。カスタムViewの実装は、ソースコードの整理やロジックをまとめる際に非常に有効な手法です。今回のように、必要なコンストラクタがどれか、スタイル定義が必要か、などを理解した上で効率よく開発していきたいですね。

参考

2023年9月1日金曜日

Python HTTP通信で情報取得

どうも。どっことです。通信取得する処理について紹介します。今回はPythonでサーバ通信・情報取得する処理です。

説明

さっそくサンプルを載せます。pythonをインストールできていれば、以下でOKです。

import sys
import json 
import urllib.request

# 取得したい情報のURL
url = "取得したい情報のURL"
header = {
  # 例えば header に仕込む key-value
  'key': 'value', 
  # 例えば header に仕込む 認証情報
  'Authorization': 'Bearer <YOUR TOKEN>'
}
req = urllib.request.Request(url, headers = header)

with urllib.request.urlopen(req) as res:
    body = json.load(res)
    print(body)

Android/iOSといったネイティブアプリのように、非同期処理などのことを考えなくていいので、とても簡単ですね(逆に不安になる)。巷ではrequestsといった、通信処理を簡単に実装できるようなライブラリはごまんとあるようですが、今回は「可能な限り簡単に使えるスクリプト」を意識したいので、標準のurllibを使いました。

参考

2023年8月11日金曜日

Android 裏にいるActivityもすべて終了するfinishAffinityメソッドを紹介

どうも。どっことです。今回はスタックに積まれているActivityをすべて終了させるメソッドを紹介します。

裏のActivityもすべて終了するfinishAffinity

Activity AからActivity BstartActivity()でスタックを積んだとき、Activity Aが明示的に自身をfinish()させなければ、Activity Bの裏にActivity Aはスタックとして存在します。

そしてこのときActivity Bfinish()を呼び、自身を終了させても、スタックに残っているActivity Aが表示され、アプリを終了することができません。

今回は、Activity BからスタックにいるすべてのActivityを終了させるメソッドを紹介したいと思います。

Activity#finishAffinity()

すべてのActivityを終了させるにはfinishAffinity() というメソッドを使います。単純なケースであれば、このメソッドを呼び出すことで裏にいるActivityをすべて終了することができます。

単純なケースと書いたのは、Activityには親和性(affinity)という概念があるためです。これが厳格に管理されているActivityですと、今回のケースは期待した動作をしない可能性があります。

ただし基本的に同一のAndroidアプリという領域のActivityであるためaffinityが厳格に管理されているケースは非常に稀で、まずはやりたいことが実現できるかをこのメソッドを呼んで試してみるのが解決への一番の近道になるかと思います。

参考

2023年8月10日木曜日

Android 通知チャンネルの設定画面を表示する実装方法について解説

どうも。どっことです。今回は、通知チャンネルの設定画面を表示するための実装方法について解説します。

通知チャンネルの設定画面を表示する

Android O から追加された通知チャンネルですが、アプリからは追加・削除以外は通知チャンネルの設定値を修正・変更することができません。その代わりに端末の設定画面に遷移させるための導線を具備することで、ユーザに通知チャンネルまで簡単にアクセスできるようにしてあげましょう。

実装方法

アプリが追加したチャンネルの設定画面に遷移する方法は以下となります。

val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId)
startActivity(intent)

通常のstartActivityと同様に、必要なActionやパラメーターを設定することで通知チャンネルの設定画面に遷移することができます。

まとめ

今回は、通知チャンネルの設定画面を表示するための実装方法について解説しました。このブログでは、アプリで通知を表示するために必要な実装として他にも投稿しているので、もしよろしければそちらも参考にしていただけると幸いです。

参考

2023年8月9日水曜日

Android AndroidPでhttp通信に失敗する問題

targetSDKVersionをAndroidP以上に設定すると、セキュリティの問題でアプリでのhttp通信が失敗する。AndroidManifest.xml のapplicationタグに以下の属性を追加する。

<application
    ....
    android:usesCleartextTraffic="true">
</application>

開発段階ではローカル環境にサーバ立ててそこにスタブデータを置いて動作確認することが多いが、本番環境では回避すべき設定なので、debug/releaseでAndroidManifest.xmlを分けるなど、きちんと切り分けること。

2023年8月8日火曜日

HTML/CSS マウスオーバーしたときの表示をカスタマイズする

マウスオーバーしたときに表示を切り替えたいときは、CSSに疑似クラスを指定する。

a:hover {
  マウスオーバー中に表示したい内容
}

この指定を複数の要素に指定することで、例えばテキストやイメージの表示切替などもできる。

a:hover {
  マウスオーバー中に表示したい内容
}
.a-covered:hover {
  マウスオーバー中に表示したい内容
}

マウスオーバー以外にも疑似クラスの指定により表示を変えられるものは以下。

  • link:御訪問リンク
  • visited:訪問済みリンク
  • hover : マウスオーバー
  • active : リンククリック中

参考

2023年8月7日月曜日

Android Parcelableを実装する方法を解説

どうも。どっことです。今回はParcelableの実装方法について解説します。

Parcelableを実装する

ActivityFragmentなどの画面間におけるデータ受け渡しはアプリ全体の動きを考える上でなくてはならない処理ですが、自前で用意したデータクラスはそのままだとBundleに乗せることができません。

それではどうするかというと、そのデータクラスにParcelableSerializableを実装します。取り出すときにキャストが必要にはなるが、これでBundleに乗せることができるようになり画面間のデータ受け渡しができるようになります。

今回はその呪文の如きParcelableのインターフェース群の実装について、説明します。

実装

必要な実装ですが、データクラスに以下のクラス・メソッドを実装します。

  • Parcelableを実装する
  • describeContentsを実装する
  • 引数がParcelのコンストラクタを実装する
  • writeToParcel()を実装する
  • CREATOR : Parcelable.Creatorを実装する

サンプルとしてItemクラスにParcelableを実装する場合は以下となります。

data class Item(
    var title: String,
    var description: String,
) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString()!!,
        parcel.readString()!!
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(title)
        parcel.writeString(description)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Item> {
        override fun createFromParcel(parcel: Parcel): Item {
            return Item(parcel)
        }

        override fun newArray(size: Int): Array<Item?> {
            return arrayOfNulls(size)
        }
    }
}

あとは実装したデータクラスのオブジェクトをBundle#putParcelable()Bundleに詰め

val bundle = Bundle().apply {
    putSerializable("適当なキー", item)
}

Bundle#getParcelable()Bundleから取り出すことで

val item = bundle.getParcelable("適当なキー", Item::class.java)

画面間でデータクラスをやり取りすることができます。

ここまで書いててですが…

Percelableをいい感じに実装してくれるアノテーションがあると公式サイトが謳っていました。

Parcelable 実装生成ツール

アノテーション付けるだけで上記の面倒臭い実装をしなくてよくなるなんて、なんて素晴らしいんだ!!ありがとうGoogle様!!!

まとめ

今回はParcelableの実装方法について解説しました。ボイラープレートなParcelableの実装ですが、すでに自動生成してくれるツールがあるので、そちらを使う方が無難でしょう。今回の紹介した内容がほぼ無用なものになってしまいますが、必要なものが簡単に実装できることの方が重要だと思うので、まあ仕方ないでしょう笑

2023年8月6日日曜日

VBA 今日の日付を取得する

単純な日付だけであれば Dateをって取得する。

Dim date As Date: date = Date()

時刻まで必要であれば Now を使って取得する。

Dim now As Date: now = Now()

参考

移行予定

どうも。どっことです。 タイトルの通りですが、諸事情により GitHubPage に移行予定です。 https://mkt120.github.io/ この備忘録に記載の内容を転記しつつ、今後はこちらのページを更新していく予定です。