使用单例 MainActivity?

Using Singleton MainActivity?

我想知道使用单例 MainAcitivity 是否是一个糟糕的设计选择,如下所示:

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

例如,在很多需要访问上下文的情况下,我使用getContext(),但有时(我不知道为什么)getContext() returns null 导致运行时异常。我最终使用了我创建的 mainActivitySingleton 而不是 getContext().

我的小手指告诉我这是一个糟糕的设计选择!如果是这样,谁能解释一下为什么?

永远不要那样做。那是糟糕的设计模式。您不应该将 activity 实例保存为静态实例,因为这可能会导致内存泄漏。如果你在片段实例中调用 getContext() 方法,那么你应该在这个生命周期 onActivityCreated() method 中调用 getContext() 方法。

像这样:

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

持有对 Activity 对象或 Context 的静态引用是内存泄漏情况之一,它会导致额外的内存消耗,然后导致性能下降。如果没有引用指向某个对象,则将其标记为要进行垃圾收集的候选对象。当一个对象在程序中不再使用,但它的内存不能被垃圾收集器释放时,它被认为是内存泄漏情况。因此,在静态引用 Activity 的情况下,调用 onDestroy 方法后无法释放其内存。

如果你真的想持有ActivityContext实例的静态引用,建议使用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);
    }
} 

用法:

Context context = sContextReference.get();

.

更新:

保留对 Context 实例的引用的更好解决方案是在 Application class 中创建并保存对它的弱引用。通过这种方式,我们确保在应用程序的 运行 时间内只有一个引用指向应用程序上下文。

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>

用法:

Context context = MyApplication.getContext();