Singleton in Android


73

Ich bin diesem Link gefolgt und habe erfolgreich Singleton-Klasse in Android gemacht. http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/

Problem ist, dass ich ein einzelnes Objekt möchte. wie ich habe Aktivität A und Aktivität B. In Aktivität AI Zugriff auf das Objekt von Singleton class. Ich benutze das Objekt und habe einige Änderungen daran vorgenommen.

Wenn ich zu Aktivität B wechsle und von der Singleton-Klasse aus auf das Objekt zugreife, habe ich das initialisierte Objekt erhalten und die in Aktivität A vorgenommenen Änderungen nicht beibehalten. Gibt es eine andere Möglichkeit, die Änderung zu speichern? Bitte helfen Sie mir Experten. Das istMainActivity

public class MainActivity extends Activity {
    protected MyApplication app;        
    private OnClickListener btn2=new OnClickListener() {    
        @Override
        public void onClick(View arg0) {
            Intent intent=new Intent(MainActivity.this,NextActivity.class);
            startActivity(intent);              
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Get the application instance
        app = (MyApplication)getApplication();

        // Call a custom application method
        app.customAppMethod();

        // Call a custom method in MySingleton
        Singleton.getInstance().customSingletonMethod();

        Singleton.getInstance();
        // Read the value of a variable in MySingleton
        String singletonVar = Singleton.customVar;

        Log.d("Test",singletonVar);
        singletonVar="World";
        Log.d("Test",singletonVar);

        Button btn=(Button)findViewById(R.id.button1);
        btn.setOnClickListener(btn2);
    }

}

Das ist NextActivity

public class NextActivity extends Activity {

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

            String singletonVar = Singleton.customVar;

            Log.d("Test",singletonVar);
        }
  }

Singleton Klasse

public class Singleton
{
    private static Singleton instance;

    public static String customVar="Hello";

    public static void initInstance()
    {
    if (instance == null)
    {
      // Create the instance
      instance = new Singleton();
    }
    }

    public static Singleton getInstance()
    {
     // Return the instance
     return instance;
     }

     private Singleton()
     {
     // Constructor hidden because this is a singleton
     }

     public void customSingletonMethod()
     {
     // Custom method
     }
 }

und MyApplication

public class MyApplication extends Application
    {
    @Override
    public void onCreate()
    {
    super.onCreate();

     // Initialize the singletons so their instances
     // are bound to the application process.
     initSingletons();
     }

     protected void initSingletons()
     {
     // Initialize the instance of MySingleton
     Singleton.initInstance();
     }

     public void customAppMethod()
     {
     // Custom application method
    }
}

Wenn ich diesen Code ausführe, erhalte ich Hello, das ich in der SingletonWelt initialisiert habe, in der ich es gegeben habe, MainActivityund zeigt Hello NextActivityin logcat erneut an. Ich möchte, dass es die Welt wieder zeigt NextActivity. Bitte helfen Sie mir, dies zu korrigieren.


Warum rufen Sie in MainActivity Singleton.getInstance () zweimal auf?
IgorGanapolsky

1
Dies geschah hauptsächlich, weil beim Aufrufen von String singletonVar = Singleton.customVar; In Java weist diese Zuweisungsoperation keinen Verweis auf Singleton.customVar im Speicher zu. Sie erstellt einfach eine neue Variable namens singletonVar. Wenn Sie also SingltonVar ändern, ändern Sie einfach den Wert der lokalen Variablen, nicht der Singleton-Variablen.
M_AWADI

Alt, aber String singletonVar = Singleton.customVar; String ist ein primitiver Typ, es ist also kein Objekt. Sie kopieren einfach den korrekten Wert vom Singleton in die loca-Variable und ändern dann den Wert der lokalen Variablen
Pecana

Der Link ist falsch
Slaknation

Antworten:


47

EDIT:

Die Implementierung eines Singleton in Android ist nicht "sicher" ( siehe hier ) und Sie sollten eine Bibliothek verwenden, die dieser Art von Muster gewidmet ist, wie Dagger oder eine andere DI-Bibliothek, um den Lebenszyklus und die Injektion zu verwalten.


Könnten Sie ein Beispiel aus Ihrem Code posten?

Schauen Sie sich dieses Wesentliche an: https://gist.github.com/Akayh/5566992

es funktioniert, aber es war sehr schnell erledigt:

MyActivity: Setzen Sie den Singleton zum ersten Mal + initialisieren Sie das mString-Attribut ("Hello") im privaten Konstruktor und zeigen Sie den Wert ("Hello") an.

Setzen Sie den neuen Wert auf mString: "Singleton"

Starten Sie activityB und zeigen Sie den mString-Wert an. "Singleton" erscheint ...


Es ist ein Beispielcode für Singleton zwischen Aktivitäten. Wenn Sie weitere Hilfe benötigen, geben Sie Ihren Code (oder ein einfaches Beispiel) ein, um das Problem zu erkennen
Akayh,

3
Dies liegt nur daran, dass die Zeichenfolge in singletonVar kopiert wird und nicht auf sie verweist. Wenn Sie die statische Variable direkt wie folgt ändern: Singleton.customVar = "World"; es ist Arbeit.
Akayh

6
Nur ein Kopf hoch, das ist NICHT threadsicher! Denken Sie immer an Murphys Gesetz. Eine Möglichkeit, den Thread sicher zu machen, besteht darin, das synchronizedkeyworkd in Ihrer getInstance()Methode zu verwenden.
Dazito

4
@Akayh Könnten Sie bitte erklären, warum Singleton unter Android nicht sicher ist? Ist es sicher nur nicht sicher bei Aktivitäten oder nicht sicher bei der Anwendung?
Saba

1
"Singleton in Android ist nicht sicher" - benötigt eine Referenz und im Idealfall eine Erklärung.
Noelicus

61

Tipp: So erstellen Sie eine Singleton-Klasse Klicken Sie in Android Studio mit der rechten Maustaste in Ihr Projekt und öffnen Sie das Menü:

New -> Java Class -> Choose Singleton from dropdown menu

Geben Sie hier die Bildbeschreibung ein


2
Nicht mehr verfügbar
Thecave3

32

Es ist einfach, als Java unterstützt Android auch Singleton. - -

Singleton ist Teil des Gang of Four-Designmusters und wird unter Kreationsdesignmuster kategorisiert.

-> Statisches Mitglied: Enthält die Instanz der Singleton-Klasse.

-> Privater Konstruktor: Dadurch wird verhindert, dass andere Personen die Singleton-Klasse instanziieren.

-> Statische öffentliche Methode: Hiermit wird der globale Zugriffspunkt auf das Singleton-Objekt bereitgestellt und die Instanz an die aufrufende Clientklasse zurückgegeben.

  1. private Instanz erstellen
  2. privaten Konstruktor erstellen
  3. Verwenden Sie getInstance () der Singleton-Klasse

    public class Logger{
    private static Logger   objLogger;
    private Logger(){
    
            //ToDo here
    
    }
    public static Logger getInstance()
    {
        if (objLogger == null)
       {
          objLogger = new Logger();
       }
       return objLogger;
       }
    
    }
    

während Singleton verwenden -

Logger.getInstance();

Wie unterscheidet sich dies von der ursprünglichen Implementierung von Singleton durch den veröffentlichten Benutzer?
IgorGanapolsky

18

Die von Rakesh vorgeschlagene Antwort ist großartig, aber mit einigen Beschreibungen ist Singleton in Android dieselbe wie Singleton in Java: Das Singleton-Entwurfsmuster behebt all diese Probleme. Mit dem Singleton-Entwurfsmuster können Sie:

1) Stellen Sie sicher, dass nur eine Instanz einer Klasse erstellt wird

2) Stellen Sie einen globalen Zugriffspunkt auf das Objekt bereit

3) Erlauben Sie in Zukunft mehrere Instanzen, ohne die Clients einer Singleton-Klasse zu beeinträchtigen

Ein einfaches Beispiel für eine Singleton-Klasse:

public class MySingleton
{
    private static MySingleton _instance;

    private MySingleton()
    {

    }

    public static MySingleton getInstance()
    {
        if (_instance == null)
        {
            _instance = new MySingleton();
        }
        return _instance;
    }
}

1
Dies ist definitiv der beste Ansatz, da er einen faulen Konstruktor erstellt hat. Mit anderen Worten, er wird nur instanziiert, wenn getInstance()er zum ersten Mal aufgerufen wird.
Angelo Polotto

14

Wie in dieser Antwort von @Lazy angegeben , können Sie in Android Studio aus einer Vorlage einen Singleton erstellen. Es ist zu beachten, dass nicht überprüft werden muss, ob die Instanz null ist, da die statische ourInstanceVariable zuerst initialisiert wird. Daher ist die von Android Studio erstellte Implementierung der Singleton-Klasse so einfach wie der folgende Code:

public class MySingleton {
    private static MySingleton ourInstance = new MySingleton();

    public static MySingleton getInstance() {
        return ourInstance;
    }

    private MySingleton() {
    }
}

1
Dies ist die einfachste und schnellste Lösung. Wenn Sie getInstance () häufig in einer Schleife aufrufen, sind die anderen Antworten mit einer Überprüfung auf null erheblich langsamer.
BitByteDog

5

Sie kopieren Singletons customVarin eine singletonVarVariable und das Ändern dieser Variablen wirkt sich nicht auf den ursprünglichen Wert in Singleton aus.

// This does not update singleton variable
// It just assigns value of your local variable
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);

// This actually assigns value of variable in singleton
Singleton.customVar = singletonVar;

Wäre es nicht sicherer, customVar zu einer privaten statischen Variablen zu machen und Zugriffsmethoden dafür zu erstellen?
Igor Ganapolsky

2

Ich habe meine Version von Singleton unten angegeben:

public class SingletonDemo {
    private static SingletonDemo instance = null;
    private static Context context;

    /**
     * To initialize the class. It must be called before call the method getInstance()
     * @param ctx The Context used

     */
    public static void initialize(Context ctx) {
     context = ctx;
    }

    /**
     * Check if the class has been initialized
     * @return true  if the class has been initialized
     *         false Otherwise
     */
    public static boolean hasBeenInitialized() {
     return context != null;

    }

    /**
    * The private constructor. Here you can use the context to initialize your variables.
    */
    private SingletonDemo() {
        // Use context to initialize the variables.
    }

    /**
    * The main method used to get the instance
    */
    public static synchronized SingletonDemo getInstance() {
     if (context == null) {
      throw new IllegalArgumentException("Impossible to get the instance. This class must be initialized before");
     }

     if (instance == null) {
      instance = new SingletonDemo();
     }

     return instance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Clone is not allowed.");
    }
}

Beachten Sie, dass die Methodeninitialisierung in der Hauptklasse (Splash) und die Methode getInstance von anderen Klassen aufgerufen werden kann. Dies behebt das Problem, wenn die Aufruferklasse den Singleton benötigt, aber nicht über den Kontext verfügt.

Schließlich wird mit der Methode hasBeenInitialized überprüft, ob die Klasse initialisiert wurde. Dadurch wird vermieden, dass unterschiedliche Instanzen unterschiedliche Kontexte haben.


Android Studio behandelt diese Antwort als Problem - Speicherverlust -, da Sie einen Kontext in einer statischen "Instanz" einer anderen Klasse festgelegt haben. Dieses Muster ist jetzt nutzlos
Narkis

@narkis Interessant. Wenn dies zutrifft, wird auch dann, wenn die Personen die statische Instanz von Context in der CustomApplication haben, ein Speicherverlust generiert. Sie sollten uns alle darüber wärmen :-)
Jiahao

1

Die sauberste und modernste Art, Singletons in Android zu verwenden, ist die Verwendung des Dependency Injection- Frameworks namens Dagger 2 . Hier finden Sie eine Erläuterung der möglichen Bereiche, die Sie verwenden können. Singleton ist einer dieser Bereiche. Die Abhängigkeitsinjektion ist nicht so einfach, aber Sie sollten ein wenig Zeit investieren, um sie zu verstehen. Dies erleichtert auch das Testen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.