Home-Automation-App

  • 43 Antworten
  • Neuester Beitrag
Diskutiere Home-Automation-App im Tipps und Anleitungen zur Code-Entwicklung im Bereich Android App Entwicklung.
BulliM

BulliM

Neues Mitglied
Nur zur Info: Ich bin noch dran und habe tatsächlich nun mein Ziel erreicht und eine kleine App für mich programmiert. Mit der kann ich mir diverse Infos auf das Handy liefern lassen. Auch Notifications sind möglich. Ich erweitere die App jetzt um ein Widget, so dass ich verschiedene Infos immer sofort im Blick habe.
 
BulliM

BulliM

Neues Mitglied
Momentan hänge ich an einer Stelle. Ich habe nun ein Widget erstellt. Das Widget wird beim Laden der App aktualisiert. Nun möchte ich das Widget auch beim Click auf das Widget aktualisieren. Auch das funktioniert - allerdings ohne Update über eine URL, wie in dem Thread der MainActivity.java.

In der Klasse des Widgets habe ich in der Methode onUpdate einen remoteViews.setOnClickPendingIntent angelegt, der die Methode onReceive auch anspricht. Folgender intent wird bei einem Click auf einen Button im Widget ausgeführt:

Code:
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);

if(intent.getAction().toString() == "update"){
    String message = "Neuer Text";
    remoteViews.setTextViewText(R.id.textView, message);
    updateWidget(context, remoteViews);
}
      
super.onReceive(context, intent);
Oben das funktioniert. Nun möchte ich den Text (message) natürlich auch dynamisch wie im Thread in der MainActivity.class über eine URL abfragen. Wie mache ich das elegant? Kann ich den Thread irgendwie in eine Methode "verpacken", die ich auch von der Klasse des Widgets aus ansprechen kann?
 
Zuletzt bearbeitet:
swa00

swa00

Moderator
Teammitglied
Hallo @BulliM ,

ich musste leider jetzt ein paar mal deinen Betrag lesen , bevor ich ihn wirklich verstanden habe :)


Was spricht denn dagegen :

a) Entweder deinen Request direkt im Provider auszuführen .
b) eine eigene Requestklasse mit Callbacks zu erstellen und Diese als neue Instanz im "OnUpdate" zu benutzen ?
 
Zuletzt bearbeitet:
BulliM

BulliM

Neues Mitglied
Gegen a) spricht, dass ich die URL-Abfrage auch noch in anderen Funktionen nutzen will. Also spricht mich eher Version b) an. Habe das aber noch nicht gemacht. Ein einfaches Beispiel dazu wäre hilfreich. 🙂
 
Zuletzt bearbeitet:
BulliM

BulliM

Neues Mitglied
Ich habe den Aufruf der URL nun im Receiver platziert und das funktioniert. Ist allerdings etwas unübersichtlich. Zu den Callbacks und dem Listener werde ich dann morgen früh nach Tutorials schauen. Hab die Nacht durchgearbeitet und gönne mir jetzt eine Pause. Danke euch für die Hilfe!
 
BulliM

BulliM

Neues Mitglied
Update. Ich habe den Thread jetzt in eine neue Klasse ausgelagert.

Code:
public class ThreadRunner implements Runnable  {

    String message;

    public void run() {

        HttpURLConnection httpURLConnection = null;
        try {
            ...
            message = convertStreamToString(inputStream);
        }
    }

    public String getString() {
        return message;
    }

    public static String convertStreamToString(InputStream inputStream) {
        ...
    }
}
Dann im Receiver:

Code:
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);

if(intent.getAction().toString() == "update") {

    ThreadRunner threadRunner = new ThreadRunner();

    try {
        Thread thread = new Thread(threadRunner);
        thread.start();

        while (thread.getState()!=Thread.State.TERMINATED) {
            //System.out.println("Thread thread has not finished");
        } if (thread.getState()==Thread.State.TERMINATED) {
            String message = threadRunner.getString();
            remoteViews.setTextViewText(R.id.textView,  message);
            updateWidget(context, remoteViews);
        }
    } catch (Exception e) {
        System.out.println("Error Thread thread: " + e.getMessage());
    }

}

super.onReceive(context, intent);
Ist das eine elegante Lösung oder geht das noch besser? Das Updaten des Widgets in der Klasse ThreadRunner ist wohl nicht möglich oder sinnvoll? Meine Sorge: Die While-Schleife frisst möglicherweise Ressourcen, wenn der Thread nicht schnell terminiert werden kann.
 
Zuletzt bearbeitet:
J

jogimuc

Stammgast
Hallo das mit der while Schleife die wartet bis der Thread beendet ist.,finde ich nicht gut. Das könnte sogar den System blockieren denn die Schleife läuft ja in UI.

Dafür gibst es Handler und Listener.
Das was du machst ist kein asyncone Händling.
Beitrag automatisch zusammengefügt:

Tipp benutze Volley das arbeitet asyncon und das Ergebnis kommt in einem listener callback im UI an.
Android - HandlerThreads and communication between Threads | android Tutorial

Multi-Threaded Android: Handler, Thread, Looper, and Message Queue
 
Zuletzt bearbeitet:
J

jogimuc

Stammgast
Hallo da du ja sehr an dem Http Protokoll festhält.
Hier ein Beispiel Projekt mit Volley und HttpUrlConnection und Callback Listener.

Wie schon gesagt wurde ist für dein Vorhaben das MQTT Protokoll besser geeignet als Http.
 

Anhänge

  • Http_Listnener.zip
    142 KB Aufrufe: 1
BulliM

BulliM

Neues Mitglied
Danke, sehe ich mir an. Ich brauche solche Beispiele. Mir ist Java noch nicht vertraut. Viele Abläufe begreife ich einfach nicht. Asynchron ist auch tricky. So ähnlich ging es mir aber auch mit z.B. Actionscript 3. Irgendwann konnte ich das wie im Schlaf.
 
Zuletzt bearbeitet:
J

jogimuc

Stammgast
AS3 ist auch OOP und Eventgesteuert auch Asynchron, Threads ist da ein Thema.
Auch Listener Callbacks gibt es da.....
Wenn du AS3 im Schlaf beherrschst sollte du es eigentlich selber können.
 
Zuletzt bearbeitet:
BulliM

BulliM

Neues Mitglied
Ich sage ja nicht, dass ich es gar nicht kann. Vele kommt mir vertraut vor. Aber Java ist eine Fremdsprache. Und mir sind die Klassen und Methoden einfach nicht vertraut. Android Studio hilft sehr, aber noch hat es nicht Klick gemacht. Meine App hat bisher nur wenige Funktionen.

Ich greife übrigens auf ein API zu, dass nur https per get abfragen lässt. Darum bleibt es bei dem Protokoll.
 
Zuletzt bearbeitet:
BulliM

BulliM

Neues Mitglied
jogimuc schrieb:
Ich nutze jetzt Volley. Habe die Klassen entsprechend angepasst. Funktioniert prima. Mir ist aufgefallen, dass das Aktualisieren nicht sofort passiert. Klicke ich mehrfach zum Aktualisieren, werden die Klicks alle noch abgearbeitet. Da hängt also nichts mehr, falls eine Abfrage nicht unmittelbar ausgeführt werden kann.

Im Gegensatz zu einem loadDataHttp() sieht die loadDataVolley() sehr aufgeräumt aus:
Code:
public void loadDataVolley() {
    String url = "https://api.domain.tlv?var1="+ v1 + "&var2=" + v2;
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, response -> listener.getResponse(response, v1, v2), error -> listener.getErrors("Error: " + error));
    Volley.newRequestQueue(context).add(jsonObjectRequest);
}
Danke dir sehr, dass du mich auf Volley aufmerksam gemacht hast. Hab auch nur Gutes darüber gelesen. 🙂
 
J

jogimuc

Stammgast
OK

Ich habe deine ersten Pst auch gesehen. Ich hoffe du weißt jetzt das du ein Json Objekt von Volley bekommst. Was du ja auch richtig weitergegeben hast.
Aber du wolltest ein Json Objekt mit „JSONObject getJSONObject (String name)“ Parsen, was nicht geht denn du hast ja keinen String.
https://developer.android.com/reference/org/json/JSONObject

Und was ist in deinen Json „name“ ? Ein Child Objekt.

Mir ist aufgefallen, dass das Aktualisieren nicht sofort passiert
Das ist normal es muss ja auch erst aus dem Netz geladen werden. Asynchron.
Dein HttpUrl… macht das gleiche. Deshalb der Listener.
 
Zuletzt bearbeitet:
BulliM

BulliM

Neues Mitglied
jogimuc schrieb:
OK

Ich habe deine ersten Pst auch gesehen. Ich hoffe du weißt jetzt das du ein Json Objekt von Volley bekommst. Was du ja auch richtig weitergegeben hast.
Aber du wolltest ein Json Objekt mit „JSONObject getJSONObject (String name)“ Parsen, was nicht geht denn du hast ja keinen String.
https://developer.android.com/reference/org/json/JSONObject

Und was ist in deinen Json „name“ ? Ein Child Objekt.
"name" wäre ein Objekt. Der Fehler lag aber an was Anderem. Ich hatte try {...} } catch (JSONException e) {...} in der Responsemethode vergessen. Daher der Fehler. Bin da einfach noch nicht drin. Ich dachte, es läge am Interface.

In der try war dann parsen sehr wohl möglich. War also eigentlich alles richtig, fehlte halt nur der catch für die Exception.
 
Zuletzt bearbeitet:
J

jogimuc

Stammgast
Es ist ja schon ein Json Objekt kannst du gleich verwenden sonnst könnste du es auch als String aus den Netz laden.
dann brauchst du das Parsen.
 
BulliM

BulliM

Neues Mitglied
Das sind dann die Feinheiten. Ich muss noch schauen, wie ich in Java an die Inhalte eines JSONObject komme. Das ist mir von PHP vertraut. Da ginge es z. B. so: $json->name[0]->alter;

Da habe ich die Syntax noch nicht raus. Kommt aber. Muss nur darüber lesen.
 
BulliM

BulliM

Neues Mitglied
Ein weiteres Problem. Ich habe bemerkt, dass - bei mehreren Widgets - alle angelegten Widgets auf Updates reagieren. Bei einem Klick auf ein Widget, soll eben nur dieses updaten. Bei Actionscript konnte ich der Instanz bei der Instanziierung eine ID geben und über diese dann später auch alle Children ansprechen. Ein widget_1 = new Widget(); findet hier aber nicht statt, das passiert automatisch, eben per drag&drop über das GUI.

Ich kann dann später nur auf die Intents zugreifen. Das nützt mir aber wenig, weil ich dann am Ende immer doch die ID des Widgets brauche. Und ich muss wissen, wie ich darüber die Children anspreche.

In der Methode onReceive werden jeweils alle Childobjekte der Instanzen angesprochen, die den Namen R.id.TextView haben. Die über context. getRessources() gelieferte Ressourceid dür Children ist offenbar in allen Widgets gleich.

Wie komme ich an die appWidgetId ebender Instanz, in welcher der Button angeklickt wurde und wie spreche ich damit in der onReceive explizit (nur) die Children dieser Instanz an? Ich suche jetzt viele Stunden und mir dreht sich alles. Wo ist das Objekt und wie identifiziere ich es?
 
Zuletzt bearbeitet:
J

jogimuc

Stammgast
@BulliM
Wie hast du denn das Layout erstellt?
Eine doppelte ID sollte und dürfte es nicht geben. Das müsste der Resoursen Compiler im XML bemängeln.
Du musst schon selber dafür sorgen das es keine doppelten IDs gibt im XML.

Zeige mal das XML vom Layout.
 
Zuletzt bearbeitet:
BulliM

BulliM

Neues Mitglied
jogimuc schrieb:
Du musst schon selber dafür sorgen das es keine doppelten IDs gibt im XML.
Kann man dort eine dynamische @+id vergeben? Wie?

EDIT: Jetzt, wo ich danach suche, finde ich heraus, dass man Layouts sehr wohl auch dynamisch erstellen kann. Wusste ich nicht. Ich probiere das mal aus.
 
Zuletzt bearbeitet:
Ähnliche Themen - Home-Automation-App Antworten Datum
1