Android color int の色の並び
超小ネタです。
アンドロイドの UI で Color( 0xd0203040 ) となっていた場合の色の並び
ARGB の順に並んでいる A は透明度で基本 FF でもかまわないと思う。
超小ネタです。
アンドロイドの UI で Color( 0xd0203040 ) となっていた場合の色の並び
ARGB の順に並んでいる A は透明度で基本 FF でもかまわないと思う。
sudo apt update を実行すると以下のようなメッセージで Wine のキーが trusted.gpg にあるって理由で警告がでた。昨日 Linux Mint 22 にアップグレードしたのが原因かもしれない。
W: XXXXttps: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
この辺の操作はいつも適当にファイルをいじって回避しているので少しだけ調べた。
参考ページの操作をするとキーが trusted.gpg ファイルから trusted.gpg.d フォルダの個別ファイルに移せるってことらしい。
$ apt-key list
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
/etc/apt/trusted.gpg
-------------------------------------------
pub rsa3072 2018-12-10 [SC]
D43F 6401 4536 9C51 D786 DDEA 76F1 A20F F987 672F
uid [ unknown] WineHQ packages <wine-devel@winehq.org>
sub rsa3072 2018-12-10 [E]
#trasted.gpg.d 内のファイルについて続く
例として wine のキーを移動してみる
$ sudo apt-key export F987672F | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
これで警告がでなくなった。
Fixing “Key is stored in legacy trusted.gpg keyring” Issue in Ubuntu
21.3 から 22 にアップグレードした。
やり方は簡単、mintupgrade というツールをインストールして起動してやるだけ。
$ sudo apt install mintupgrade
$ mintupgrade
注意しないといけないのは、【Timeshift】のスナップショットが一つもないとアップグレードのプロセスが途中で中断してしまう。
TimeShift の注意点として保存先のパーティションに timeshift フォルダが作成される。その時バックアップ対象から timeshift フォルダを除外しないとスナップショットの作成が空き容量が 0 になるまで永遠に終わらないので注意すること。
例えば / のあるパーティションに timeshift フォルダが作成されている時、 / 全体をバックアップする設定の場合に発生する。この場合は、前述の通り /timeshift フォルダをバックアップ対象から除外すること。
順調に行けば1時間から2時間くらい放っておけば、あっけなくアップグレードは完了する。
公式のフォーラム見てみると、どうも Linux Mint は LM と略すらしい。 Linux Mint で検索かけてもいまいち Mint 特有の結果に絞り込むことはできないことが多いのので LM22 とか入れてみるといいかもしれない。
pip search が廃止されて結構長いこと時間が経っているが、いい感じの代替が見つかったのでメモする。
pypi に pypi-search というのが登録されていたので試してみた。
2024-12-24 追記: pypi-search で検索できなくなった。
2024-9-3 追記: pipx でインストールすることにした
// pipenv 内で実行していたので pipx に変更する
//$ pip install pypi-search
$ pipx install pypi-search
$ pipy-search mqtt
[INFO] :: Searching for package `mqqt`...
[INFO] :: Could not find package `mqqt`
[INFO] :: Searching for other packages that match that query...
Here are some packages that match `mqqt`:
=========================================================================================================================================================================================================================
Name : dyrkdevice
Version : 0.1.0
Release date : Oct 24, 2021
Description : Library for implementing a dyrk device
$ $ pypi-search -help
usage: pypi-search [-h] [-d] [--version] [-o] search
Search for PyPi packages
positional arguments:
search Package to show information on
options:
-h, --help show this help message and exit
-d, --description Show package description
--version show program's version number and exit
-o, --open Open homepage in browser
これでいちいち pypi をブラウザで開く必要がなくなりそうで助かるなと。
Ubuntu 24.04 かそれに含まれる Python 3.12.3 は pip が venv の中でしか実行できないらしい。先日インストールできたのははからずも、venv 内で作業していたため後日 pypi-search を実行できないことに気がついた。pipx なら実行できるらしい。
python 製のコマンドツールはちょくちょくあるので pipx でインストールするようにしよう。恐らく pip –user と同じようなことをしているのだと思われる。
今日の時点で実行するとこんなエラーが起きている
$ pypi-search numpy
[INFO] :: Searching for package `numpy`...
Traceback (most recent call last):
File "/home/mnishi/.local/bin/pypi-search", line 8, in <module>
sys.exit(main())
^^^^^^
File "/home/mnishi/.local/share/pipx/venvs/pypi-search/lib/python3.12/site-packages/pypi_search/main.py", line 35, in main
version_info = pypi.get_version_info()
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/mnishi/.local/share/pipx/venvs/pypi-search/lib/python3.12/site-packages/pypi_search/utils.py", line 41, in get_version_info
version_no = package_name_header.text.split()[1]
^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'text'
ソース見てみると .local/share/pipx/venvs/pypi-search/lib/python3.12/site-packages/pypi-search の utils.py で URL を開いている。(package_name は、検索したい文字列)
ここで .text が返ってこないらしい。
self.response: Optional[requests.Response] = requests.get(
f'http://pypi.org/project/{self.package_name}'
)
try:
試しに、wget するとエラーを意味する html が返ってきてよく見ると javascript が動かないとだめってことらしい。恐らく以前からのスクレーピング対策が強化されたようだ。
それもあるのか、pypi-search の Github に行くとアーカイブになっていた。javascript 対応するのが面倒なのでもうやめることにしたのだと思う。
うーん、困った。
サービスと通信するサンプル 3 部作の追加編です。で Flow (Channel) を使用してみます。
3 部作はこちら
そもそも、なぜ上の3手法を試したのかというと、Claude か Gemini か ChatGTP に「サービスの状態をアクティビティに通知するにはどういう方法がある?」って聞いた結果、3 つの方法が回答にあったのがキッカケだった。
でサンプルを探して作っていくうちに、Flow をイベントバスに使う方法もあるらしいということを探し当てたのでやってみる。
MainActivity はこんな感じになりました。
package red.txn.service_flow
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import red.txn.service_flow.ui.theme.ServiceflowTheme
class MainActivity : ComponentActivity() {
companion object {
const val TAG = "MainActivity"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ServiceflowTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
// launch service
Intent(this, FlowService::class.java).also { intent ->
startService(intent)
}
Log.d(TAG,"service launched")
val scope = CoroutineScope(Dispatchers.IO)
scope.launch {
FlowService.BUS.collect {
Log.d(TAG, "Received data: $it")
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ServiceflowTheme {
Greeting("Android")
}
}
LiveData の observe が Flow の cllect に変わった感じで極端な変化はないですね。わかりやすい。
サービスのインスタンスなしでアクセスできているのは BUS がサービスの中で companion ojbect として定義されているからです。(理解あってる?)
package red.txn.service_flow
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
class FlowService : Service() {
companion object {
val TAG = "FlowService"
private var _BUS = Channel<String>()
val BUS = _BUS.receiveAsFlow()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "onBind")
Thread {
for (i in 1..2) {
Thread.sleep(2000)
updateData("データ$i")
Log.d(TAG, "データ$i")
}
}.start()
return START_STICKY
}
override fun onBind(intent: Intent): IBinder? {
return null
}
fun updateData(data: String) {
val scope = CoroutineScope(Dispatchers.IO)
scope.launch {
_BUS.send(data)
}
}
}
BUS と _BUS は companion object から普通のメンバに変えてもいいかも。
AIチャットボットの回答で漏れていた方法をたまたま見つけたわけですが、現時点では AI の回答が網羅性があり、正しい(妥当か)を判断するには読み取る人間側がそもそもその答え知らないといけない例として覚えておきたい。
AIチャットボットに限らず検索の回答から漏れているものが認識されない、つまり存在しないことにされてしまうのはとても考えさせられると感じてしまう。
LiveDataをFlowにリプレースしてみて得た知見(StateFlow、SharedFlow、Channel) #Android – Qiita
すぐに忘れてしまうので、完全に自分用メモ。
flat パックも snap も基本的にはホスト PC を汚染しない発想なのでインストールしただけの状態ではファイルアクセスが制限されすぎている場合、調整する必要がある。
Flatseal というツールを使うとインストールした flat パッケージの一覧からファイルアクセス権を調整できる。
3 部作の最後です、Messanger を使ってみます。
アクティビティとハンドラーの定義です。
package red.txn.service_messenger
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import red.txn.service_messenger.MainActivity.Companion.TAG
import red.txn.service_messenger.ui.theme.ServicemessengerTheme
class MainActivity : ComponentActivity() {
companion object {
const val TAG = "MainActivity"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ServicemessengerTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
// launch service
Intent(this, MessengerService::class.java).also { intent ->
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}
}
private lateinit var messenger: Messenger
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
messenger = Messenger(service)
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d(TAG, "onServiceDisconnected()")
}
}
}
class MessageHandler: Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when(msg.what) {
MESSAGE_FROM_SERVICE-> {
// handle the response message
Log.d(TAG, "received: ${msg.data.toString()}")
}
else -> {
Log.d(TAG, "received other: $msg")
}
}
}
}
//***
//*** compsable functions
//***
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ServicemessengerTheme {
Greeting("Android")
}
}
class Handler はサービスでも参照します。
package red.txn.service_messenger
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
const val MESSAGE_FROM_SERVICE: Int = 2
class MessengerService : Service() {
companion object {
const val TAG = "MessengerService"
}
private val messenger = Messenger(MessageHandler())
override fun onBind(intent: Intent): IBinder {
Log.d(TAG, "onBind()")
Thread {
for (i in 1..2) {
Thread.sleep(2000)
sendMessageFromService()
Log.d(TAG, "sendBroadcast: $i")
}
}.start()
return MyBinder()
}
inner class MyBinder: Binder() {
fun getService(): MessengerService = this@MessengerService
}
private fun sendMessageFromService() {
val message = Message.obtain()
message.what = MESSAGE_FROM_SERVICE
message.data.putString("message", "Hello from MessengerService")
//message.replyTo = messenger
messenger.send(message)
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy(")
}
}
普通はメッセージの場合、普通は双方向通信に使うことが多いようですが、message.replyTo が空でも問題ないようです。
ちょっと試していないのでなんともいえませんがこのサービスももしかすると、startService() 起動に書き換えることができるかもしれません。その場合は Messenger を Activity に渡す必要があるので、LiveData の時と同じようにMessenger を companion object にする必要がありそうです。
その 2 今度は LiveData を使ってみます。
LiveData を使うならこんな感じ
package red.txn.service_livedata
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import red.txn.service_livedata.ui.theme.ServicelivedataTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ServicelivedataTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
// launch service
Intent(this, LiveDataService::class.java).also { intent ->
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
}
private var bound = false
private lateinit var liveDataService: LiveDataService
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder) {
val binder = service as LiveDataService.MyBinder
liveDataService = binder.getService()
bound = true
observeData()
}
override fun onServiceDisconnected(name: ComponentName?) {
bound = false
}
}
fun observeData() {
liveDataService.BUS.observe(this) { newData ->
Log.d("AAA", "Activity:" + newData.toString())
}
}
}
//***
//*** Composable functions
//***
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ServicelivedataTheme {
Greeting("Android")
}
}
bindService() でサービス起動をしているので少し様子が異なるが、バインドしたとき observeData() で監視している。とっても簡単
package red.txn.service_livedata
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class LiveDataService : Service() {
companion object {
const val TAG = "LiveDataService"
}
val BUS = MutableLiveData<String>()
override fun onBind(intent: Intent): IBinder {
Log.d(TAG, "serviee onBind()")
Thread {
for (i in 1..2) {
Thread.sleep(2000)
updateData("データ$i")
Log.d(TAG, "データ$i")
}
}.start()
val scope = CoroutineScope(Dispatchers.IO)
scope.launch {
for (i in 1..2) {
Thread.sleep(2000)
updateData("データ2$i")
Log.d(TAG, "データ2$i")
}
}
return MyBinder()
}
inner class MyBinder: Binder() {
fun getService(): LiveDataService = this@LiveDataService
}
private fun updateData(newData: String) {
BUS.postValue(newData)
}
}
AndroidManifest.xml は生成されたものなので省略。
startService() でサービス起動したい場合は、こんなふうになった。
package red.txn.service_livedata
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import red.txn.service_livedata.ui.theme.ServicelivedataTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ServicelivedataTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
// launch service
Intent(this, LiveDataService::class.java).also { intent ->
startService(intent)
}
LiveDataService.BUS.observe(this) {
Log.d("BUS change:", "Activity:" + it.toString())
}
}
}
//***
//*** Composable functions
//***
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ServicelivedataTheme {
Greeting("Android")
}
}
サービスの方では LiveData を companion object に入れてインスタンスなしでも取得できるようにしている。
package red.txn.service_livedata
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class LiveDataService : Service() {
companion object {
const val TAG = "LiveDataService"
val BUS = MutableLiveData<String>()
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
Thread {
for (i in 1..2) {
Thread.sleep(2000)
BUS.postValue("newData: $i")
}
}
return START_STICKY
}
}
Gemini を使ってみているが、前の文脈からの続きの質問したら流れをぶった切って新しい話題のように回答するのやめてほしい。Claude のほうがその辺楽かも。
今回は3部作になり、その1です。
何をしたいかというとサービスで何か変更した状態をActivityに知らせる方法を試してみます。
Gemini に聞いてみると 3 つの方法があるようです。
まずは、SendBroadCast を使ってみます。
インテントをブロードキャストするパターンの場合、他のアプリでも受信できるようです。
アクティビティはこんな感じになります。
package red.txn.service_broadcast
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import red.txn.service_broadcast.ui.theme.ServicebroadcastTheme
class MainActivity : ComponentActivity() {
private lateinit var receiver: MyReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ServicebroadcastTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
val filter = IntentFilter("serviceComm")
receiver = MyReceiver()
registerReceiver(receiver, filter, RECEIVER_NOT_EXPORTED)
val serviceIntent = Intent(this, MyService::class.java)
startService(serviceIntent)
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(receiver)
}
}
class MyReceiver: BroadcastReceiver() {
companion object {
val TAG = "MyReceiver"
}
override fun onReceive(context: Context?, intent: Intent) {
val action = intent.action
val extras = intent.extras
Log.d(TAG, "onReceive - action: $action")
extras?.let {
for (key in it.keySet()) {
val value = it.getString(key)
Log.d(TAG, "onReceive - extras: $value")
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
val context = LocalContext.current
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ServicebroadcastTheme {
Greeting("Android")
}
}
クラス MyReceiver は分けたほうがいいですけど、面倒なのでここに入れてます。 IntentFilter に直接文字列で “serviceComm” を入れていますが、これはちゃんと const にしたほうがいいと思います。この値はサービス側でも同じものを使い送信元を識別します。
サービスは、Android Studio のFile > New > Service > Service メニューから追加すると簡単でいいです。
AndroidManifest.xml に必要なエントリを追加してくれます。
package red.txn.service_broadcast
import android.app.Service
import android.content.Intent
import android.content.res.Configuration
import android.os.IBinder
import android.util.Log
class MyService : Service() {
companion object {
val TAG = "MyService"
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Thread {
for (i in 1..2) {
Thread.sleep(3000)
val intent = Intent("serviceComm").putExtra("data", "メッセージ$i")
sendBroadcast(intent)
Log.d(TAG, "sendBroadcast: $i")
}
}.start()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy")
}
}
startService() でサービスを起動しているので onStartCommand() で受けます。一応サービスっぽく時間がかかる処理をするためにダミーで Thread {} で時間稼いでます。
実行すると class MyReceiver: BroadcastReceiver() で受信して、Log.d(TAG, “onReceive – extras: $value”) で内容を表示します。
最後に AndroidManifest.xml を提示しますが、Android Studio が自動生成したものでいじっていません。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Servicebroadcast"
tools:targetApi="31">
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Servicebroadcast">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Shanling の M3X という DAP を使用していますが、SD カードスロットの蓋に付いていた O (オー) リングが突然切れました。
O リングというのは、この場合黒いゴムのパッキンのことをいいます。防水目的でこのリングで水の侵入の防ぐ役割をしています。(ちょっと前のSDカードスロットありのスマホの蓋も同じようになってます。)
仕方ないので瞬間接着剤で切れた O リングをつけてしのいでいたのですがすぐにまた切れてしまい面倒とおもいつつ合いそうな O リングを買って修理してみました。
【楽天市場】線形 0.5mm 外径 1.5mm ~ 9mm 選択 NBR Oリング ニトリルゴム 耐油 耐摩耗:GAVAN
こちらの 線形0.5mm 幅 外径/内径 8mm/7mm です。
オリジナルのものと比較すると若干細いようです。(ちょっと失敗したかもしれません。)
フタの溝にそって着てみると若干細いのが災いしてスカスカですぐ開いてしまいます。仕方ないので2本掛けすると今度は、少しゆるいながらも止まったのでこれでよしとします。
様子見て3本がけか、同じお店で売っていた 0.7mm に変えるかもしません。
同じ現象で困っている人の役にたてれば嬉しいです。