【Android】全局变量的实现
在Android里面,经常需要在Activity之间共享数据。
1)方法一:使用static变量,但是静态变量容易引起内存泄漏,举例解释如下(zz:Android中Context):
当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息,再创建一个新的。比如我们写了一个应用程序,它需要加载一个很大的图片,我们不希望每次旋转屏幕的时候都销毁这个图片,重新加载。实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中。实现类似:
1 public class myactivity extends Activity { 2 private static Drawable sBackground; 3 protected void onCreate(Bundle state) { 4 super.onCreate(state); 5 6 TextView label = new TextView(this); 7 label.setText("Leaks are bad"); 8 9 if (sBackground == null) { 10 sBackground = getDrawable(R.drawable.large_bitmap); 11 } 12 label.setBackgroundDrawable(sBackground);//drawable attached to a view 13 14 setContentView(label); 15 } 16 }
这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有leak(即gc没法销毁activity)。我们刚才说过,屏幕旋转的时候系统会销毁当前的activity。但是当drawable和view关联后,drawable保存了view的 reference,即sBackground保存了label的引用,而label保存了activity的引用。既然drawable不能销毁,它所引用和间接引用的都不能销毁,这样系统就没有办法销毁当前的activity,于是造成了内存泄露。gc对这种类型的内存泄露是无能为力的。避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免由于对象对 activity的引用导致activity不能正常被销毁。
2)方法二:使用SharedPreferences
会产生xml配置文件,最好是用来保存用户的个性化设置,存储效率不是很高。和SQLite一样,不适合存储在很多Activity都要使用的变量。
3)方法三:来自:http://stackoverflow.com/questions/708012/android-how-to-declare-global-variables/708317#708317 ,也就是使用Application context来保存全局变量
The more general problem you are encountering is how to save state across several Activities and all parts of your application. A static variable (for instance, a singleton) is a common Java way of achieving this. I have found however, that a more elegant way in Android is to associate your state with the Application context.
As you know, each Activity is also a Context, which is information about its execution environment in the broadest sense. Your application also has a context, and Android guarantees that it will exist as a single instance across your application.
The way to do this is to create your own subclass of android.app.Application, and then specify that class in the application tag in your manifest. Now Android will automatically create an instance of that class and make it available for your entire application. You can access it from any context using the Context.getApplicationContext() method (Activity also provides a method getApplication() which has the exact same effect):
1 class MyApp extends Application { 2 3 private String myState; 4 5 public String getState(){ 6 return myState; 7 } 8 public void setState(String s){ 9 myState = s; 10 } 11 } 12 13 class Blah extends Activity { 14 15 @Override 16 public void onCreate(Bundle b){ 17 ... 18 MyApp appState = ((MyApp)getApplicationContext()); 19 String state = appState.getState(); 20 ... 21 } 22 }
This has essentially the same effect as using a static variable or singleton, but integrates quite well into the existing Android framework. Note that this will not work across processes (should your app be one of the rare ones that has multiple processes).
关于在AndroidManifest.xml文件中的注册:
1 <application android:name=".MyApp" 2 android:icon="@drawable/icon" 3 android:label="@string/app_name">
谷歌文档解释:
use android:name, in addition to the default icon and label in the application stanza.
android:name The fully qualified name of an Application subclass implemented for the application. When the application process is started, this class is instantiated before any of the application's components.
The subclass is optional; most applications won't need one. In the absence of a subclass, Android uses an instance of the base Application class.
补充:在android中context可以作很多操作,但是最主要的功能是加载和访问资源。在android中有两种context,一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。比如一个activity的onCreate:
1 protected void onCreate(Bundle state) { 2 super.onCreate(state); 3 4 TextView label = new TextView(this); 5 //传递context给view control 6 label.setText("Leaks are bad"); 7 setContentView(label); 8 }
把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。