Forum Xamarin.Android
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

My ListView is not populating anymore, what's wrong with it?

ActLightActLight USMember ✭✭

I'm trying to populate a listview with data from the server, i have a functionin example of it which was working in this same app, but now was forced to update and the thing pretty much broke showing this error:

{Android.Util.AndroidRuntimeException: Only the original thread that created a view hierarchy can touch its views.
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <3fd174ff54b146228c505f23cf75ce71>:0
at Java.Interop.JniEnvironment+InstanceMethods.CallVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00069] in :0
at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualVoidMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0002a] in :0
at Android.Widget.ListView.set_Adapter (Android.Widget.IListAdapter value) [0x00036] in <9ab9faae1b4b4f0da28e7c4ac61e2c78>:0
at Notificaciones_Movil.MainActivity+d__15.MoveNext () [0x001ef] in C:\Users\Sincron\Documents\Visual Studio 2015\Projects\Notificaciones-Movil\Notificaciones-Movil\MainActivity.cs:213
--- End of managed Android.Util.AndroidRuntimeException stack trace ---
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4056)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:709)
at android.view.View.requestLayout(View.java:12833)
at android.view.View.requestLayout(View.java:12833)
at android.view.View.requestLayout(View.java:12833)
at android.view.View.requestLayout(View.java:12833)
at android.view.View.requestLayout(View.java:12833)
at android.widget.AbsListView.requestLayout(AbsListView.java:1697)
at android.widget.ListView.setAdapter(ListView.java:488)
at dalvik.system.NativeStart.run(Native Method)
}

The code is this one:

The function than populate the listview, (the one present in the activity):

        public async Task PopulateListView()
        {
            //Here is Reading Data
            try
            {
                list = await "http://186.67.204.54:2472/NotificacionesPruebas/Receiver.aspx".GetRequest<List<ItemAbstract>>(loginLogan.Nombre_Login, loginLogan.PasswordLogin, "17ba0791499db908433b80f37c5fbc89b870084b");

                mItems.Clear();
                mItems.Add(new ItemAbstract { ID = 0, Nombre = "Ninguno", Cheked = false, ID2 = 0 });

                if (default(List<ItemAbstract>) != list)
                {
                    loginSuccessfull = true;
                    foreach (var user in list)
                    {
                        mItems.Add(user);
                    }
                }

                // ListView Parts of Code II
                MyListViewAdapter adapter = new MyListViewAdapter(this, mItems);
                result.Adapter = adapter;
                //RunOnUiThread(() => result.Adapter = adapter);

                //Toast.MakeText(this, "Data Cargada Satisfactoriamente", ToastLength.Short).Show();
            }
            catch (Exception ex)
            {
                RunOnUiThread(() => Toast.MakeText(this, "No se pudo cargar la data: " + ex.ToString(), ToastLength.Short).Show());
            }
            //END Reading Data
        }

when i run the result.Adapter = adapter; line is when it breaks, please notice than the RunOnUiThread i already try it, and, even when not return any error, it doesn't populate the listview either.

Here is the adapter code:

using System.Collections.Generic;
using Android.Content;
using Android.Views;
using Android.Widget;
using Notificaciones_Movil.DataObject;

namespace Notificaciones_Movil
{
    class MyListViewAdapter : BaseAdapter<ItemAbstract>
    {
        private List<ItemAbstract> mItems;
        private Context mContext;

        public MyListViewAdapter(Context context, List<ItemAbstract> items)
        {
            mItems = items;
            mContext = context;
        }

        public override int Count
        {
            get
            {
                return mItems.Count;
            }
        }

        public override long GetItemId(int position)
        {
            return position;
        }

        public override ItemAbstract this[int position]
        {
            get
            {
                return mItems[position];
            }
        }

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View row = convertView;

            if (row == null)
            {
                row = LayoutInflater.From(mContext).Inflate(Resource.Layout.listview_row, null, false);
            }

            //TextView txtName = row.FindViewById<TextView>(Resource.Id.txtName);
            TextView txtDeparment = row.FindViewById<TextView>(Resource.Id.txtDepartment);

            //txtName.Text = mItems[position].ID.ToString();
            txtDeparment.Text = mItems[position].Nombre;

            return row;
        }

    }
}

Here is the adapter axml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="25px"
    android:minHeight="25px">
<!--<TextView
        android:text="Name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/txtName" />-->
    <TextView
        android:text="Department"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/txtDepartment" />
</LinearLayout>

Here are the functions (in the same activity) who actualy contains the function to populate the listView, being the last one called PopulateListView()

protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView (Resource.Layout.Main);

            // Get our button  from the Layout resource,
            // and attach an event to it
            Button buttonLogIn = FindViewById<Button>(Resource.Id.buttonLogIn);
            Button buttonDeleteLogIn = FindViewById<Button>(Resource.Id.buttonDeleteLogIn);

            txtLogIn = FindViewById<EditText>(Resource.Id.txtLogIn);
            txtPswdLgIn = FindViewById<EditText>(Resource.Id.txtPassword);

            // ListView Parts of Code
            result = FindViewById<ListView>(Resource.Id.mylistView);
            result.ItemClick += Result_ItemClick;

            buttonLogIn.Click += ButtonLogIn_Click;
            buttonDeleteLogIn.Click += ButtonDeleteLogIn_Click;

             loginLogan = new ItemLogin();

            if (JSONDesdeArchivo(out loginLogan))
            {
                txtLogIn.Visibility = Android.Views.ViewStates.Gone;
                txtPswdLgIn.Visibility = Android.Views.ViewStates.Gone;
                PopulateListView();
            }
        }

. . .

private async void ButtonLogIn_Click(object sender, System.EventArgs e)
        {
            //Here is preparing connection to send data
            FormUrlEncodedContent DicformContent;
            HttpClient client = new HttpClient();

            //Preparing to send the data
            if (JSONDesdeArchivo(out loginLogan))
            {
                DicformContent = new FormUrlEncodedContent(new[] {
                    new KeyValuePair<string, string>("ID", loginLogan.Nombre_Login),
                    new KeyValuePair<string, string>("PSWRD", loginLogan.PasswordLogin),
                    new KeyValuePair<string, string>("OperationType", activityName) //11
                });
            }
            else
            {
                DicformContent = new FormUrlEncodedContent(new[] {
                    new KeyValuePair<string, string>("ID", txtLogIn.Text),
                    new KeyValuePair<string, string>("PSWRD", txtPswdLgIn.Text),
                    new KeyValuePair<string, string>("OperationType", activityName) //11
                });
            }

            HttpResponseMessage response = await client.PostAsync(uri.ToString(), DicformContent).ConfigureAwait(false);

            //Reading data
            //var response = await client.GetAsync(url); //This is to just get the data, it doesn't send anything before get it, like PostAsync does instead.
            var json = await response.Content.ReadAsStringAsync();
            string Result = string.Empty;
            json = json.Replace("\r\n", "");
            if (!string.IsNullOrWhiteSpace(json) && json == "validLogin")
            {
                loginLogan = new ItemLogin();
                loginLogan.Nombre_Login = txtLogIn.Text.ToString();
                loginLogan.PasswordLogin = txtPswdLgIn.Text.ToString();
                if (JSONHaciaArchivo(loginLogan))
                {
                    Result = "Login data almacenada exitosamente";
                }
                else
                {
                    Result = "Ha ocurrido un problema al grabar sus credenciales, por favor contacte a soporte";
                }
            }
            else
            {
                Result = "Ha fallado en el login, por favor intente nuevamente, si el problema persiste consulte con el administrador del servicio";
            }

            RunOnUiThread(() => Toast.MakeText(this, Result, ToastLength.Long).Show());

            await PopulateListView();
        }

Comments, questions, request for clarification or anything than helps to actualy obtain the answer would be much apreciated too,

thanks in advance.

Sign In or Register to comment.