0

I really need your expertise as I got stuck for a long time with this problem. I have a main activity which gets MP3 file uri from the emulator memory. It saves the uri in an SQLite database and reads the database than to populate a ListView. When a ListView item is selected, main activity starts another activity and handles it the file's uri to play the file. If I start the app first time it plays selected files just fine. When I close the app and start it again, I select a ListView item saved in SQLite last time. This time it cause the player activity crash at setDataSource stage. If I select a new MP3 file from emulator memory this time however, it works ok. Looks like the problem is connected to uri and SQLite. I checked that uri string is the same in both cases. Here is the main activity

class MainActivity : AppCompatActivity() {
    
        val REQUEST_FILE = 1
        lateinit var newFilePath: Uri
        lateinit var newFileName: String
        lateinit var AuDB: SQLiteDatabase
        val auName = mutableListOf<String>("")
        var auUri = mutableListOf<Uri>()
        var audioFileValues: ContentValues = ContentValues()
    
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            val MyDBHelper = AudioSQLhelper(this)
            AuDB = MyDBHelper.writableDatabase

            val auCursor = AuDB.query("myaudio", arrayOf("name", "uri"), null, null, null, null, "prio", null)
            readcursor(auCursor)
    
            val tbMain = findViewById<Toolbar>(R.id.toolbar1)
            setSupportActionBar(tbMain)
    
            val scAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, auName)
            val lvData = findViewById<ListView>(R.id.lv1)
            lvData.setAdapter(scAdapter)
    
            lvData.setOnItemClickListener { parent, view, position, id ->
    
                val playIntent: Intent = Intent(this, PlayTest::class.java)

                playIntent.putExtra("aname", auName[position])
                playIntent.setData(auUri[position])

                startActivity(playIntent)
            }
        }
    
        override fun onCreateOptionsMenu(menu: Menu?): Boolean {
            menuInflater.inflate(R.menu.menu_main, menu)
            return super.onCreateOptionsMenu(menu)
        }
    
        override fun onOptionsItemSelected(item: MenuItem): Boolean {
            when (item.itemId) {
                R.id.action_select_file -> {
    // Select a new audio file
                    val audioIntent: Intent = Intent(Intent.ACTION_GET_CONTENT)
                    audioIntent.setType("audio/mpeg")
                    audioIntent.addCategory(Intent.CATEGORY_OPENABLE)
                    startActivityForResult(audioIntent, REQUEST_FILE)
                }
            }
            return super.onOptionsItemSelected(item)
        }
    
        private fun readcursor(auCursor: Cursor) {
            auCursor.moveToFirst()
            auName.clear()
            auUri.clear()
            while (auCursor.isAfterLast == false) {
                auName.add(auCursor.getString(0))
                auUri.add(Uri.parse(auCursor.getString(1)))
                auCursor.moveToNext()
            }
        }
    
        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            super.onActivityResult(requestCode, resultCode, data)
            if (requestCode == REQUEST_FILE && resultCode == RESULT_OK) {
                newFilePath = data?.data!!
                newFileName = newFilePath.lastPathSegment?.substringAfterLast('/').toString()
    
                if (AuDB.query("myaudio", arrayOf("_id"), "name=?", arrayOf(newFileName), null, null, null).moveToFirst()) {
                    val au_text = "This file has already been added!"
                    val au_duration = Toast.LENGTH_SHORT
                    val toast = Toast.makeText(applicationContext, au_text, au_duration)
                    toast.show()
                } else {
                    // Add the file to the database
                    audioFileValues.put("name", newFileName)
                    audioFileValues.put("uri", newFilePath.toString())
                    audioFileValues.put("prio", 1)
                    addRecord(audioFileValues)
    
                }
            }
        }
        // Add new file at the beginning if the list
        fun addRecord(content: ContentValues) {
            val MyDBHelper = AudioSQLhelper(this)
            val AuDB = MyDBHelper.writableDatabase
       // Increase others file priority fiels by one
            AuDB.execSQL("UPDATE myaudio SET prio = prio + 1")

            AuDB.insert("myaudio", null, content)
            val auCursor = AuDB.query("myaudio", arrayOf("name", "uri"), null, null, null, null, "prio", null)

            readcursor(auCursor)
    
            val scAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, auName)
            val lvData = findViewById<ListView>(R.id.lv1)
            lvData.setAdapter(scAdapter)
        }
    }

Here is the player activity

class PlayTest : AppCompatActivity() {

    var mPlayer = MediaPlayer()
    lateinit var auUri: Uri

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_playtest)

        val caption = findViewById<TextView>(R.id.txtAUName)
        caption.text = intent.getStringExtra("aname")
        auUri = intent.data!!
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun playClick(view: View) {
        when (view.id) {
            R.id.btnAStart -> {
                mPlayer = MediaPlayer().apply {
                    setAudioAttributes(
                        AudioAttributes.Builder()
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .build()
                    )
                    setDataSource(this@PlayTest, auUri)
                    prepare()
                }
                mPlayer.start()
            }
            R.id.btnAStop -> {
                mPlayer.pause()
            }
            R.id.btnAClose -> {
                    mPlayer.release()
                    finish()

            }
        }
    }
}

Here is the Logcat. It doesn't say much to me

2021-04-03 01:10:51.193 11233-11233/com.example.test1 E/MediaPlayerNative: Unable to create media player
2021-04-03 01:10:51.195 11233-11233/com.example.test1 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.test1, PID: 11233
    java.lang.IllegalStateException: Could not execute method for android:onClick
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:414)
        at android.view.View.performClick(View.java:7448)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
        at android.view.View.performClickInternal(View.java:7425)
        at android.view.View.access$3600(View.java:810)
        at android.view.View$PerformClick.run(View.java:28305)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409)
        at android.view.View.performClick(View.java:7448) 
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119) 
        at android.view.View.performClickInternal(View.java:7425) 
        at android.view.View.access$3600(View.java:810) 
        at android.view.View$PerformClick.run(View.java:28305) 
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
     Caused by: java.io.IOException: setDataSource failed.: status=0x80000000
        at android.media.MediaPlayer.nativeSetDataSource(Native Method)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1175)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1162)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1079)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1004)
        at com.example.test1.PlayTest.playClick(PlayTest.kt:46)
        at java.lang.reflect.Method.invoke(Native Method) 
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409) 
        at android.view.View.performClick(View.java:7448) 
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119) 
        at android.view.View.performClickInternal(View.java:7425) 
        at android.view.View.access$3600(View.java:810) 
        at android.view.View$PerformClick.run(View.java:28305) 
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
cheid
  • 1
  • 1
  • Does this answer your question? [Unfortunately MyApp has stopped. How can I solve this?](https://stackoverflow.com/questions/23353173/unfortunately-myapp-has-stopped-how-can-i-solve-this) – a_local_nobody Apr 02 '21 at 19:04

1 Answers1

0

Hope this will help a newbie like me to save some time if he faced similar problem. The problem was related to Android allowing full access to handling Uri of a file picked by a user, via Intent(Intent.ACTION_GET_CONTENT) in my case. This Uri doesn't have any permission after your gadget or emulator restart. To keep the file accessible by means of Uri, you need to take the persistable URI permission. Here is the link to the official guidelines. I have added this code fragment to my onActivityResult function, where I receive a file Uri from the Intent.

        val contentResolver = applicationContext.contentResolver
        val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION
        contentResolver.takePersistableUriPermission(newFilePath, takeFlags) 
cheid
  • 1
  • 1