使用单例 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
方法后无法释放其内存。
如果你真的想持有Activity
或Context
实例的静态引用,建议使用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();
我想知道使用单例 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
方法后无法释放其内存。
如果你真的想持有Activity
或Context
实例的静态引用,建议使用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();