Wie kann ich aus der MainActivity eine Methode in einer anderen Klasse aufrufen? [GELÖST]

Bergmann2016

Bergmann2016

Neues Mitglied
4
Einen angenehmen Nachmittag wünsche ich Euch,

meine Frage ist gewiss eine simple Anfängerfrage, aber alles was ich im Inet fand bezog sich auf Variablen oder ähnliches übergeben.

Ich möchte jedoch nur das die MainActivity aus einer anderen Klasse eine Methode aufruft.

Zur Erläuterung:
Ich habe angefangen eine neue App zu schreiben. Beim Start der App werden SharedPreference-Einträge überprüft und ausgewertet. Ursprünglich lag das ganze Zeug in der MainActivity, aber um es 1. übersichtlicher zu haben und 2. um es auch wiederverwertbar zu machen habe ich es nun in eine eigene Klasse ausgelagert und dieser Klasse einem eigenen Package gegeben.

Jetzt will die MainActivity aber das ich in meiner neuen Klasse Methoden und Werte statisch mache, was nicht geht. Denn die Werte variieren.

Ich hatte versucht ein Interface zu verwenden, aber ich fand merkwürdiger Weise nirgends eine Erklärung wie es genau geht. Aber ich bin mir mittlerweile auch gar nicht sicher ob ein Interface das ist was ich benötige. Denn der Aufruf der fraglichen Methode verläuft ohne Übergabe von Parametern.

Während ich es hier schreibe, fällt mir ein, dass am Ende ja doch eine Information zurück an die MainActivity übergeben werden muss. Damit diese weiß was sie als nächstes aufrufen soll. :confused2:

Kann mir jemanden von euch einen Denkanstoß, ein Link zum narrensicheren Tutorial oder ähnliches nennen? Denn das ist für mich ja was elementares was ich verstehen will und muss.

Okay nun habe ich einen neuen Ansatz im Internet gefunden. In dem ich

Code:
MeineKlassex = new MeineKlasse();
        x.Methode();

verwende. So gibt es keine Probleme wegen statisch oder nicht statisch. Jedoch meckert Android Studio das die Zeile sp = getSharedPreferences() auf nichts verweist.

Code:
public void Methode() {
        //Daten für SharedPreference vorbereiten
        sp = getSharedPreferences("Installation ", MODE_PRIVATE);
        e = sp.edit();

        //prüfen ob daten schon gespeichert wurden
        if(sp.getString("Installation", "").equals("")){
            //Wenn Daten fehlen
            setzeZeit();
        }else {
            //Wenn Daten vorhanden
            datum_zeit = sp.getString("Installation", "");

            if(InetVorhanden()){
                vergleicheDatum();
            }else{
                Toast.makeText(getApplicationContext(),"Internet ist nicht vorhanden", Toast.LENGTH_SHORT).show();
            }
        }
    }

Jedoch funktioniert die Methode, wenn sie in der MainActivity eingetragen ist.

Ich glaube ich habe das Prinzip von Klassen bis jetzt noch nicht verstanden... kann es sein das meine Klasse aus getter und ggf. setter bestehen muss? Ich schreibe meine Klasse erstmal um.

Dann melde ich mich morgen noch einmal, vllt. hat ja bis dahin irgendwer auch einen Tipp für mich gehabt.
 
Zuletzt bearbeitet:
Hallo,

erstmal eine Frage. Du hast doch schon einiges programmiert wie man hier aus dem Forum lesen kann und dort hast du nie mit Klassen gearbeitet?
Des Weiteren wäre mir neu, dass man Klassen benutzt um Code auszulagern.

Du musst in der Klasse die Varaible sp initilaisiseren.
Code:
private SharedPreferences sp;
public void Methode() {
        //Daten für SharedPreference vorbereiten
        sp = getSharedPreferences("Installation ", MODE_PRIVATE);
        e = sp.edit();

        //prüfen ob daten schon gespeichert wurden
        if(sp.getString("Installation", "").equals("")){
            //Wenn Daten fehlen
            setzeZeit();
        }else {
            //Wenn Daten vorhanden
            datum_zeit = sp.getString("Installation", "");

            if(InetVorhanden()){
                vergleicheDatum();
            }else{
                Toast.makeText(getApplicationContext(),"Internet ist nicht vorhanden", Toast.LENGTH_SHORT).show();
            }
        }
    }

Und ein Beispiel mit Rückgabe einer SharedPreferences.

Code:
private SharedPreferences sp;
public SharedPreferences Methode() {
        //Daten für SharedPreference vorbereiten
        sp = getSharedPreferences("Installation ", MODE_PRIVATE);
        e = sp.edit();

        //prüfen ob daten schon gespeichert wurden
        if(sp.getString("Installation", "").equals("")){
            //Wenn Daten fehlen
            setzeZeit();
        }else {
            //Wenn Daten vorhanden
            datum_zeit = sp.getString("Installation", "");

            if(InetVorhanden()){
                vergleicheDatum();
            }else{
                Toast.makeText(getApplicationContext(),"Internet ist nicht vorhanden", Toast.LENGTH_SHORT).show();
            }
//Daten zurückgeben
   return sp;
    }

Aufruf:
Code:
private SharedPreferences sharedPreferences;
MeineKlassex = new MeineKlasse();
      sharedPreferences =  x.Methode();

Gruß
 
  • Danke
Reaktionen: Bergmann2016
Die Initialisierung habe ich ich drin, dass ist für mich selbstverständlich gewesen. Dennoch danke für deinen Hinweis :thumbup:

Mit return hatte ich es auch versucht, aber ich glaube ich hatte nur return; da stehen. Das war ja auch weshalb ich dann zum Schluß auf die Bemerkung mit Getter gekommen bin.

Zu deiner Frage:

123thomas schrieb:
erstmal eine Frage. Du hast doch schon einiges programmiert wie man hier aus dem Forum lesen kann und dort hast du nie mit Klassen gearbeitet?
Des Weiteren wäre mir neu, dass man Klassen benutzt um Code auszulagern.

Nein, das ist ja weshalb ich vor "Ewigkeiten" zum Thema Fragmente und Widget einen Rüffel bekam, erst bei der letzten App habe ich dann für jedes Fragment eine eigene Klasse erstellt. Aber die Klassen sind nicht miteinander verzweigt gewesen.

Die jetzige App soll eben meine Erste werden wo ich meine eigenen Methoden in meiner eigenen Klasse habe.

Klassen werden doch dafür benutzt um sich wiederholende Objekte zu erzeugen. Also warum sollte man dann nicht auch eine Klasse dafür benutzen sich ständig wiederholende Methoden zu bündeln? Denn bestimmte Methoden werden doch bei jeder App verwendet. Ob es ein TextView beschreiben ist oder ob es ein EditText auszulesen gilt oder eben wie in meinem Fall ein SharedPreferences-Datei auslesen. Wie gesagt, ich will diese Klasse ja wiederverwenden. Also wenn ich mir nun die Mühe mache, "gefährliche" Permission erlauben zu lassen und diese Methode immer zu brauche, dann finde ich es einfache diese nur einmal schreiben zu müssen und nicht bei jeder App von vorne anzufangen.

Vielleicht missbrauche ich damit auch den Sinn von Klassen, kann durchaus sein. Aber da ist meine "Faulheit" wichtiger. Denn für den Programmteil, den ich auslagern will, saß ich die letzten zwei Tage rund 18 Stunden dran und das brauche ich nicht bei jeder zukünftigen App. :blink:
[doublepost=1469639538,1469637576][/doublepost]
123thomas schrieb:
Aufruf:
Code:
private SharedPreferences sharedPreferences;
MeineKlassex = new MeineKlasse();
      sharedPreferences =  x.Methode();

An dieser Stelle bekomme ich von Android Studio gesagt, dass ich SharedPreferences sharedPreferences; nicht private machen soll. Was wieder zu dem ursprünglichen Fehler führt.

Ich versuche dann eben meine Klasse irgendwie sinnvoll umzuschreiben, dass ich Getter zur Verfügung habe und mir so die Daten holen kann. Mal schauen ob es so klappt wie ich es mir vorstelle.
 
123thomas schrieb:
Des Weiteren wäre mir neu, dass man Klassen benutzt um Code auszulagern.

Genau, das ist der Sinn von Klassen. Programmcode auszulagern und zu kapseln. Alles andere sind schöne Zugaben (Vererbung und so). Schon mal rein Strukturiert programmiert?

Hallo @Bergmann2016,
wenn man eine Methode einer Klasse in dieser Klasse aufruft, schreibt man this.methode(). Man kann auch das this weglassen.
Code:
class test {

   public void foo() {
      this.bar();
      // und einfacher ohne this:
     bar();
   }

  private void bar() {
  }
}

In deinem Beispiel ist getSharedPreferences(...) eine Methode der Klasse Activity, welche du in einer Activity aufrufst.

PS: Getter und Setter brauchst du unter Android nicht. Es kostet zu viel RAM und Performance, weshalb man sie unter Android vermeiden sollte.
 
  • Danke
Reaktionen: Bergmann2016
markus.tullius schrieb:
PS: Getter und Setter brauchst du unter Android nicht. Es kostet zu viel RAM und Performance, weshalb man sie unter Android vermeiden sollte.

Wie signifikant ist das? Performanceeinbußen durch Java-aufrufe soltlen doch mit dem Ahead-of-Time compiling seit Android 5 nciht besonders ins Gewicht fallen?!
 
So da bin ich wieder und muss euch sagen das gar nichts so richtig klappen will. Entweder bekomme ich es einfach nicht richtig verstanden oder die Android-Götter wollen mich ärgern.

Da ich euch nun nicht mit dem ganzen Code behelligen will und ich nicht ständig zig Zeilen Code umschreiben will, habe ich mir ein Test-Projekt erstellt. Ausser einem TextView und einem Aufruf im OnCreate() beinhaltet das Projekt eben meine Klasse. Nun habe ich mit verschiedenen Varianten versucht meine Methode aufzurufen. Jedesmal bekomme ich eine von Zwei Meldungen:
1. To much Output
2.
Code:
FATAL EXCEPTION: main
                                                                  Process: de.wilfried.test, PID: 12704
                                                                  java.lang.RuntimeException: Unable to start activity ComponentInfo{de.wilfried.test/de.wilfried.test.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
                                                                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3253)
                                                                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349)
                                                                      at android.app.ActivityThread.access$1100(ActivityThread.java:221)
                                                                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
                                                                      at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                      at android.os.Looper.loop(Looper.java:158)
                                                                      at android.app.ActivityThread.main(ActivityThread.java:7225)
                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
                                                                   Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
                                                                      at android.app.Activity.findViewById(Activity.java:2303)
                                                                      at tools.MeineTools.beschreibeTextView(MeineTools.java:26)
                                                                      at de.wilfried.test.MainActivity.onCreate(MainActivity.java:18)
                                                                      at android.app.Activity.performCreate(Activity.java:6876)
                                                                      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135)
                                                                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3206)
                                                                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349)
                                                                      at android.app.ActivityThread.access$1100(ActivityThread.java:221)
                                                                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
                                                                      at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                      at android.os.Looper.loop(Looper.java:158)
                                                                      at android.app.ActivityThread.main(ActivityThread.java:7225)
                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

Meine MAinActivity:
Code:
package de.wilfried.test;

import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import tools.MeineTools;

public class MainActivity extends Activity {



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

        MeineTools MT = new MeineTools();
        MT.beschreibeTextView(R.id.TextView, "Ich komme aus einer anderen Klasse");
    }
}

Damit ihr auch wisst wie meine Klasse aussieht:
Code:
package tools;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import de.wilfried.test.MainActivity;

/**
* Created by Wilfried on 28.07.2016.
*/
public class MeineTools extends Activity {

    TextView tv;
    EditText et;
    SharedPreferences sp;
    SharedPreferences.Editor e;

    MainActivity MA = new MainActivity();//nur bei extend
  
    public void beschreibeTextView(int id, String text){

        tv = (TextView)MA.findViewById(id);  //MA nur bei extend ansonsten mit "this" und "Context" und "getActivity" versucht und
        tv.setText(text);                     //natürlich auch mit "tv" (Weil AS es mir vorschlug) und wenn ich es ohne extend hatte auch ohne irgendwas

    }

    public void leseEditText(int id, String text){

        et = (EditText)findViewById(id);
        et.getText().toString();

    }

    public void speicherInSP(String dateiname, String inhalt) {

        e.putString(dateiname, inhalt);
        e.commit();

    }

    public void leseAusSP(Context context, String dateiname, String defaultwert){

        sp = context.getSharedPreferences(dateiname, Context.MODE_PRIVATE);
        sp.getString(dateiname, defaultwert);

    }

    public void macheEinToastKurz(String text){

        Toast.makeText(this.getApplicationContext(),text, Toast.LENGTH_SHORT).show();

    }

    public void macheEinToastLang(String text){

        Toast.makeText(this.getApplicationContext(),text, Toast.LENGTH_LONG).show();

    }
}

Also ich scheiter schon an einer einfachen Sachen, ich finde leider nur Video-Tutorial und Text-Tutorials die mit Getter und Setter arbeiten. Aber diese gehören ja offenbar nicht in Android rein. Kann mir irgendwer klipp und klar sagen wo mein Fehler liegt? Oder ernsthaft ein vernünftiges Tutorial ohne Getter-Setter verlinken? Ich hänge heute wieder seit 7 Stunden an diesem Problem...so langsam macht es mir echt keinen Spaß.



Ich bedanke mich für eure Hilfe :thumbsup:

jetzt habe ich meine Lösung gefunden. Meine Methode muss ja auch wissen in welchem Kontext sie arbeiten soll. Also diese Variante klappte nun:

Code:
public class MeineTools {

    TextView tv;

    public void beschreibeTextView(Activity activity, int id, String text){

        tv = (TextView) activity.findViewById(id);
        tv.setText(text);

    }

und den Aufruf habe ich so gelöst:

Code:
public class MainActivity extends Activity {

    private MeineTools MT;

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

        MT = new MeineTools();
        MT.beschreibeTextView(this, R.id.tv_textview, "Ich komme aus einer anderen Klasse");
    }
}

Sollte ich jetzt noch immer was falsch gemacht haben und es nur Zufall ist das es klappt, dann bitte ich euch es mir mitzuteilen.
 
Zuletzt bearbeitet:
markus.tullius schrieb:
"Without a JIT, direct field access is about 3x faster than invoking a trivial getter. With the JIT (where direct field access is as cheap as accessing a local), direct field access is about 7x faster than invoking a trivial getter"

Darauf wollte ich hinaus. Mit dem alten JIT Dalvik compiler sit das richtig. Die neue art der Kompilierung macht die ganzen Aufrufe aber performanter. Natürlich haben noch nicht alle Android 5 und darüber, deßhalb stimmt deine Aussage, vorläufig :)


@Bergamnn2016: du initialisiert niemals selbst eine Activity im Code. Das überlässt du dem System!
 
@Jaiel
Ich verstehe jetzt nicht was du meinst? Ich muss doch den Anstoß geben das irgendwas in Gang kommt. Woher soll das Programm sonst wissen das irgendwann etwas initialisiert werden soll?
 
Dadurch dass du die MainActivity selbst initialisiert und versuchst auf die Ressourcen ohne richtigen Kontext zuzugreifen ist es kein Wunder, dass du da Fehler bekommst. Vieles wird im Android System über Contextobjekte realisiert. Deßhalb erstellst du nie eine Acdtivity von selbst wenn du nicht weißt, was du da machst. Der Aufruf

setContentView(R.layout.activity_main);

in der MainActivity macht nichts da die Activity keinen gültigen Kontext aufweist, da du diese Activity ja selbst im Code initialisiert hast.

tl;dr: falls du nicht weißt was du da machst, dann mach es nicht sondern lies dich nochmal ein oder stelle hier die Frage vorzeitig :)

Jaiel
 
@Jail
Es ist egal, ob du Davlik o. Art benutzt. Bei Methodenaufrufe wird immer ein zusätzlicher Ballast mit geschleppt, und das braucht eben Speicher und Zeit.

Das gilt eigentlich auch für normales Java, nur dort sind die Rechner schneller. Und für so was wie JSF braucht man beans, und da sind Getter und Setter eben Pflicht.

@Bergmann2016

Du siehst das eigentlich richtig, irgendwo muss es eine main-Methode geben. Sprich der Punkt, wo alles beginnt. Der ist bei Android gekapselt, die Grund dafür ist der Lifecyle der App.
Die main Methode befindet sich in der Klasse ZygoteInit.
core/java/com/android/internal/os/ZygoteInit.java - platform/frameworks/base.git - Git at Google (Zeile 657)

Android benutzt eine andere Lösung, Entwicklercode einzubinden. Dies funktioniert über das Manifest. Das System durchsucht beim Start der App das Manifest, und sucht eine Activity mit folgenden Intentfiltern:
Code:
<intent-filter>
       <action   android:name="android.intent.action.MAIN"       />
       <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
MAIN seht für den Haupteintrittpunkt der App und
LAUNCHER erlaubt dem System die Acticity zu starten.

Sprich die Activity wird vom System instantiiert. Du muss nichts machen. Das xml (Manifest) ist eine Map, die dem System sagt, was es zu tun hat.
 

Ähnliche Themen

S
Antworten
0
Aufrufe
593
Sergio13
S
M
Antworten
3
Aufrufe
168
moin
M
Helmut1A
  • Helmut1A
Antworten
7
Aufrufe
1.128
Helmut1A
Helmut1A
Zurück
Oben Unten