3

I've written a kotlin class with an overridden fun and a fun to update a var into the class scope (I'm tragically new to Kotlin!)

class mySampleClass: sampleReference(){
    var varToBeUpdated:String = "my string" //var in class scope to be updated

    fun updateMyVar(gotString:String){

        //I tried this, it didn't work
        this.varToBeUpdated = gotString
        // also this didn't work
        varToBeUpdated = gotString

    }

    override fun sample(context: Context, intent: Intent){
        //here i need my varToBeUpdated with new string
        runSomeThing(varToBeUpdated)
        //some work to be done here
    }
}

In the place where I call the methods i do:

myObject.updateMyVar("new string")
myObject.sample()

I wonder how I can update the var i need, since I cannot add new args in the "fun sample", due to the fact it's overriding a class method

Thanks in advance, best regards to everyone :)



UPDATE: add my actual code, due to the fact that the class it seems unable to keep on the right updated value as i call the overrid method:

Here is my BroadcastReceiver, to check whem download is completed and them perform some action

class DownloadBroadcastManager: BroadcastReceiver() {

    var myClassFilename:String = "default"
    var myClassExtension:String = ".default"

    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action

        if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {
            //Show a notification
            // here there's a log to check if var are updated
            println("myTag - variables $myClassFilename, $myClassExtension")

            Toast.makeText(context, "Download of $myClassFilename$myClassExtension completed", Toast.LENGTH_LONG).show()
            // richiama azioni come player o display image o altro?

            //player
            var uri = Uri.parse (Environment.getExternalStorageDirectory().getPath() + "/Download/$myClassFilename$myClassExtension") //myClassExtension is ".mp3", dot is included, however it seems class is re-intialized as i call the method
            println("myTag - uri: $uri")
            println("myTag - context: $context")

            var mPlayer = MediaPlayer() // I added this declaration (that's be re-done later) cause I had a problem in making the player running (of course giving it a valid path to a valid file). Now this is "junk code"
            mPlayer.stop()
            mPlayer.reset()
            mPlayer.release()
            mPlayer = MediaPlayer.create(context, uri) // here there's the proper declaration + initialization
            mPlayer.start()

        }
    }
}

Here is the part from my DownloaderClass...

var brReceiver = DownloadBroadcastManager()
    // shows when download is completed
    println("myTag - ${brReceiver.myClassFilename}, ${brReceiver.myClassExtension}: originals") //here shows the default: it's right
    val intent = Intent(context, MainActivity::class.java)
    brReceiver.myClassFilename = myTitle // inject filename
    brReceiver.myClassExtension = ".mp3" // inject file extension
    println("myTag - ${brReceiver.myClassFilename}, ${brReceiver.myClassExtension}: modified") // here it shows my class property as correctly updated

    brReceiver.onReceive(context, intent) // here, as calling the override fun, it get back to default value of the property
Zoe
  • 27,060
  • 21
  • 118
  • 148
Michele Rava
  • 184
  • 4
  • 17
  • If you make `varToBeUpdated` public you might access it using `myObject.varToBeUpdated=“my string”` – 113408 Feb 16 '19 at 13:47
  • maybe my issue now is that i didn't declared it public? Hmm: nothing to do. Something declare my var again as i call the method or simply something is preventing me to update them – Michele Rava Feb 16 '19 at 20:45
  • `var mPlayer = MediaPlayer() // I added this declaration (that's be re-done later) cause I had a problem in making the player running (of course giving it a valid path to a valid file). Now this is "junk code"` you should probably remove that. – EpicPandaForce Feb 17 '19 at 14:36
  • If you call `brReceiver.onReceive(...)` the values in `DownloadBroadcastManager` are updated. But you shouldn't do that. The Android framework calls it for you. And when it happens new instance of `DownloadBroadcastManager` class is created and default values are set. We use Intents to pass data to BroadcastReceiver, e.g. call `intent.putExtra("filename", "yourFileName")` when you create BroadcastReceiver, and call `intent.getStringExtra("filename")` in your `onReceive()` function. https://stackoverflow.com/questions/10032480/how-to-pass-data-to-broadcastreceiver – Sergio Feb 17 '19 at 14:47
  • Really thanks a lot! – Michele Rava Feb 17 '19 at 14:56
  • Ok, I had chances to check it again. I deleted the call I made to the method, since it's indeed run by framework itself as you said... But it's still recreating the object and... It loses the intent with extras! When it runs first it gets the intent, in second automatic call it reinitializes the object and I dunno how to keep or sending again the intent with extras... It's an Odissey, I'm sorry I'm a perfect noob – Michele Rava Feb 18 '19 at 14:15

3 Answers3

1

Accoirding to kotlin's docs you can define getter and setter methods for any variable like this way:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]

in your case it's might be something like:

var varToBeUpdated:String = "my string"
    get() = field
    set(value) { field = value }
SamiAzar
  • 1,260
  • 13
  • 29
1

You can just do the following:

  1. Get rid of updateMyVar function:

    class MySampleClass: SampleReference(){
        var varToBeUpdated:String = "my string" //var in class scope to be updated
    
        override fun sample(context: Context, intent: Intent){
            //here i need my varToBeUpdated with new string
            runSomeThing(varToBeUpdated)
            //some work to be done here
        }
    }
    
  2. Update varToBeUpdated property directly:

    val myObject = MySampleClass()
    myObject.varToBeUpdated = "new string"
    myObject.sample()
    

Update: If you call brReceiver.onReceive(...) the values in DownloadBroadcastManager are updated. But you shouldn't do that. The Android framework calls it for you. And when it happens new instance of DownloadBroadcastManager class is created and default values are set. We use Intents to pass data to BroadcastReceiver, e.g. call intent.putExtra("filename", "yourFileName") when you create BroadcastReceiver, and call intent.getStringExtra("filename") in onReceive() function to get the value. Here is how to pass/get data to/from BroadcastReceiver

Sergio
  • 27,326
  • 8
  • 128
  • 149
  • I think this solution violates the encapsulation principle. – SamiAzar Feb 16 '19 at 14:02
  • No it doesn't. Kotlin has concept of properties https://kotlinlang.org/docs/reference/properties.html. To use a property, we simply refer to it by name. `varToBeUpdated` is a property. The getter and setter are optional. – Sergio Feb 16 '19 at 14:54
  • I could work at pc only now.. it seems something prevent this from workin. Can the object can be re-initializated and i cannot notice it? – Michele Rava Feb 16 '19 at 20:45
  • You can check in Android Studio where the value is updated by right clicking on the property -> Find Usage -> at the bottom window look for `Value write` drop down list. When you click it you'll get all places where the property is updated. – Sergio Feb 16 '19 at 20:51
  • Ok, I tried to find usage and also to send some output to console with println() My result is that in MainActivity the update is confirmed: println(myObject.varToBeUpdated) //resutl here is the default one myObject.varToBeUpdated = "new string" // new value injection println(myObject.varToBeUpdated) // result in console here is the new one! myObject.sample() // here it works again with the default value... What's going on here? Thanks in advance, best regards brReceiver.onReceive(context, intent) – Michele Rava Feb 16 '19 at 23:52
  • In find usage -> Value write it shows no more updates after my last one (whic is the correct one). I really dunno why it keeps on the default as I call the class method – Michele Rava Feb 16 '19 at 23:54
  • I made another test: I created a new method, simply returning the var that should be updated... and it works? Can it be an issue related to the overriding process??? – Michele Rava Feb 17 '19 at 00:45
  • When I put log at the beginning of the `sample()` method I see updated value '"new string"'. Maybe you use the reference to the `MySampleClass` which is not updated. It's hard to say without seeing your code. If you update your question with the full code, logs, comments We will find the reason. – Sergio Feb 17 '19 at 06:53
0

Ok, at first thank to M.SamiAzar and especially to Sergey, for their answers and for the unbelievable patience! Unluckily it seems that, as it is re-initialized by the framework, the BroadcastReceiver also loses any extras that i previously put in the Intent variable. I finally solved this issue, letting me to retrieve the strings I needed, only writing a line of text into a file in the internal storage and retrieving it in my BroadcastReceiver class. Here's the code:

this is my "onReceive" methond in BroadcastReceiver class

 override fun onReceive(context: Context, intent: Intent) {
    val action = intent.action
    Log.i("Receiver", "myTag - Broadcast received: " + action)
    var myFilename = "deafult"

    if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {

        // read the previously created file from internal storage
        var fileInputStream: FileInputStream? = null
        fileInputStream = context.openFileInput("storeDownloadedData")
        var inputStreamReader: InputStreamReader = InputStreamReader(fileInputStream)
        val bufferedReader: BufferedReader = BufferedReader(inputStreamReader)

        // here setting string var and stringbuilder var to catch the text updated outside the while loop
        val stringBuilder: StringBuilder = StringBuilder()
        var text: String? = null
        var sumText:java.lang.StringBuilder? = null
        // while loop for reading the file line by line (in this case the file can contains just one line a time)
        while ({ text = bufferedReader.readLine(); text }() != null) {
            sumText = stringBuilder.append(text)
        }

        // convert stringBuilder to a list of string splitting the original string obtained by file reading
        var secondText:String = "default"
        println("myTag - text: $text, $sumText")
        if (sumText != null){
            secondText = sumText.toString()
            var listFromText = secondText.split(",")
            // set filename to the title contained in the string
            myFilename = listFromText[0]
        }

        //player - finally play the file retrieving the title from the file in internal storage
        var uri = Uri.parse (Environment.getExternalStorageDirectory().getPath() + "/Download/$myFilename.mp3")
        println("myTag - uri: $uri")
        println("myTag - context: $context")

        var mPlayer = MediaPlayer.create(context, uri)
        mPlayer.start()

    }

this is the code added in my DownloadManager class:

// strore into an internal storage file the data of title and extensione for the file's gonna be downloaded
    val myStoredFile:String = "storeDownloadedData"
    val data:String = "$myTitle,.mp3"
    val fileOutputStream: FileOutputStream
    // write file in internal storage
    try {
        fileOutputStream = context.openFileOutput(myStoredFile, Context.MODE_PRIVATE)
        fileOutputStream.write(data.toByteArray())
    }catch (e: Exception){
        e.printStackTrace()
    }

    // it notifies when download is completed
    val intent = Intent(context, MainActivity::class.java)
    var brReceiver = DownloadBroadcastManager()

I do not know if this is "ortodox", but it seems to work atm :)

Michele Rava
  • 184
  • 4
  • 17