Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 保持互相呼叫服务/广播_Android_Kotlin - Fatal编程技术网

Android 保持互相呼叫服务/广播

Android 保持互相呼叫服务/广播,android,kotlin,Android,Kotlin,我正在构建一个简单的应用程序,它可以持续监控媒体级别,并一直将其调整为最高级别的20%,如果用户增加,它应该会再次回到20% 我遵循的概念是通过一个服务进行监控,一旦这个服务被破坏,它会调用一个广播接收器,而广播接收器又会再次调用接收器,以此类推,这是一个无休止的循环,但下面的代码看起来有些错误,soit没有按预期工作,服务/广播也不会继续互相调用 我以以下方式启动了main活动: class MainActivity : AppCompatActivity() { override

我正在构建一个简单的应用程序,它可以持续监控媒体级别,并一直将其调整为最高级别的20%,如果用户增加,它应该会再次回到20%

我遵循的概念是通过一个服务进行监控,一旦这个服务被破坏,它会调用一个广播接收器,而广播接收器又会再次调用接收器,以此类推,这是一个无休止的循环,但下面的代码看起来有些错误,soit没有按预期工作,服务/广播也不会继续互相调用

我以以下方式启动了
main活动

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val audio = this.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val level = audio.getStreamVolume(AudioManager.STREAM_MUSIC)

        val maxVolume = audio.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
        val percent = 0.2f
        val twintyVolume = (maxVolume * percent).toInt()

        if ( level > twintyVolume) {
            Toast.makeText(this,"audio level is $level", Toast.LENGTH_LONG).show()
            audio.setStreamVolume(AudioManager.STREAM_MUSIC,twintyVolume,0)
        }

        this.startService(Intent(this, VolumeCheck::class.java))
    }
}
以上操作将进行初始检查,并将介质卷减少到最大卷的20%,然后启动该服务,该服务使用以下代码执行相同操作:

class VolumeCheck : Service() {

    private lateinit var context: Context

    override fun onCreate() {
        super.onCreate()
        context = this
        Toast.makeText(this, "service created", Toast.LENGTH_SHORT).show();
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

        val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val mediaPlayer = MediaPlayer()


     //   Thread().run {
            val maxVolume = audio.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
            val percent = 0.2f
            val twintyVolume = (maxVolume * percent).toInt()
            if (mediaPlayer.isPlaying) {
                val level = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
                if ( level > twintyVolume) {
                    Toast.makeText(context,"audio level is $level", Toast.LENGTH_LONG).show()
                    audio.setStreamVolume(AudioManager.STREAM_MUSIC,twintyVolume,0)
                }
            }
      //      Thread.sleep(3000)
     //   }
        stopSelf()
        return Service.START_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        //TODO for communication return IBinder implementation
        return null
    }

    override fun onDestroy() {
        super.onDestroy()
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show()
        val intent = Intent("com.kortex.mediafix.BootUpReceiver")
        sendBroadcast(intent)
    }
}
一旦服务被破坏,它将调用引导广播接收器,引导广播接收器将再次调用服务:

class BootUpReceiver: BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        context.startService(Intent(context, VolumeCheck::class.java))
    }
}
清单是:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.kortex.mediafix">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".BootUpReceiver"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
        <service android:name=".VolumeCheck" />
    </application>

</manifest>

这一行不调用您的广播接收器,而是以“com.kortex.mediafix.bootupureceiver”的形式进行意图与意图操作

更改清单中BootUpReceiver的条目以接收此操作

<receiver android:name=".BootUpReceiver"
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            <action android:name="com.kortex.mediafix.BootUpReceiver" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>

我通过使用
服务调用的
ContentObserver
解决了这个问题,因此我现在的代码是:

  • MainActivity
    启动应用程序、进行首次调整以及启动服务:

    class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val audio = this.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val level = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
    
        val maxVolume = audio.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
        val percent = 0.2f
        val twintyVolume = (maxVolume * percent).toInt()
    
        if ( level > twintyVolume) audio.setStreamVolume(AudioManager.STREAM_MUSIC,twintyVolume,0)
    
        Toast.makeText(this,"Audio level adjusted to 20% instead of $level", Toast.LENGTH_LONG).show()
    
        this.startService(Intent(this, VolumeCheck::class.java))
    
        finish()
       }
    }
    
  • 广播
    每次重新启动设备时启动应用程序和服务:

    class BootUpReceiver: BroadcastReceiver() {
    
    override fun onReceive(context: Context, intent: Intent) {
        context.startService(Intent(context, VolumeCheck::class.java))
       }
    }
    
  • 服务
    注册并呼叫观察员:

    class VolumeCheck : Service() {
    
    private lateinit var context: Context
    private lateinit var myObserver: VolumeOnserver
    
    
    override fun onCreate() {
        super.onCreate()
        context = this
        // Define the VolumeOnserver
        myObserver = VolumeOnserver(context, Handler())
        Toast.makeText(this, "service created", Toast.LENGTH_SHORT).show();
    }
    
    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    
        // Register the VolumeOnserver for setting changes
        contentResolver.registerContentObserver(android.provider.Settings.System.CONTENT_URI ,true, myObserver);
    
        return Service.START_STICKY
    }
    
    override fun onBind(intent: Intent): IBinder? {
        return null
    }
    
    override fun onDestroy() {
        super.onDestroy()
    
        // Unregister the VolumeOnserver
        contentResolver.unregisterContentObserver(myObserver);
       }
    }
    
  • 观察者
    观察
    设置的任何变化
    并检查媒体音量,必要时进行调整:

    class VolumeOnserver (context: Context, h: Handler?): ContentObserver(h) {
    
    private val context = context
    
    override fun onChange(selfChange: Boolean) {
        onChange(selfChange, uri = null)
    }
    
    // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
    override fun onChange(selfChange: Boolean, uri: Uri?) {
        // Handle change.
        val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val level = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
    
        val maxVolume = audio.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
        val percent = 0.2f
        val twintyVolume = (maxVolume * percent).toInt()
    
        if ( level > twintyVolume) audio.setStreamVolume(AudioManager.STREAM_MUSIC,twintyVolume,0)
    
        // Toast.makeText(context,"audio level is $level", Toast.LENGTH_LONG).show()
       }
    }
    
  • 清单
    文件为:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.kortex.mediafix">
    
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <receiver android:name=".BootUpReceiver"
                android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                    <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                   <action android:name="com.kortex.mediafix.BootUpReceiver" />
    
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </receiver>
            <service android:name=".VolumeCheck" />
        </application>
    
    </manifest>
    
    
    


    但有一个问题是它不稳定,我认为用户坚持要改变音量,经过多次尝试,服务和/或观察员是/是不再工作,直到应用程序重新启动

    另一种不使用
    服务的方法是从
    BroadcastReceiver

  • 广播接收机

    类BootUpReceiver:BroadcastReceiver(){

  • ContentObserver

    类VolumeOnserver(上下文:context,h:Handler?):ContentObserver(h){

  • main活动

    类MainActivity:AppCompatActivity(){

  • <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.kortex.mediafix">
    
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <receiver android:name=".BootUpReceiver"
                android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                    <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                   <action android:name="com.kortex.mediafix.BootUpReceiver" />
    
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </receiver>
            <service android:name=".VolumeCheck" />
        </application>
    
    </manifest>
    
    override fun onReceive(context: Context, intent: Intent) {
        val myObserver = VolumeOnserver(context, Handler())
    
        // Register the VolumeOnserver for setting changes
        context.contentResolver.registerContentObserver(
                android.provider.Settings.System.CONTENT_URI ,true,
                myObserver)
       }
    }
    
    private val context = context
    
    override fun onChange(selfChange: Boolean) {
        onChange(selfChange, uri = null)
    }
    
    // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
    override fun onChange(selfChange: Boolean, uri: Uri?) {
        // Handle change.
        val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val level = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
    
        val maxVolume = audio.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
        val percent = 0.2f
        val twintyVolume = (maxVolume * percent).toInt()
    
        if ( level > twintyVolume) audio.setStreamVolume(AudioManager.STREAM_MUSIC,twintyVolume,0)
        }
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val audio = this.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val level = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
    
        val maxVolume = audio.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
        val percent = 0.2f
        val twintyVolume = (maxVolume * percent).toInt()
    
        if ( level > twintyVolume) audio.setStreamVolume(AudioManager.STREAM_MUSIC,twintyVolume,0)
    
        finish()
       }
    }