Laden...

Daten in einer Tabelle automatisch updaten

Erstellt von TBMSam vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.037 Views
T
TBMSam Themenstarter:in
9 Beiträge seit 2018
vor 5 Jahren
Daten in einer Tabelle automatisch updaten

Hallo zusammen,

Auf einer Aktivität meiner Xamarin.Android-App wird eine Tabelle bestehend aus mehreren Spalten (mittels eines ListAdapters realisiert) angezeigt. Diese wird OnCreate erstellt und von einer Datenbank Zeile für Zeile gefüllt. Um es sich besser vorstellen zu können, im Detail: Es wird pro Zeile je der Name einer Maschine sowie ihr Online-Status angezeigt. Für die Abfrage des Statuses habe ich eine Funktion, die bei Erreichbarkeit bzw. Verfügbarkeit einen entsprechenden Integer-Wert liefert. Aber diese Funktion wird ja nur einmal für jede Zeile aufgerufen (onCreate). Kann mir jemand eventuell einen Tipp geben, wie ich diese Funktion mehrfach zur Laufzeit aufrufen kann? Also alle 2 Sekunden oder so? Ziel ist am Ende, dass wenn sich der Status einer Maschine ändert, oder diese nicht (mehr) erreichbar ist, sich entsprechend die Statusanzeige in der Tabelle ändert, ohne die Tabelle jedes mal komplett neu aufzubauen oder gar jedes mal eine neue Aktivität zu erstellen.

Ich werde nachfolgend noch etwas Code posten, um das Verstehen vielleicht etwas zu erleichtern:

Activity:


protected override void OnCreate(Bundle bundle)  
{  
    //...  
    var lv = FindViewById<ListView>(Resource.Id.ListView);  
    lv.Adapter = new ListAdapter(this, Resource.Layout.List, list.CurrentList, Constants.ServerIP);  
}  

class ListAdapter : ArrayAdapter


public ListAdapter(Context Context, int ListId, List<Geraet> list, string serverip) : base(Context, ListId, Geraete)  
{   
    this.List = list;   
}

public override View GetView(int position, View convertView, ViewGroup parent)  
{  
    View v = convertView;  
    if (v == null)  
    {  
        LayoutInflater inflater = (LayoutInflater) Context.GetSystemService(Context.LayoutInflaterService);  
        v = inflater.Inflate(Resource.Layout.List, parent, false);  
    }
    v.FindViewById<TextView>(Resource.Id.TextView).Text = List[position].Bezeichnung; 
    if (Get_Status(List[position]) == 1)  
    {  
        v.FindViewById<ImageView>(Resource.Id.ImageView).SetImageResource(Resource.Drawable.green);  
    }  
    if (Get_Status(List[position]) != 1)  
    {  
        v.FindViewById<ImageView>(Resource.Id.ImageView).SetImageResource(Resource.Drawable.red);  
    }
    return v;  
}   

Ich habe auch schon ein paar eigene Versuche unternommen, jedoch waren diese leider nicht von Erfolg gekrönt. Ich werde trotzdem mal die verschiedenen Versuche auch noch posten, vielleicht sieht man ja direkt, woran es gescheitert ist.

1.) using System.Threading:


//(...)
var thread = new Thread(() => MethodToRun(geraet));  
thread.Start();
//(...)
void MethodToRun(Geraet geraet)  
{  
    while (true)  
    {  
        Thread.Sleep(2000);  
        var a = new Activity();  
        a.RunOnUiThread(() => {    
            int status = Get_Status(geraet);  
            if (status == 1)  
            {  
                v.FindViewById<ImageView>(Resource.Id.ImageView).SetImageResource(Resource.Drawable.green);  
            }  
            if (status != 1)  
            {  
                v.FindViewById<ImageView>(Resource.Id.ImageView).SetImageResource(Resource.Drawable.red);  
            }  
        });  
    }  
} 

Erhaltene Fehlermeldung: Java.Lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() (MethodToRun() Zeile 6)

2.) Mit einem Handler:


handler = new Handler(Looper.MainLooper);  
actions = new Runnable(() =>  
{  
    int status = Get_Geraetestatus(Geraetelist[position]);  
  
    handler.Post(() =>  
    {  
        ImageView display = v.FindViewById<ImageView>(Resource.Id.ImageView);    
        led.SetImageResource(status == 1 ? Resource.Drawable.green: Resource.Drawable.red);    
        PostAction();  
    });  
  
});
 
private void PostAction()  
{  
    handler.PostDelayed(() => {  
        new Thread(actions).Start();  
    }, 2000);  
}  

Erhaltene Fehlermeldung: Keine, jedoch wird auch nichts angezeigt. Wenn ich mit dem Debugger durchgehe, sieht es so aus, als geht er gar nicht in den Code nach Runnable actions = new Runnable() rein. Auch werden die Variablen handler sowie actions weder angelegt, noch wird ihnen ein Wert zugewiesen.

3.) ThreadWithState


ThreadWithState tws = new ThreadWithState(Serverip, Geraetelist[position]);  
Thread thread = new Thread(new ThreadStart(tws.ThreadProc));
thread.Start();

public class ThreadWithState
{
   public void ThreadProc()  
   {  
      while (true)  
      {  
        Thread.Sleep(1000);  
        Activity a = new Activity();  
        a.RunOnUiThread(() => { geraetestatus = Get_Geraetestatus(geraet); });  
      }  
   }
}   

Erhaltene Fehlermeldung: Could not convert "System.Threading.ThreadStart" to "Java.Lang.IRunnable" (new Thread()-Parameter Zeile 2) - obwohl das in meiner Anleitung (https://docs.microsoft.com/de-de/dotnet/standard/threading/creating-threads-and-passing-data-at-start-time) der fast gleiche Code ist.

4.) using System.Timers.Timer


startTimer();

public void startTimer()  
{  
    System.Timers.Timer Timer = new System.Timers.Timer();  
    Timer.Start();  
    Timer.Interval = 1000;  
    Timer.Enabled = true;  
    Timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) =>  
    {  
        RunOnUiThread(() =>  
        {  
            lv.Adapter.NotifyDataSetChanged();  
        });  
    };  
    Timer.Start();  
}  

Erhaltene Fehlermeldung: > Fehlermeldung:

"IListAdapter" enthält keine Definition für "NotifyDataSetChanged", und es wurde keine verfügbare NotifyDataSetChanged-Erweiterungsmethode gefunden, die ein erstes Argument vom Typ "IListAdapter" akzeptiert (möglicherweise fehlt eine using-Direktive oder ein Assemblyverweis). (Zeile lv.Adapter.NotifyDataSetChanged();)

Abschließend kurz noch ein paar Gedanken zur Theorie: Ich dachte evtl. an so etwas wie pro Statusanzeige 1 Thread, der in einer Endlosschleife alle Sekunde den Status holt (Stichwort: asynchron?) In der Aktivität dann sowas wie ein Listener, der auf Änderungen await[ed] (sowas wie NotifyStatusChanged(); oder so), bei Änderung dann usw. usw... irgendwie so keine Ahnung, kann auch anderst sein, ich weiß es nicht, bin leider noch ein ziemlicher Anfänger 😦

Würde mich wirklich sehr freuen, wenn sich jemand meiner annehmen und mir helfen / ein paar Tipps geben könnte.

Vielen Dank für alle Antworten schon mal im Voraus

Freundliche Grüße