NullPointerException beim erteilen von Rechten

  • Antworten:2
  • Bentwortet
Robbiani Renato
  • Forum-Beiträge: 648

26.10.2024, 21:25:49 via Website

Hallo zusammen

Ich bekomme beim Erteilen von Rechten andauernd eine "NullPointerException".

private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){ isRecht : Map<String, Boolean> ->
    if( (isRecht.get(Manifest.permission.READ_EXTERNAL_STORAGE)!!) && (isRecht.get(
            Manifest.permission.WRITE_EXTERNAL_STORAGE)!!)){
        str_text = getString(R.string.lbl_recht_neu)
        Toast.makeText(ctx, str_text, Toast.LENGTH_SHORT).show()
    }else{
        str_text = getString(R.string.lbl_recht_fasch)
        Toast.makeText(ctx, str_text, Toast.LENGTH_SHORT).show()

// finish()
}
}

Ich habe die Zeile mit "finish()" auskommentiert. Denn er geht immer durch diesen Zweig. Nehme ich diese Zeile raus, dann startet die App ohne Probleme.

Sieht jemand wo das Problem liegt?

package ch.robbisoft.lustigesrechnen

import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.speech.tts.TextToSpeech
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.widget.EditText
import android.widget.SeekBar
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.*
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.widget.addTextChangedListener
import ch.robbisoft.lustigesrechnen.databinding.ActivityMainBinding
import kotlin.math.abs
import androidx.preference.PreferenceManager
import java.util.Locale
import kotlin.math.absoluteValue
import java.io.*
import java.nio.file.Files
import java.nio.file.Paths
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

class MainActivity : AppCompatActivity(), TextToSpeech.OnInitListener {

var rechte = arrayOf(
    Manifest.permission.WRITE_EXTERNAL_STORAGE,
    Manifest.permission.READ_EXTERNAL_STORAGE
)
private var str_text: String? = null
private var tts: TextToSpeech? = null

private lateinit var ctx: Context
private lateinit var ac_ctx: Context

private lateinit var binding: ActivityMainBinding
private var zahl_eins: Int = 0
private var zahl_zwei: Int = 0
private var resultat: Int = 0
private var frage : String = ""
private var addi: Boolean = true   //Additionrchnung
private var subi: Boolean = false  //Subtraktionrechnung
private var mult: Boolean = false  //Multiplikationrechnung
private var divi: Boolean = false  //Divisionenrechnung
private var gros: Int = 20         //Wie gross ist der Zahlenraum
private var negativ: Boolean = false //Negative Resultate zulassen
private var hundert: Boolean = true //Hundertergrenze überschreiten zulassen
private var zahl_richtig : Int = 0 // Anzahl der richtig gelösten Aufgaben
private var zahl_falsch : Int = 0 // Anzahl der falsch gelösten Aufgaben
private var str_rechnung : String = "" //Rechnung für Sprachausgabe
private var str_protokoll : String = ""
private var str_proname : String = "" //Name der Protokolldatei
private val formater = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
private var b_schreib : Boolean = true //Soll ins Protokoll geschrieben werden
                                        //Damit beim Aufruf der Activity anzeige nicht ins Protokoll geschrieben wird

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    enableEdgeToEdge()
    binding = ActivityMainBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)

// setContentView(R.layout.activity_main)

    ctx = applicationContext
    ac_ctx = this
    tts = TextToSpeech(ac_ctx, ac_ctx as MainActivity)

    //Daten laden

// val prefs = PreferenceManager.getDefaultSharedPreferences(ac_ctx)
val prefs = ctx.getSharedPreferences("lustig", Context.MODE_PRIVATE)
if (prefs.contains("Key_ad")) {
addi = prefs.getBoolean("Key_ad", true)
subi = prefs.getBoolean("Key_su", true)
mult = prefs.getBoolean("Key_mu", false)
divi = prefs.getBoolean("Key_di", false)
gros = prefs.getInt("Key_gr", 20)
negativ = prefs.getBoolean("Key_negativ", false)
hundert = prefs.getBoolean("Key_hundert", true)
str_proname = prefs.getString("Key_proname", "protokoll").toString()

        binding.edtName.setText(str_proname)
    }

    ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.lay_main)) { v, insets ->
        val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
        v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
        insets
    }

    //Dialog richtig
    val melde_gut = AlertDialog.Builder(this)
    melde_gut.setTitle(resources.getString(R.string.m_gut))
    melde_gut.setMessage(resources.getString(R.string.m_guttext))
    melde_gut.setIcon(ResourcesCompat.getDrawable(getResources(), R.drawable.lachen, null))
    melde_gut.setPositiveButton(resources.getString(R.string.btn_weit)) { _, _ ->
        anzeige()
    }
    //Dialog falsch
    val melde_falsch = AlertDialog.Builder(this)
    melde_falsch.setTitle(resources.getString(R.string.m_fel))
    melde_falsch.setMessage(resources.getString(R.string.m_feltext))
    melde_falsch.setIcon(ResourcesCompat.getDrawable(getResources(), R.drawable.traurig, null))
    melde_falsch.setPositiveButton(resources.getString(R.string.btn_weit)) { _, _ ->
        str_protokoll += frage + '\n'
    }

    anzeige()

    binding.btnEins.setOnClickListener {
        var button_res = binding.btnEins.text.toString()
        if (teste(button_res)) {
            zahl_richtig++
            melde_gut.show()
        } else {
            zahl_falsch++
            binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))
            melde_falsch.show()
        }
    }

    binding.btnZwei.setOnClickListener {
        var button_res = binding.btnZwei.text.toString()
        if (teste(button_res)) {
            zahl_richtig++
            melde_gut.show()
        } else {
            zahl_falsch++
            binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))
            melde_falsch.show()
        }
    }

    binding.btnDrei.setOnClickListener {
        var button_res = binding.btnDrei.text.toString()
        if (teste(button_res)) {
            zahl_richtig++
            binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))
            melde_gut.show()
        } else {
            zahl_falsch++
            binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))
            melde_falsch.show()
        }
    }

    binding.btnVier.setOnClickListener {
        var button_res = binding.btnVier.text.toString()
        if (teste(button_res)) {
            zahl_richtig++
            melde_gut.show()
        } else {
            zahl_falsch++
            binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))
            melde_falsch.show()
        }
    }

    binding.editTextNumber.setText(gros.toString())
    binding.seeRaum.progress = gros
    binding.seeRaum.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
            if (seekBar != null) {
                gros = seekBar.progress
                binding.editTextNumber.setText(gros.toString())
            }
        }

        override fun onStartTrackingTouch(seekBar: SeekBar?) {

        }

        override fun onStopTrackingTouch(seekBar: SeekBar?) {

        }
    })

    binding.editTextNumber.setOnEditorActionListener(object : TextView.OnEditorActionListener {
        override fun onEditorAction(view: TextView, actionId: Int, event: KeyEvent?): Boolean {
            gros = view.text.toString().toInt()
            binding.seeRaum.progress = gros
            KeyBoard().toggle(this@MainActivity)
            return true
        }
    })

    binding.chipAdd.isChecked = addi
    binding.chipAdd.setOnCheckedChangeListener { buttonView, isChecked ->
        addi = isChecked
    }

    binding.chipSub.isChecked = subi
    binding.chipSub.setOnCheckedChangeListener { buttonView, isChecked ->
        subi = isChecked
    }

    binding.chipMulti.isChecked = mult
    binding.chipMulti.setOnCheckedChangeListener { buttonView, isChecked ->
        mult = isChecked
    }

    binding.chipDiv.isChecked = divi
    binding.chipDiv.setOnCheckedChangeListener { buttonView, isChecked ->
        divi = isChecked
    }

    binding.swtNegativ.isChecked = negativ
    binding.swtNegativ.setOnCheckedChangeListener { buttonView, isChecked ->
        negativ = isChecked
    }

    binding.swiHundert.isChecked = hundert
    binding.swiHundert.setOnCheckedChangeListener { buttonView, isChecked ->
        hundert = isChecked
    }

    binding.edtName.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

        override fun afterTextChanged(s: Editable?) {
        }
    })

    binding.btnAnzeigen.setOnClickListener {
        //Layout aufrufen Daten übergeben und anzeigen
        val intent = Intent(ctx, Protokoll::class.java)
        b_schreib = false

        str_protokoll += getAnzahl(zahl_richtig, zahl_falsch) + '\n'

        intent.putExtra("proto", str_protokoll)
        protokollhorcher.launch(intent)
    }

    binding.btnLoeschen.setOnClickListener {
        str_protokoll = ""

// writeToFile(str_protokoll, str_proname)
writefile(str_protokoll, str_proname)
zahl_richtig = 0
zahl_falsch = 0
binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))

        val str_loesch = resources.getString(R.string.lbl_loeschen)
        Toast.makeText(ctx, str_loesch, Toast.LENGTH_LONG).show()
        //Zeitstempel schreiben
        val zeitstempel = LocalDateTime.now().format(formater)
        str_protokoll = resources.getString(R.string.lbl_start) + zeitstempel + '\n'
    }

    binding.edtName.afterTextChanged {
        //altes Protokoll Speichern
        str_protokoll += getAnzahl(zahl_richtig, zahl_falsch) + '\n'
        //Zeitstempel schreiben
        val zeitstempel = LocalDateTime.now().format(formater)
        str_protokoll += resources.getString(R.string.lbl_ende) + zeitstempel + '\n'

// writeToFile(str_protokoll, str_proname)
writefile(str_protokoll, str_proname)

        //neues Protokoll anlegen
        str_proname = it.toString()
        //bisheriges Protokoll lesen

// str_protokoll = readFromFile(str_proname)
str_protokoll = readfile(str_proname)
//Zeitstempel schreiben
str_protokoll += resources.getString(R.string.lbl_start) + zeitstempel + '\n'
zahl_richtig = 0
zahl_falsch = 0
binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))
}

    binding.txtAnzeige.setOnClickListener {
        //Rechnung vorlesen
        if(tts!! != null) {
            tts!!.speak(str_rechnung, TextToSpeech.QUEUE_FLUSH, null, "")
        }
    }

    requestPermissionLauncher.launch( rechte )
}

override fun onStart() {
    super.onStart()
    //Protokoll aus Dateilesen
    var str_dat = binding.edtName.text.toString()
    //Wenn Dateiname leer ist dann einen defaultnamen setzen
    if( str_dat.isEmpty() ){
        str_dat = "protokoll"
        binding.edtName.setText(str_dat)
    }

// str_protokoll = readFromFile( str_dat )
str_protokoll = readfile( str_dat )

    if( b_schreib ) {
        //Zeitstempel schreiben
        val zeitstempel = LocalDateTime.now().format(formater)
        str_protokoll += resources.getString(R.string.lbl_start) + zeitstempel + '\n'
        // Auf null Setzen damit es bei jedem Start wieder von vorne beginnt
        zahl_richtig = 0
        zahl_falsch = 0
        binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))
    }
}

override fun onStop() {
    if( b_schreib ) {
        str_protokoll += getAnzahl(zahl_richtig, zahl_falsch) + '\n'

        val zeitstempel = LocalDateTime.now().format(formater)
        str_protokoll += resources.getString(R.string.lbl_ende) + zeitstempel + '\n'
        writefile(str_protokoll, str_proname)
    }

    val prefs = ctx.getSharedPreferences("lustig", Context.MODE_PRIVATE)
    val prefw = prefs.edit()
    prefw.putBoolean("Key_ad", addi)
    prefw.putBoolean("Key_su", subi)
    prefw.putBoolean("Key_mu", mult)
    prefw.putBoolean("Key_di", divi)
    prefw.putInt("Key_gr", gros)
    prefw.putBoolean("Key_negativ", negativ)
    prefw.putBoolean("Key_hundert", hundert)
    prefw.putString("Key_proname", str_proname)
    prefw.apply()
    prefw.commit()

    //Protokoll in Datei speichern

// writeToFile(str_protokoll, str_proname)
writefile(str_protokoll, str_proname)

    super.onStop()
}

override fun onDestroy() {
    // Shutdown TTS Sprachausgabe
    if (tts != null) {
        tts!!.stop()
        tts!!.shutdown()
    }

    super.onDestroy()
}

fun anzeige() {
    //Rechenaufgabe stellen
    var fragefrage = getString(R.string.lbl_frage)
    frage = rechnung(gros, addi, subi, mult, divi)
    fragefrage += frage
    binding.txtAnzeige.setText(fragefrage)

    binding.txtAnzahl.setText(getAnzahl(zahl_richtig, zahl_falsch))
    //Sprachausgabe
    if(tts != null) {
        tts!!.speak(str_rechnung, TextToSpeech.QUEUE_FLUSH, null, "")
    }
    // Welcher Button zeigt das richtige Resultat
    val was = (1..4).random()
    when (was) {
        1 -> {
            binding.btnEins.setText(resultat.toString())
            binding.btnZwei.setText(zufallres())
            binding.btnDrei.setText(zufallres())
            binding.btnVier.setText(zufallres())
        }

        2 -> {
            binding.btnEins.setText(zufallres())
            binding.btnZwei.setText(resultat.toString())
            binding.btnDrei.setText(zufallres())
            binding.btnVier.setText(zufallres())
        }

        3 -> {
            binding.btnEins.setText(zufallres())
            binding.btnZwei.setText(zufallres())
            binding.btnDrei.setText(resultat.toString())
            binding.btnVier.setText(zufallres())
        }

        4 -> {
            binding.btnEins.setText(zufallres())
            binding.btnZwei.setText(zufallres())
            binding.btnDrei.setText(zufallres())
            binding.btnVier.setText(resultat.toString())
        }
    }
}

fun rechnung(raum: Int, ad: Boolean, su: Boolean, mu: Boolean, di: Boolean): String {
    zahl_eins = (1..raum).random()
    zahl_zwei = (1..raum).random()

    var was: Int = 0
    var res: String = ""
    val opera: Array<operator> = operator.values()
    var tun: Array<Boolean> = arrayOf(ad, su, mu, di)

    //Wahl der Operation und Prüfen ob es möglich ist
    do {
        was = (0..3).random()
    } while (!tun.get(was))

    when (opera.get(was).toString()) {
        "AD" -> {
            resultat = zahl_eins + zahl_zwei
            if(!hundert){ //Obergrenze darf nicht überschritten werden
                do{
                    zahl_zwei -= 1
                    resultat = zahl_eins + zahl_zwei
                }while (resultat > gros)
            }
            str_rechnung = zahl_eins.toString() + " plus " + zahl_zwei.toString()
            res = zahl_eins.toString() + " + " + zahl_zwei.toString()
        }

        "SU" -> {
            if (!negativ) {
                if (zahl_zwei > zahl_eins) {
                    var pool = zahl_eins
                    zahl_eins = zahl_zwei
                    zahl_zwei = pool
                }
            }
            resultat = zahl_eins - zahl_zwei
            if(!hundert){ //Obergrenze darf nicht überschritten werden
                do{
                    zahl_eins += 1
                    resultat = zahl_eins - zahl_zwei
                }while(resultat.absoluteValue > gros)
            }
            str_rechnung = zahl_eins.toString() + " minus " + zahl_zwei.toString()
            res = zahl_eins.toString() + " - " + zahl_zwei.toString()
        }

        "MU" -> {
            resultat = zahl_eins * zahl_zwei
            if (!hundert) { //Obergrenze darf nicht überschritten werden
                do {
                    zahl_zwei -= 2
                    resultat = zahl_eins * zahl_zwei
                }while (resultat > gros)
            }
            str_rechnung = zahl_eins.toString() + " mal " + zahl_zwei.toString()
            res = zahl_eins.toString() + " x " + zahl_zwei.toString()
        }

        "DI" -> {
            zahl_zwei = (1..9).random()
            resultat = zahl_eins * zahl_zwei
            if(!hundert){ //Obergrenze darf nicht überschritten werden
                do{
                    zahl_eins -= 1
                    resultat = zahl_eins * zahl_zwei
                }while(resultat > gros)
            }
            var pool = resultat
            resultat = zahl_eins
            zahl_eins = pool
            str_rechnung = zahl_eins.toString() + " durch " + zahl_zwei.toString()
            res = zahl_eins.toString() + " : " + zahl_zwei.toString()
        }

        else -> {
            resultat = zahl_eins + zahl_zwei
            if(!hundert){ //Obergrenze darf nicht überschritten werden
                do{
                    zahl_zwei -= 1
                    resultat = zahl_eins + zahl_zwei
                }while (resultat > gros)
            }
            str_rechnung = zahl_eins.toString() + " plus " + zahl_zwei.toString()
            res = zahl_eins.toString() + " + " + zahl_zwei.toString()
        }
    }

    return res
}

// Zufallsresultate erstellen
fun zufallres(): String {
    var zufallzahl : Int = 0
    if (negativ) {
        zufallzahl = ((gros * -1)..gros).random()
    } else{
        zufallzahl = (1..gros).random() //nur Positive Resultate zulassen
    }
    if( zufallzahl == resultat){
        zufallzahl + 5
    }
    return (resultat + zufallzahl).toString()
}

//Testen ob der richtige Button geklickt wurde
fun teste(s_wert : String) : Boolean{
    val but_res = s_wert.toFloat()
    var res : Float = 0F
        res = but_res - resultat
    if( abs(res) < 1 )
        return true
    else
        return false
}

private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){ isRecht : Map<String, Boolean> ->
    if( (isRecht.get(Manifest.permission.READ_EXTERNAL_STORAGE)!!) && (isRecht.get(
            Manifest.permission.WRITE_EXTERNAL_STORAGE)!!)){
        str_text = getString(R.string.lbl_recht_neu)
        Toast.makeText(ctx, str_text, Toast.LENGTH_SHORT).show()
    }else{
        str_text = getString(R.string.lbl_recht_fasch)
        Toast.makeText(ctx, str_text, Toast.LENGTH_SHORT).show()

// finish()
}
}

fun onClickRequestPermission( iew : View){
    var result : Int
    val listPermissionsNeeded : MutableList<String> = ArrayList<String>()
    for( p in rechte ){
        result = ContextCompat.checkSelfPermission(this, p)
        if(result != PackageManager.PERMISSION_GRANTED){
            listPermissionsNeeded.add(p)
        }
    }
    if( !listPermissionsNeeded.isEmpty() ){
        ActivityCompat.requestPermissions(this, (listPermissionsNeeded.toTypedArray() as Array<String?>;), MULTIPLE_PERMISSIONS)
    }
}

private fun pruefrechte(): Boolean {
    var result: Int
    val listPermissionsNeeded: MutableList<String> = ArrayList<String>()
    for (p in rechte) {
        result = ContextCompat.checkSelfPermission(this, p)
        if (result != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add((p))
        }
    }
    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(this, (listPermissionsNeeded.toTypedArray() as Array<String?>;), MULTIPLE_PERMISSIONS)
        // keine permissions gesetzt

        return false
    }
    // alle permissions gesetzt
    return true
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when (requestCode) {
        MULTIPLE_PERMISSIONS -> {
            if (grantResults.size > 0) {
                var permissionsDenied = ""
                for (per in permissions) {
                    if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                        permissionsDenied += "\n" + per
                    }
                }
                // Nach dem ersten Male
            }

// return
}
}
}

companion object {
    const val MULTIPLE_PERMISSIONS = 99
}

override fun onInit(status: Int) {
    if (status == TextToSpeech.SUCCESS) {
        // set US English as language for tts
        val result = tts!!.setLanguage(Locale.GERMAN)

        if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
            val str_sprache = getString(R.string.lbl_sprache)
            Log.e("TTS",getString(R.string.lbl_sprache))
            Toast.makeText(ctx, str_sprache, Toast.LENGTH_SHORT).show()
            tts = null
        } else {
            //alles ist gut gegangen
            Toast.makeText(ctx, getString(R.string.lbl_spracheio), Toast.LENGTH_SHORT).show()
        }

    } else {
        tts = null
        Log.e("TTS", getString(R.string.lbl_initial))
    }
}

// private fun writeToFile(data: String, datname : String) {
// try { //MODE_PRIVATE Daten können nur von der App gelesen werden
// val fileOutputStream: FileOutputStream = openFileOutput(datname, MODE_PRIVATE)
// fileOutputStream.write(data.toByteArray())
// fileOutputStream.close()
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }

private fun writefile(str_text : String, str_datname : String){
    val str_pfad = ac_ctx.applicationInfo.dataDir

    try{
        //Prüfen ob der Pfas vorhanden ist; Wenn nicht dann anlegen
        val path = Paths.get(str_pfad)
        val isdir = Files.isDirectory(path)
        if(isdir) {//Prüfen ob Pfad existiert
            File(str_pfad, str_datname).writeText(str_text)
        }else{
            File(str_pfad).mkdir() //Pfad anlegen
            File(str_pfad, str_datname).writeText(str_text)
        }
    }catch( e : Exception ){
        e.printStackTrace()
    }
}

// private fun readFromFile(datname : String): String {
// var fileInputStream: FileInputStream? = null
// var inputStreamReader: InputStreamReader? = null
// var bufferedReader: BufferedReader? = null
// val stringBuilder = StringBuilder()
//
// try {
// fileInputStream = openFileInput(datname)
// inputStreamReader = InputStreamReader(fileInputStream)
// bufferedReader = BufferedReader(inputStreamReader)
//
// var text: String? = bufferedReader.readLine()
// while (text != null) {
// text += '\n'
// stringBuilder.append(text)
// text = bufferedReader.readLine()
// }
// } catch (e: Exception) {
// e.printStackTrace()
// } finally {
// try {
// bufferedReader?.close()
// inputStreamReader?.close()
// fileInputStream?.close()
// } catch (e: IOException) {
// e.printStackTrace()
// }
// }
//
// return stringBuilder.toString()
// }

private fun readfile( str_datname : String ) : String{
    var str_text : String = ""
    val str_pfad = ac_ctx.applicationInfo.dataDir

    try{
        val str_file = File(str_pfad, str_datname)
        if( str_file.exists() ){
            str_text = File(str_pfad, str_datname).readText()
        }
    }catch( e : Exception ){
        e.printStackTrace()
    }

    return str_text
}

fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
    this.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

        override fun afterTextChanged(editable: Editable?) {
            afterTextChanged.invoke(editable.toString())
        }
    })
}

fun getAnzahl(n_richtig : Int, n_falsch : Int) : String{
    var str_stand : String = ""
    str_stand+= resources.getString(R.string.lbl_richtig) + n_richtig + " / "
    str_stand += resources.getString(R.string.lbl_falsch) + n_falsch

    return str_stand
}

var protokollhorcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->
    if(result.resultCode == Activity.RESULT_OK){
        b_schreib = true
    }
}

}

Gruss Renato

Kommentieren
Beste Antwort
Robbiani Renato
  • Forum-Beiträge: 648

27.10.2024, 11:48:28 via Website

Hallo zusammen

Ich bin mir nicht ganz sicher, aber ich habe es einige Male gelesen, dass ab Android 13 das Schreiben und Lesen keine speziellen Rechte mehr benötigt. Auf jeden Fall prüfe ich auf die Version 13 oder höher und mache in diesem Fall keine Prüfung auf die Rechte. Die App läuft auch so.

Grüss Renato

Hilfreich?
Kommentieren
Robbiani Renato
  • Forum-Beiträge: 648

26.10.2024, 21:56:30 via Website

Irgendwie ist alles mit dem Manifest verbunden.

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

Wer weiss wie es richtig funktioniert?

<?xml version="1.0" encoding="utf-8"?>

xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

<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:requestLegacyExternalStorage="true"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.LustigesRechnen"
    tools:targetApi="31">
    <activity
        android:name=".Protokoll"
        android:exported="false"
        android:theme="@style/Theme.LustigesRechnen" />
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

Gruss Renato

Hilfreich?
Kommentieren
Beste Antwort
Robbiani Renato
  • Forum-Beiträge: 648

27.10.2024, 11:48:28 via Website

Hallo zusammen

Ich bin mir nicht ganz sicher, aber ich habe es einige Male gelesen, dass ab Android 13 das Schreiben und Lesen keine speziellen Rechte mehr benötigt. Auf jeden Fall prüfe ich auf die Version 13 oder höher und mache in diesem Fall keine Prüfung auf die Rechte. Die App läuft auch so.

Grüss Renato

Hilfreich?
Kommentieren