Overload toString (for use in ArrayAdapter)


#1

What am I doing wrong?

I want to fill a listView with filenames. All works fine with full path, but I’ld prefere just the name.
My extension function doesnt work as ment:

class SelectActivity : AppCompatActivity() {
//...

  override fun onCreate(savedInstanceState: Bundle?) {
     ...
     lv_Files = findViewById(R.id.lv_Files) as ListView
     listDir()
     ...
  }

  val fileList = ArrayList<File>()
  // I'ld like only name, not full path:
  fun File.toString() = this.name   // "is shadowed by member"   <== ????  no effect!

  fun listDir() {
    fileList.clear()
    val files = rootdir.listFiles()
    files.mapTo(fileList) { it }
    val viewedFiles=ArrayAdapter(this,android.R.layout.simple_list_item_1,fileList)
    lv_Files.adapter = viewedFiles
  }
//...
}

(Code simplyfied)


#2

If a class has a member function, and an extension function is defined which has the same receiver type, the same name and is applicable to given arguments, the member always wins.

http://kotlinlang.org/docs/reference/extensions.html#extensions-are-resolved-statically


#3

thx for the answer.

Though it doesn’t solve my problem, so let my ask the other way round:

  • How can I make _ArrayAdapter( _, , ArrayList<File>) use the desired toString function in Kotlin?

Help to ArrayAdapter:
However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.


PS: " … the member always wins. …"
I don’t understand: … so when an extension function could work ever , as overrride is not accepted (here) by compiler.
(saluti a Milano)


#4

Use a custom object

class DecoratedFile(val file: File) {
    override fun toString() = file.name
}

An extension function cannot override or implement any method.


#5

Even if it worked, it would be a bad solution, because it could have changed a lot of other code, you do not want to be changed. I think that the most correct way to address the problem is to implement custom adapter (which is not very complicated), but wrapper object with custom toString() also suitable solution.


#6

@fvasco
Switching to DecoratedFile makes issues on “val files = f.listFiles()” and “files.mapTo(fileList) { it }”

@darksnake
Sorry, your answer is to general or to high for me. If it were “not very complicated” I would have tryed it.
For me it IS to complicated.

Maybe I’m just a weak programmer. I’m almost resigning.


#7

Well, as a workaround you could try something like this:

class DecoratedFile(name: String): File(name) {
override fun toString() = this.name }

Alternatively you could, instead of using mapTo, use a for loop.


#8

@andrejpetelin
THX, that worked fine.

I just have to learn, what this means: class DecoratedFile(name: String): File(name)
(It works without understanding.)

… and some calls, (like mapTo) had to be changed quite strange:

  • files.mapTo(fileList) { DecoratedFile(it.absolutePath) }

But for now I’m “crafting” a running version for further tests.
Later on I’ll learn more.


#9
class DecoratedFile(name: String): File(name)

means that class DecoratedFile with a constructor that takes a parameter name of type string inherits from class File, passing along the string name to its constructor. Think extends if familiar with Java.


#10

I’m quite familiar with Java. (At least I thought! :roll_eyes:)

I’ve made about 10 (real used) applications so far. and all are working fine.
Nevertheless I’m not that firm to know all constructions really good.
I knew “extends”, but did not happen to use it really. (Vintage programm style? :thinking: )

There’s a lot to learn.


#11

When you add a new activity to your Android project you get a new Java class like this:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // code
    }
}

This literally means that publicly accessible class MainActivity that inherits from the class AppCompatActivity (as in it contains the entirety of AppCompatActivity) contains a function onCreate but no constructors, so it inherits AppCompatActivity’s constructor. A constructor is, simply put, a special function in Java, C++ and some other languages, that gets executed when you create an instance of an object. Its purpose is to establish the initial state of the class.

Kotlin allows you to write things like this more concisely.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // code
    }
}

A very nice, approachable, concise and to the point Kotlin explanation can be found in the Kotlin documentation on classes at this link.


#12

Indeed, there is no need. A custom adapter would be much better (and why not go with recyclerview in the meantime) as it also allows for more complex views and was intended for this purpose. As an alternative, have the arraylist just contain the string values (but then you don’t have your file object internally).


#13

You are right. I learned ArrayAdapter now, which give me a lot of posibilities (complex view) now.
(But was quite hard to find out.)

Though I used decoration too, to mark some files spezificly.

All hints were very useful to me! and pushed me a bunch further.
Thx

closed to me