Java-Anfänger: Auf Objekt einer Methode von einer anderen Methode aus zugreifen

Grml

Cadet 3rd Year
Registriert
Feb. 2016
Beiträge
63
Hallo zusammen,
ich mach gerade meine ersten Schritte in Java (Android Studio). Ich hoffe, ich verwende die Begriffe aus der OOP richtig...

Ich habe mir nun eine kleine Anwendung gebastelt mit drei Eingabefeldern. Bei Klick auf einen Button wird eine Methode "A" (public void) aufgerufen, die mit diesen Werten rechnet und sie ausgibt. Funktioniert soweit.

Nun habe ich einen zweiten Button. Der soll eine Methode "B" (public void) aufrufen, mit der ich die Eingabefelder zurücksetzen kann (setText mit einem leeren String).
Aber: Wie kann ich denn aus der Methode "B" direkt auf die Objekte in der Methode "A" zugreifen?
Klar könnte ich mir in der Methode "B" wieder per findViewbyId die Eingabefelder holen. Mein Gefühl sagt mir aber, dass das zu umständlich ist.

Ich habe natürlich schon etwas gesucht, suche aber vermutlich falsch bzw. mit den falschen Begriffen...
 
Der "normale" Weg hierfür sind Felder in der Klasse. Die kannst du dann bspw im Konstruktor oder einer Init-Methode einmalig setzen und dann in jeder anderen Methode nutzen.
 
  • Gefällt mir
Reaktionen: Grml
Danke für Deine Antwort. Ich muss nur leider gestehen ich verstehe sie nicht :-(

Könntest Du mir beim Code auf die Sprünge helfen?

Code:
public class MainActivity extends AppCompatActivity {
[...]
   public void MethodeA(View view) {
       EditText my_edTxt_weight = findViewById(R.id.edTxt_weight);
       EditText my_edTxt_size = findViewById(R.id.edTxt_size);
       EditText my_edTxt_age = findViewById(R.id.edTxt_age);
       [...]
   }

   public void MethodeB(View view) {
      ?????????
   }
}
Das ist (gekürzt) was ich habe. Und auf die drei Objekte in MethodeA will ich zugreifen um sie per .setText() neu zu beschreiben.
 
Zuletzt bearbeitet: (CODE-Tag eingefügt)
Wenn du Code hast, füge ihn bitte in [CODE][/CODE] ein (oder einfach im Editor über die 3 Punkte -> Code).

Ich habe noch nie wirklich mit Java gearbeitet, kann also sein, dass die Syntax nicht ganz stimmt (evtl. braucht man "this." und ich glaube in Java braucht es ein super() call).

C#:
public class MainActivity extends AppCompatActivity {
  private EditText weightEditText;
  private EditText sizeEditText;
  private EditText ageEditText;

  public MainActivity() {
    weightEditText = findViewById(R.id.edTxt_weight);
    sizeEditText = findViewById(R.id.edTxt_size);
    ageEditText = findViewById(R.id.edTxt_age);
  }

  public void MethodeA(View view) {
    // work with weightEditText etc.
  }

  public void MethodeB(View view) {
    // work with weightEditText etc.
  }
}
 
Sorry, für das fehlende CODE-Tag, habe es ergänzt.

Ich habe Deine C-like-Variante ausprobiert, geht so nicht. Dann sind meine Objekte in den Methoden nicht bekannt.
Das "this." habe ich irgendwo schonmal gesehen, kann es aber gerade noch nicht einordnen. Genauso wie das super(). Aber dann suche ich mal in der Richtung weiter...
 
Ersetz mal das "public MainActivity() { [...] }" durch das hier:
Java:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    weightEditText = findViewById(R.id.edTxt_weight);
    sizeEditText = findViewById(R.id.edTxt_size);
    ageEditText = findViewById(R.id.edTxt_age);
}

Das @Override sagt, dass diese Methode schon in der Klasse "AppComparActivity" existiert und überschrieben wird. Das super(savedInstanceState) ruft einfach diese, bereits existierende, Methode auf. Alles was danach kommt kannst du frei selber schreiben und wird automatisch ausgeführt, wenn die Activity erstellt wurde.
 
  • Gefällt mir
Reaktionen: Grml
Zur Erklärung: Der Code von BagBag ist soweit schon korrekt. Beachtet allerdings nicht den Kontext.

In einer Android Activity muss zuerst das Layout mittels "setContentView" zugewiesen worden sein, bevor man über "findViewById" auf die Elemente zugreifen kann. Deswegen kann man die Initialisierung nicht im Konstruktor machen, aber die Android API bietet natürlich entsprechende Möglichkeiten wie oben gezeigt.
 
Danke für Eure Beiträge!

Frazer1 schrieb:
Ersetz mal das "public MainActivity() { [...] }" durch das hier:
Java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
weightEditText = findViewById(R.id.edTxt_weight);
sizeEditText = findViewById(R.id.edTxt_size);
ageEditText = findViewById(R.id.edTxt_age);
}
Das @Override sagt, dass diese Methode schon in der Klasse "AppComparActivity" existiert und überschrieben wird. Das super(savedInstanceState) ruft einfach diese, bereits existierende, Methode auf. Alles was danach kommt kannst du frei selber schreiben und wird automatisch ausgeführt, wenn die Activity erstellt wurde.
Wenn ich die drei "findViewById" in die onCreate-Methode reinpacke kann ich sie später nirgends mehr verwenden. Schon meine MethodeA findet die Objekte dann nicht mehr.

Rossie schrieb:
Zur Erklärung: Der Code von BagBag ist soweit schon korrekt. Beachtet allerdings nicht den Kontext.

In einer Android Activity muss zuerst das Layout mittels "setContentView" zugewiesen worden sein, bevor man über "findViewById" auf die Elemente zugreifen kann.
Das Layout habe ich zugewiesen. Wie gesagt, mein Code oben war der Übersichtlichkeit wegen gekürzt.
Rossie schrieb:
Deswegen kann man die Initialisierung nicht im Konstruktor machen, aber die Android API bietet natürlich entsprechende Möglichkeiten wie oben gezeigt.
Ähhhhh.... Genau :D
Das ist mein Problem. Ich verstehe diesen Satz schon gar nicht. Wenn ich mir bei Wikipedia den Artikel zu Konstruktoren (und Destruktoren) durchlese habe ich danach noch mehr Fragezeichen über dem Kopf.

Um konkreter zu werden (aber halt auch länger ;)): Das ist mein kompletter Quelltext, soll ein einfacher Kalorienrechner sein. Mir ist (glaube ich) in dem Quelltext soweit klar, was wann passiert, aber eben nicht die Eigenheiten der OOP.
Ich wälze jetzt den halben Tag schon Seiten und Tutorials. Aber weiterkommen klappt irgendwie nicht.

Code:
package com.grml.calcounter;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;

import org.w3c.dom.Text;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    public void calculateCalories(View view) {

        // Get Input and define objects
        EditText my_edTxt_weight = findViewById(R.id.edTxt_weight);
        EditText my_edTxt_size = findViewById(R.id.edTxt_size);
        EditText my_edTxt_age = findViewById(R.id.edTxt_age);
        RadioGroup rg_gender = findViewById(R.id.grp_gender);
        RadioButton male = findViewById(R.id.rb_m);
        RadioButton female = findViewById(R.id.rb_f);
        RadioGroup rg_activityLevel = findViewById(R.id.grp_activity);
        RadioButton activityLevel1 = findViewById(R.id.rb_active1);
        RadioButton activityLevel2 = findViewById(R.id.rb_active2);
        RadioButton activityLevel3 = findViewById(R.id.rb_active3);
        RadioButton activityLevel4 = findViewById(R.id.rb_active4);
        RadioButton activityLevel5 = findViewById(R.id.rb_active5);
        RadioGroup rg_deficit = findViewById(R.id.grp_deficit);
        RadioButton deficit15 = findViewById(R.id.rb_deficit15);
        RadioButton deficit20 = findViewById(R.id.rb_deficit20);
        RadioButton deficit25 = findViewById(R.id.rb_deficit25);

        // Gender stuff
        int genderSelectedValueId;
        double genderValue = 0.0;

        genderSelectedValueId = rg_gender.getCheckedRadioButtonId();
        //checking the id of the selected radio button
        if(genderSelectedValueId == male.getId())
        {
            //Log.i("Gender", "male");
            genderValue = 5;
        }
        else if(genderSelectedValueId == female.getId())
        {
            //Log.i("Gender1", "female");
            genderValue = -161;
        }

        // Activity Level stuff
        int activityLevelSelectedValueId;
        double activityLevelValue = 0.0;

        activityLevelSelectedValueId = rg_activityLevel.getCheckedRadioButtonId();
        //checking the id of the selected radio button
        if(activityLevelSelectedValueId == activityLevel1.getId())
        {
            activityLevelValue = 1.1;
        }
        else if(activityLevelSelectedValueId == activityLevel2.getId())
        {
            activityLevelValue = 1.2;
        }
        else if(activityLevelSelectedValueId == activityLevel3.getId())
        {
            activityLevelValue = 1.4;
        }
        else if(activityLevelSelectedValueId == activityLevel4.getId())
        {
            activityLevelValue = 1.7;
        }
        else if(activityLevelSelectedValueId == activityLevel5 .getId())
        {
            activityLevelValue = 2.1;
        }

        // Deficit stuff
        int deficitSelectedValueId;
        int deficitValue = 0;
        deficitSelectedValueId = rg_deficit.getCheckedRadioButtonId();
        //checking the id of the selected radio button
        if(deficitSelectedValueId == deficit15.getId())
        {
            deficitValue = 15;
        }
        else if(deficitSelectedValueId == deficit20.getId())
        {
            deficitValue = 20;
        }
        else if(deficitSelectedValueId == deficit25.getId())
        {
            deficitValue = 25;
        }


        // Calculate

        // Grundumsatz
        double grundumsatz =
                (10 * (Double.parseDouble(String.valueOf(my_edTxt_weight.getText())))) +
                (6.25 * (Integer.parseInt(String.valueOf(my_edTxt_size.getText())))) -
                (5 * (Integer.parseInt(String.valueOf(my_edTxt_age.getText())))) +
                genderValue;

        // Leistungsumsatz
        double leistungsumsatz = grundumsatz * activityLevelValue;
        int leistungsumsatzAbgerundet = (int) leistungsumsatz;

        // Abnahmekalorien
        int deficitTotalNumber = (leistungsumsatzAbgerundet / 100) * deficitValue;
        int abnahmekalorien = leistungsumsatzAbgerundet - deficitTotalNumber;

        // Output
        TextView ausgabe_grundumsatzResult = findViewById(R.id.tv_grundumsatzResult);
        ausgabe_grundumsatzResult.setText(String.valueOf(grundumsatz));

        TextView ausgabe_leistungsumsatzResult = findViewById(R.id.tv_leistungsumsatzResult);
        ausgabe_leistungsumsatzResult.setText(String.valueOf(leistungsumsatzAbgerundet));

        TextView ausgabe_abnehmenKalorienResult = findViewById(R.id.tv_abnehmenKalorienResult);
        ausgabe_abnehmenKalorienResult.setText(String.valueOf(abnahmekalorien));

        //Log.i("Activitylevel", String.valueOf(activitylevel));
    }

    public void resetForm(View view) {

    }

}

Mein Ziel ist eigentlich nur in der (noch leeren) Methode "resetForm()" auf die Objekte in der Methode "calculateCalories()" zugreifen zu können um die editText-Felder bearbeiten zu können. Aber für mich als "Kacknoob" ist selbst das nicht verständlich.

Aber so lange denke ich mir ich lasse das Ganze einfach :-( Vielleicht bin ich einfach zu alt um das zu verstehen. Liegt nicht an Euch, bitte nicht falsch verstehen. Aber auch in Euren beiden Beiträgen, die sicherlich richtig sind(!), ist für mich schon wieder zu viel drin, dass ich (noch) nicht verstehe. Auf der anderen Seite aber nicht weiß wo ich anfangen soll zu suchen um das zu schnallen.
Deshalb kann ich gar nicht wirklich auf Fehlersuche gehen. Weil ich nicht weiß, was ich eigentlich suche.
 
Grml schrieb:
Das ist mein Problem. Ich verstehe diesen Satz schon gar nicht. Wenn ich mir bei Wikipedia den Artikel zu Konstruktoren (und Destruktoren) durchlese habe ich danach noch mehr Fragezeichen über dem Kopf.

Der Code im Konstruktor wird ausgeführt, wenn das Objekt erstellt wird. Zu dem Zeitpunkt ist das Layout aber noch nicht zugewiesen. Bedeutet also, dass für Dein Ziel der Konstruktor keine Rolle spielt und Du die gewünschten Referenzen später erstellen musst. Wie Frazer1 schon schrieb, eignet sich hierfür die "onCreate" Methode, die von Android automatisch aufgerufen wird, wenn die Activity erstellt wird.

Du musst Instanzfelder nutzen, wie von Bagbag gezeigt. Auf lokale Variablen kann nicht von außerhalb einer Methode zugriffen werden. Auf die Instanzfehler kannst Du in allen Instanzmethoden zugreifen.

Am Anfang ist alles verworren, aber das legt sich mit der Zeit. Wichtig ist natürlich, dass man die Sprachgrundlagen versteht. Sichtbarkeit von Variablen z.B. Aber das wird schon. Einfach dranbleiben. Zum Lösen dieses Problems fehlt nur noch ein winziger Schritt.
 
  • Gefällt mir
Reaktionen: Grml
@Grml
Die Daten gehören nicht in einzelne Methoden rein. Sie gehören zu dem Objekt (der Instanz der Klasse) als solches.
Lies dir doch erstmal bei Wikipedia den Abschnitt Klassen durch.
Nimm als Beispiel für eine Klasse ein Auto mit vier Rädern. Es hat dann bspw. noch die Methoden lenken und radwechseln. Beide müssen auf die Räder zugreifen, die als Datum ein Attribut der von Auto sind. Du versuchst, die Räder erst in der Methode lenken lokal anzulegen. Dann hat die Methode radwechseln keinen Zugriff darauf.
Hast du denn eigentlich in prozeduraler Programmierung Kenntnisse? Oder steigst du generell in die Programmierung ein?
 
  • Gefällt mir
Reaktionen: Grml
simpsonsfan schrieb:
Die Daten gehören nicht in einzelne Methoden rein. Sie gehören zu dem Objekt (der Instanz der Klasse) als solches.
Lies dir doch erstmal bei Wikipedia den Abschnitt Klassen durch.
Nimm als Beispiel für eine Klasse ein Auto mit vier Rädern. Es hat dann bspw. noch die Methoden lenken und radwechseln. Beide müssen auf die Räder zugreifen, die als Datum ein Attribut der von Auto sind. Du versuchst, die Räder erst in der Methode lenken lokal anzulegen. Dann hat die Methode radwechseln keinen Zugriff darauf.
Rossie schrieb:
Du musst Instanzfelder nutzen, wie von Bagbag gezeigt. Auf lokale Variablen kann nicht von außerhalb einer Methode zugriffen werden. Auf die Instanzfehler kannst Du in allen Instanzmethoden zugreifen.
Wenn ich Eure beiden Aussagen richtig verstehe, muss ich also meine "Attribute" (die ganzen EditText und RadioButton-findViewById-Geschichten) direkt in der Klasse "MainActivity" schreiben, nicht innerhalb der Methode "calculateCalories", richtig? Und das so, wie es Bagbag oben gezeigt hat.

simpsonsfan schrieb:
Hast du denn eigentlich in prozeduraler Programmierung Kenntnisse? Oder steigst du generell in die Programmierung ein?
Ich habe ein paar Jahre (prozedurale) Geschichten in PHP fürs Web gemacht. Zwar keine großen Dinger, aber soviel, dass "programmieren" als solches für mich nichts gänzlich Neues ist. Es ist bei mir wohl das Verständnis bzw. das völlige Umdenken bei OOP.
In PHP habe ich nie in Klassen, Objekten etc. gedacht (ich weiß, auch PHP kann OOP), sondern einfach "runterprogrammiert". Das rächt sich vermutlich jetzt. Zu lange an dem "alten Zeug" geklebt - und das dabei zu sehr verinnerlicht.

Das OOP-Beispiel mit dem Auto kenne ich auch. Das ist mir in der Theorie auch klar. Und wenn ich dann selber dran sitze und versuche was zu machen (wie mein Beispiel oben) schaffe ich gedanklich die Verbindung zum Auto-Beispiel nicht so wirklich. Dann fängt das rumgeeier an und endet in einem verzweifelten Posting wie hier ;)

Rossie schrieb:
Am Anfang ist alles verworren, aber das legt sich mit der Zeit. Wichtig ist natürlich, dass man die Sprachgrundlagen versteht. Sichtbarkeit von Variablen z.B. Aber das wird schon. Einfach dranbleiben. Zum Lösen dieses Problems fehlt nur noch ein winziger Schritt.
Ich bleibe mal dran - und hoffe, dass ich jetzt weiterkomme. Sonst schlage ich halt doch wieder hier auf.

Ich bin selbst seit 2003 Mitglied und seit ca. 2007 Moderator im größten deutschsprachigen Forum für Musikproduktion. Ich weiß, wie sehr begriffsstutzige Neulinge irgendwann nerven können :D Umso größer ist mein Dank für Eure Hilfe und Geduld!
 
  • Gefällt mir
Reaktionen: simpsonsfan
Ein erster Ansatz (auch wenn so nicht komplett korrekt): Alles was in verschiedenen Methoden verwendet werden soll ist vermutlich gut in der Klasse aufgehoben :).
 
  • Gefällt mir
Reaktionen: simpsonsfan und Grml
Genau, diese Textfelder gehören in dem Fall nicht zur Methode calculateCalories, sondern direkt zur Klasse MainActivity. Man könnte das natürlich alles noch anders strukturieren. Konsequenterweise würde bspw. eine Methode mit dem Namen calculateCalories auch nur die Kalorien berechnen und diesen Wert zurückgeben/ablegen. Und dann würde bspw. eine weitere Methode displayCalories den Wert auf dem Bildschirm anzeigen. Ist in dem Detaillierungsgrad für das Beispiel jetzt übertrieben aber eben so der grundsätzliche Gedankengang.
 
  • Gefällt mir
Reaktionen: Grml
Grml schrieb:
Wenn ich Eure beiden Aussagen richtig verstehe, muss ich also meine "Attribute" (die ganzen EditText und RadioButton-findViewById-Geschichten) direkt in der Klasse "MainActivity" schreiben, nicht innerhalb der Methode "calculateCalories", richtig? Und das so, wie es Bagbag oben gezeigt hat.
Fast. Die Variabeln sollten in der Klasse stehen, also in etwa so:

Code:
public class MainActivity extends AppCompatActivity {
    EditText my_edTxt_weight;
    EditText my_edTxt_size;
    EditText my_edTxt_age;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    [...]
}

Das stellt sicher, dass alle Methoden in deiner Klasse auf diese Variabeln zugreifen können.
Zuweisen, also findViewById, kann man sie hier allerdings noch nicht. Das muss man dann Beispielsweise in der onCreate Methode machen.
 
  • Gefällt mir
Reaktionen: simpsonsfan und Grml
simpsonsfan schrieb:
Methode mit dem Namen calculateCalories auch nur die Kalorien berechnen und diesen Wert zurückgeben/ablegen. Und dann würde bspw. eine weitere Methode displayCalories den Wert auf dem Bildschirm anzeigen. Ist in dem Detaillierungsgrad für das Beispiel jetzt übertrieben aber eben so der grundsätzliche Gedankengang.
Stimmt, eigentlich logisch. Das ist eben mein (ich nenne es mal) "Prozedural-Problem". Ich bin es bislang nicht gewohnt, alles einzeln zu verpacken.
Aber Dein Hinweis ist gut. Das nehme ich mir gleich als nächsten Schritt vor: Das Teil soweit auseinander zu nehmen, dass ich viele Einzelteile habe.

Aber dank Eurer Hilfe läuft es im Moment und ich kann die ersten Felder mit der Methode "resetForm()" löschen. Ich bin schon ganz happy. Jetzt suche ich erstmal, wie ich die RadioButtons wieder un-selektiere. Das dürfte ich selbst hinbekommen, habe nur noch nicht den passenden "Befehl" gefunden.
BTW: Wie nennt man "Befehl" in dem Zusammenhang in der OOP eigentlich? Bspw. ein "meineVariable.setText()". Ist das die Eigenschaft? Oder das Attribut?
 
Grml schrieb:
BTW: Wie nennt man "Befehl" in dem Zusammenhang in der OOP eigentlich? Bspw. ein "meineVariable.setText()". Ist das die Eigenschaft? Oder das Attribut?
Methode ist hier das Stichwort
 
  • Gefällt mir
Reaktionen: Grml
Zurück
Oben