android中的context可以做很多操作,但是最主要的功能是加载和访问资源。
在android中有两种context,一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
比如一个activity的onCreate:
01 | public void onCreate(Bundle savedInstanceState) { |
02 | super .onCreate(savedInstanceState); |
04 | requestWindowFeature(Window.FEATURE_NO_TITLE); |
05 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, |
06 | WindowManager.LayoutParams.FLAG_FULLSCREEN); |
07 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); |
10 | mGameView = new GameView( this ); |
11 | setContentView(mGameView); |
把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity UI占有的资源:view , resource, SensorManager等。
但是这样如果context发生内存泄露的话,就会泄露很多内存,这里泄露的意思是gc没有办法回收activity的内存(当前Activity为活动或finish后还没来得及回收)。
Leaking an entire activity是很容易的一件事。
当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息再创建一个新的。
比如我们写了一个应用程序,需要加载一个很大的图片,我们不希望每次旋转屏幕的时候都销毁这个图片重新加载。
实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中,访问速度会很快。
实现类似:
01 | public class myactivity extends Activity { |
02 | private static Drawable sBackground; |
03 | protected void onCreate(Bundle state) { |
04 | super .onCreate(state); |
06 | TextView label = new TextView( this ); |
07 | label.setText( "Leaks are bad" ); |
09 | if (sBackground == null ) { |
10 | sBackground = getDrawable(R.drawable.large_bitmap); |
12 | label.setBackgroundDrawable(sBackground); |
14 | setContentView(label); |
这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有leak,即gc没法销毁activity
我们刚才说过,屏幕旋转的时候系统会销毁当前的activity。但是当drawable和view关联后,drawable保存了view的 reference,即sBackground保存了label的引用,而label保存了activity的引用。既然drawable不能销毁,它所引用和间接引用的都不能销毁,这样系统就没有办法销毁当前的activity,于是造成了内存泄露。gc对这种类型的内存泄露是无能为力的。
避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免由于对象对 activity的引用导致activity不能正常被销毁
同时,我们可以使用application context
application context伴随application的一生,与activity的生命周期无关。
application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。
使用Application,需要在 AndroidManifest.xml 文件注册,即android:name=".GApplication":
01 | < application android:icon = "@drawable/icon" |
02 | android:label = "@string/app_name" |
03 | android:name = ".GApplication" > |
05 | < activity android:name = ".WordSearch" |
06 | android:label = "@string/app_name" |
07 | android:theme = "@android:style/Theme.NoTitleBar.Fullscreen" |
08 | android:screenOrientation = "portrait" |
09 | android:configChanges = "keyboardHidden|orientation|keyboard|screenLayout" > |
11 | < action android:name = "android.intent.action.MAIN" /> |
12 | < category android:name = "android.intent.category.LAUNCHER" /> |
避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context (继承类:public class GApplicationextends Application)
3. 尽量使用静态类(全局),避免非静态的内部类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化
文章出处:http://blog.csdn.net/sunboy_2050/article/details/6891665
android中的context可以做很多操作,但是最主要的功能是加载和访问资源。
在android中有两种context,一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
比如一个activity的onCreate:
01 | public void onCreate(Bundle savedInstanceState) { |
02 | super .onCreate(savedInstanceState); |
04 | requestWindowFeature(Window.FEATURE_NO_TITLE); |
05 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, |
06 | WindowManager.LayoutParams.FLAG_FULLSCREEN); |
07 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); |
10 | mGameView = new GameView( this ); |
11 | setContentView(mGameView); |
把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity UI占有的资源:view , resource, SensorManager等。
但是这样如果context发生内存泄露的话,就会泄露很多内存,这里泄露的意思是gc没有办法回收activity的内存(当前Activity为活动或finish后还没来得及回收)。
Leaking an entire activity是很容易的一件事。
当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息再创建一个新的。
比如我们写了一个应用程序,需要加载一个很大的图片,我们不希望每次旋转屏幕的时候都销毁这个图片重新加载。
实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中,访问速度会很快。
实现类似:
01 | public class myactivity extends Activity { |
02 | private static Drawable sBackground; |
03 | protected void onCreate(Bundle state) { |
04 | super .onCreate(state); |
06 | TextView label = new TextView( this ); |
07 | label.setText( "Leaks are bad" ); |
09 | if (sBackground == null ) { |
10 | sBackground = getDrawable(R.drawable.large_bitmap); |
12 | label.setBackgroundDrawable(sBackground); |
14 | setContentView(label); |
这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有leak,即gc没法销毁activity
我们刚才说过,屏幕旋转的时候系统会销毁当前的activity。但是当drawable和view关联后,drawable保存了view的 reference,即sBackground保存了label的引用,而label保存了activity的引用。既然drawable不能销毁,它所引用和间接引用的都不能销毁,这样系统就没有办法销毁当前的activity,于是造成了内存泄露。gc对这种类型的内存泄露是无能为力的。
避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免由于对象对 activity的引用导致activity不能正常被销毁
同时,我们可以使用application context
application context伴随application的一生,与activity的生命周期无关。
application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。
使用Application,需要在 AndroidManifest.xml 文件注册,即android:name=".GApplication":
01 | < application android:icon = "@drawable/icon" |
02 | android:label = "@string/app_name" |
03 | android:name = ".GApplication" > |
05 | < activity android:name = ".WordSearch" |
06 | android:label = "@string/app_name" |
07 | android:theme = "@android:style/Theme.NoTitleBar.Fullscreen" |
08 | android:screenOrientation = "portrait" |
09 | android:configChanges = "keyboardHidden|orientation|keyboard|screenLayout" > |
11 | < action android:name = "android.intent.action.MAIN" /> |
12 | < category android:name = "android.intent.category.LAUNCHER" /> |
避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context (继承类:public class GApplicationextends Application)
3. 尽量使用静态类(全局),避免非静态的内部类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化
文章出处:http://blog.csdn.net/sunboy_2050/article/details/6891665
使用application需要两个步骤:1.复写Application类,2.在配置文件中配置
示例代码如下:
package app.app;
import android.app.Application;
import android.content.res.Configuration;
public class MyApp extends Application {
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
public void onCreate() {
super.onCreate();
System.out.println("MyApp is called");
}
@Override
public void onLowMemory() {
super.onLowMemory();
}
@Override
public void onTerminate() {
super.onTerminate();
}
}
配置文件:
<application android:icon="@drawable/icon" android:label="@string/app_name" android:name="app.app.MyApp" >
......
</application>
Android中Activity共享变量的另一方法:Application context
感觉用这种方式存储登录信息比较好,比SharedPreferences存储登录信息的状态比较合适。
相当于存储session的数据(打个比喻)。
多个Activity中经常使用同一变量时,使用Bundle则比较麻烦,每次调用Activity都需要设置一次。如想在整个应用中使用,在java中一般是使用静态变量,而在android中有个更优雅的方式是使用Application context。
用SharedPreferences存储的话关闭应用的时候这个值还是最后一次设置的值,如果是非正常退出程序时登录状态就会有问题,所以在使用上感觉 application context是最合适存储当前登录状态的信息,当然可是存储一些相当于session当中存储的值,因为关闭应用后这些值就没有了
package org.mdx.core.modules;
import android.app.Application;
public class ApplicationHelper extends Application {
private boolean session_enter = false; // 默认为false
/**
* 设置session状态
*
* @param bol
* true为以登录,false未登录
*/
public void putSession(boolean bol) {
session_enter = bol;
}
/**
* 是否登录
*
* @return true是,false否
*/
public boolean isEnter() {
return session_enter;
}
}
在AndroidManifest.xml的application加个name属性就可以了,如下面所示:
<application android:name=".core.modules.ApplicationHelper"
android:icon="@drawable/icon" android:label="@string/app_name">
activity使用时:(这个是重点)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getApplicationContext().putSession(false); // 设置登录状态为退出
}
public ApplicationHelper getApplicationContext() {
return ((ApplicationHelper) super.getApplicationContext());
}