Abdu
Abdu

Reputation: 497

Using Singleton MainActivity?

I would like to know whether it's a bad design choice to use a singleton MainAcitivity as in the following:

public class MainActivity extends AppCompatActivity ... {
   public static MainActivity mainActivitySingleton;
   ....
   @Override
   protected void onCreate(Bundle savedInstanceState) {
   mainActivitySingleton=this;

For instance, in many occasions where I need to access the context I use getContext(), but sometimes (I don't know why) getContext() returns null resulting in a runtime exception. I ended up using the mainActivitySingleton I created instead of getContext().

My little finger tells me this is a bad design choice! if it is the case, can anyone explain why?

Upvotes: 0

Views: 2064

Answers (2)

aminography
aminography

Reputation: 22832

Holding a static reference to Activity object or Context, is one of the memory leak cases which leads to extra memory consumption then performance lost. If no reference points to an object, then it is marked as a candidate to be garbage collected. When an object is not used anymore in the program but its memory cannot be released by the Garbage Collector, it is considered as a memory leak case. Therefore, in case of static reference to an Activity, its memory could not be freed after calling onDestroy method.

If you really want to hold a static reference to an instance of Activity or Context, it is recommended to use WeakReference.

public class MyActivity extends AppCompatActivity {

    private static WeakReference<Context> sContextReference;

    @Override 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sContextReference = new WeakReference<>(this);
    }
} 

Usage:

Context context = sContextReference.get();

.

UPDATE:

Better solution to retain a reference to an instance of Context is to create and hold a weak reference to it in an Application class. By this way, we sure that only one reference is pointed to the application context during run time of the app.

MyApplication.java

import android.app.Application;
import android.content.Context;

import java.lang.ref.WeakReference;

public class MyApplication extends Application {

    private static WeakReference<Context> sContextReference;

    @Override
    public void onCreate() {
        super.onCreate();
        sContextReference = new WeakReference<>(getApplicationContext());
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        sContextReference.clear();
    }

    public static Context getContext() {
        return sContextReference.get();
    }

}

manifest.xml

<application
    android:name="path.to.MyApplication"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:theme="@style/AppTheme.NoActionBar">

    ...

</application>

Usage:

Context context = MyApplication.getContext();

Upvotes: 3

Rid Hrant
Rid Hrant

Reputation: 152

Never do that. That is the bad design pattern. You should not save activity instance as static instance, because that potential memory leak. If you call getContext() method in fragment instance then you should call getContext() in this lifecircle onActivityCreated() method.

Like this:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    Context context = getContext();
}

Upvotes: 1

Related Questions