(Solved) Change Adapter from other Class (null errors)

Hello,

I am new to Kotlin, but am enjoying programming with it. But now I run into a problem. I have a fragment (ContactsFragment) which loads data from an URL into a ListView, via a List. This all works fine.

Now I would like to add a new contact, from my activity (AddContactActivity). So I make an https POST request and get a new list of contacts back. So far everything works correct.But now I would like to update the ListView to show the new list. But I can’t get that to work. Not via calling a function from the ContactsFragment class (then I have context problems on creating the new adapter), but also not by creating a local new adapter and assigning that to the list view.

This is my code:

          override fun success(list: List<Contact>, response: Response) {
              val adapter = ContactsAdapter(getApplicationContext(), list)
              contacts_list.adapter = adapter
          }

But I get a null exception error to the contact_list at the moment. How can I update the contact_list (or the adapter) to show the new list?

(I call the Acitivity from a particular button, but that just shows a new layout, whereas the new updated list is only retrieved after a button click on that layout (so I cannot add any parameters to the activity start).

Thanks in advance!

Is it a compiler error or a runtime error?
Can contacts_list be null?

try:

contacts_list?.adapter = adapter

Thanks for your reply. It is a runtime error. It get the error in LogCat when I try to add the contact.

Your code does solve the runtime error, but I do not get the new list presented in my ListView
(sounds reasonable, since contacts_list somehow is null, but I do not understand (yet) how to call the variable (update the adapter) from within the activity)

Can you post the exception you get?
Where contacts_list comes from?

Looks like you are never initializing contacts_list.

edit: you need to findViewById(R.id.contacts_list) or something like that before use it.

Thanks for your answer, but I assumed that was not required (anymore), since I am importing the class as:

import kotlinx.android.synthetic.main.fragment_contacts.*

As per: https://antonioleiva.com/kotlin-android-extensions/

But let me look into the findViewById.

If you are using android extensions plugin it should not be necessary.
Never used it before so I can’t help much. Does it work for other Activities?

Well, this is the first Activity where I am trying to change something from a different Class/Layout. But it does work within the same Class.

update:
Using FindViewById does not solve the problem:

          var tmp_list = findViewById(R.id.contacts_list) as ListView
          tmp_list.adapter = adapter

Since I get an “kotlin.TypeCastException: null cannot be cast to non-null type android.widget.ListView”

Could it be a problem with context or something (just guessing here, since I am pretty new to Kotlin), that it does not exist in the current context or something?

Are you setting the content view of your activity?
This error is saying that findViewById(R.id.contacts_list) returned null.

This is currently my onCreate from the Activity, so yes I set the ContentView

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

  btnAddContact.setOnClickListener(View.OnClickListener {
      RetrieveData()
  })

}

Ps; RetrieveData is now the function for the API call (to keep the code smaller here).

But is that the same xml where the contacts_list is? You said on a previous post that it was on fragment_contacts.xml.
If that is the case you need to findViewById from the view inflated from that xml.

For example:

val view = layoutInflater.inflate(fragment_contacts.xml, ...)
val list = view.findViewById(R.id.contacts_list) as ListView

Slowly we are getting there. I don’t get an error anymore with this new code, but my ListView is also not showing the new information. So I have a feeling that this layoutInflater is creating a new instance of the layout and changing the adapter there. But 2 seconds later the activity is finished and the (new?) view is being destroyed and I am returned back to the previous page, showing the previous ContactList (from the backstack)

Could that be the case? Or do I have to call a refresh on the ListView or something?

You might need to call adapter.notifyDataSetChanged() if you update the adapter items after its creation.

But I am not changing the values on the adapter itself, but rather building a new adapter and switching the adapter on the ListView. So calling an ‘refresh’ on the adapter does not do the trick. I should be calling the ‘refresh’ on the ListView instead. But

list.invalidateViews();

Also does not work, I still do not see the ListView with updates values. So I am still thinking that the layoutInflater creates a new instance from the fragment_contacts and is not loading the one already on the backstack.

Sure the inflater will create a new instance of your view. You should only call it once when creating your fragment.

Okay, thanks for all your help and time. So I have to think of something completely different so solve my problem. I didn’t think it would be this hard to update a ListView with a new list :frowning: (that’s basically all I want to do)

It’s not suppose to be hard. Maybe you should look on how to do what you want in java first.

How would that make it easier? You can do everything Java can do in Kotlin already, so you would gain nothing by switching the language to Java.

Yes, I wanted to do it in Kotlin. And I have found a solution now. I am passing the complete ListView as a parameter to the activity and build a new adapter in the activity and then assign the new adapter to the ListView before calling the finish on the activity. This is working. So I have a solution for now (not the nicest I guess, but well…).

Thanks for all your help and thinking with me here.

It’s easier because there is a lot more tutorials on how to do it in java. Trying to learn both at the same time is harder than focusing in one thing, don’t you agree?