如果您想了解android–我在哪里可以找到初始化ORMLite所需的ApplicationContext?的相关知识,那么本文是一篇不可错过的文章,我们将对android中初始化sharedpref
如果您想了解android – 我在哪里可以找到初始化ORMLite所需的ApplicationContext?的相关知识,那么本文是一篇不可错过的文章,我们将对android中初始化sharedpreferences进行全面详尽的解释,并且为您提供关于1、ApplicationContextInitializer初始化器解析、Android ApplicationTestCase使用MockContext、Android context(Application/Activity)与内存泄露、android – ApplicationContext或Activity Context是否适合Adapter?的有价值的信息。
本文目录一览:- android – 我在哪里可以找到初始化ORMLite所需的ApplicationContext?(android中初始化sharedpreferences)
- 1、ApplicationContextInitializer初始化器解析
- Android ApplicationTestCase使用MockContext
- Android context(Application/Activity)与内存泄露
- android – ApplicationContext或Activity Context是否适合Adapter?
android – 我在哪里可以找到初始化ORMLite所需的ApplicationContext?(android中初始化sharedpreferences)
我找到了这个,初始化它:dao.getEmptyForeignCollection()
但对于dao,我需要DatabaseHelper,而对于databasehelper,我需要applicationContext,但在实体中我没有上下文.还有其他选择吗?
这就是Code,它是一个1:n的关系.班组:
@DatabaseField(canBeNull = true,foreign = true) private Club club;
班级俱乐部:
@DatabaseField(canBeNull = true,foreign = true) private ForeignCollection<Team> teams;
感谢帮助
解决方法
07001
你特别问:
But for the dao,i need the
DatabaseHelper
,and for the database helper i need the applicationContext
,but in the entity i haven’t a context. is there any other option?
在Android下,每个扩展Activity,ListActivity,Service和tabactivity的类也都是Context.您可以在online docs中看到类层次结构:
java.lang.Object ↳ android.content.Context ↳ android.content.Contextwrapper ↳ android.view.ContextThemeWrapper ↳ android.app.Activity
如果您查看网站上提供的Android example项目,您可以看到Android应用程序的连接情况:
>您的主要活动扩展了OrmliteBaseActivity
public class HelloAndroid extends OrmliteBaseActivity<DatabaseHelper> {
> OrmliteBaseActivity中的onCreate方法使用Ormlite OpenHelperManager构建您的DatabaseHelper,并将其自身构建为Context:
OpenHelperManager.getHelper(this.getApplicationContext());
>您使用OrmliteBaseActivity.getHelper()方法来访问帮助程序以创建DAO,以便您可以将内容保留到数据库中.
1、ApplicationContextInitializer初始化器解析
1.1、初始化器三种添加到容器中方式
1) 方式1:在resources目录下新建META-INF目录,新建spring.factories文件并赋值
org.springframework.context.ApplicationContextInitializer=com.lwh.springboot.initializer.FirstInitializer
@Order(1)
public class FirstInitializer implements ApplicationContextInitializer<configurableapplicationcontext> {
@Override
public void initialize(ConfigurableApplicationContext ctx) {
ConfigurableEnvironment environment = ctx.getEnvironment();
Map<string, object> map = new HashMap<>();
map.put("key1", "value1");
MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer", map);
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("run firstInitializer");
}
}
2) 方式3:在application.properties中赋值,ThirdInitializer代码同FirstInitializer
赋值context.initializer.classes=com.lwh.springboot.initializer.ThirdInitializer
测试代码:访问输出value1, value3,说明赋值成功
@RestController
public class TestController {
@Autowired
private TestService testService;
@GetMapping("/test/initialize")
public String testInitialize(){
String value1 = testService.test("key1");
String value3 = testService.test("key3");
return value1 + ", " + value3;
}
}
@Component
public class TestService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public String test(String key){
return applicationContext.getEnvironment().getProperty(key);
}
}
3) 方式2:SecondInitializer代码同FirstInitializer,启动方式修改一下,测试方式类似
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
//SpringApplication.run(SpringbootApplication.class, args);
SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
springApplication.addInitializers(new SecondInitializer());
springApplication.run(args);
}
}
控制台输出:
run thirdInitializer -- ThirdInitializer标注了@Order(3)
run firstInitializer -- FirstInitializer标注了@Order(1)
run secondInitializer -- SecondInitializer标注了@Order(2)
规律:Order值越小,越先输出,在application.properties中定义的先输出
1.2、SpringFactoriesLoader介绍
1) 框架内部使用的通用工厂加载机制
2) 从classpath下多个jar包特定的位置读取文件并初始化类
3) 文件内容必须是kv形式,即properties类型
4) key是全限定名,value是实现,多个实现用逗号分隔
1.3、初始化器解析
1) 在上下文刷新即refresh方法前调用
2) 用来编码设置一些属性变量,通常用在web环境中
3) 可以通过order接口进行排序
1.4、 添加原理分析
1) 定义在spring.factories文件中被SpringFactoriesLoader发现注册
2) SpringApplication初始化完毕后手动添加
3) 定义成环境变量被DelegatingApplicationContextInitializer发现注册
1.4.1、方式1分析
方式1)代码分析:定义在spring.factories文件中被SpringFactoriesLoader发现注册
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 到这一步从spring.factories中加载ApplicationContextInitializer.class的实现类
setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 1) 从spring.factories中加载ApplicationContextInitializer.class的实现类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 2) 实例化步骤1中得到的实现类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 3) 根据order注解进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
// 1) 从spring.factories中加载ApplicationContextInitializer.class的实现类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
// org.springframework.context.ApplicationContextInitializer
String factoryClassName = factoryClass.getName();
// 获得一个Map,map形如<key,List<String>>形式,后面getOrDefault是获取
// org.springframework.context.ApplicationContextInitializer对应的实现类集合
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
// 带缓存功能,从各个jar包的META-INF/spring.factories文件中加载实现类,一个key可能包含多个实现
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
// 缓存中有直接返回
return result;
}
try {
// FACTORIES_RESOURCE_LOCATION值是META-INF/spring.factories
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
// 获取key
String factoryClassName = ((String) entry.getKey()).trim();
// 将value逗号分隔,获得各个具体的实现类
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
// 放入result中
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
// 返回的result见下图
return result;
}
}
// 2) 实例化步骤1中得到的实现类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader,
Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
// 判断instanceClass是否是ApplicationContextInitializer的实现类
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
}
return instances;
}
// 3) 根据order注解进行排序
AnnotationAwareOrderComparator.sort(instances);
public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE);
}
}
1.4.2、方式2分析
方式2)代码分析:手动添加
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
springApplication.addInitializers(new SecondInitializer());
springApplication.run(args);
}
}
public void addInitializers(ApplicationContextInitializer<?>... initializers) {
// 方式1最终也是放入到了SpringApplication的initializers集合中
this.initializers.addAll(Arrays.asList(initializers));
}
1.4.3、方式3分析
方式3)代码分析:在application.properties中配置,通过DelegatingApplicationContextInitializer注入
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// 这边加载之后默认有7个实现类,有一个是DelegatingApplicationContextInitializer
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 排完序后见下图,发现DelegatingApplicationContextInitializer在最前
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 方式1中分析的是SpringApplicatin的构造函数,构造函数完了之后已经加载了spring.factories的
// class到SpringApplication的initializers集合中,接着运行run函数
return new SpringApplication(primarySources).run(args);
}
// 核心代码,删除了部分代码,只分析与此有关的步骤
public ConfigurableApplicationContext run(String... args) {
try {
context = createApplicationContext();
// 走这一步
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
}
return context;
}
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments,
Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
// 走这一步,调用各个initializers的initialize方法
applyInitializers(context);
// 删除部分代码
}
protected void applyInitializers(ConfigurableApplicationContext context) {
// 遍历每个initializers,调用其initialize方法
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
// 调用initialize方法,第一个调用的就是DelegatingApplicationContextInitializer
initializer.initialize(context);
}
}
// DelegatingApplicationContextInitializer的initialize方法
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
List<Class<?>> initializerClasses = getInitializerClasses(environment);
if (!initializerClasses.isEmpty()) {
applyInitializerClasses(context, initializerClasses);
}
}
private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
// PROPERTY_NAME = "context.initializer.classes";
// classNames这里是com.lwh.springboot.initializer.ThirdInitializer
String classNames = env.getProperty(PROPERTY_NAME);
List<Class<?>> classes = new ArrayList<>();
if (StringUtils.hasLength(classNames)) {
for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
classes.add(getInitializerClass(className));
}
}
return classes;
}
private void applyInitializerClasses(ConfigurableApplicationContext context,
List<Class<?>> initializerClasses) {
Class<?> contextClass = context.getClass();
List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();
// 实例化Initializer对象
for (Class<?> initializerClass : initializerClasses) {
initializers.add(instantiateInitializer(contextClass, initializerClass));
}
// 调用initialize方法
applyInitializers(context, initializers);
}
SpringBoot默认的几个监听器
1) DelegatingApplicationContextInitializer,使用环境属性context.initializer.classes指定的初始化器(initializers)进行初始化工作,
如果没有指定则什么都不做
2) ServerPortInfoApplicationContextInitializer,通过监听器监听WebServerInitializedEvent事件,将内置servlet容器实际使用的监
听端口写入到Environment环境属性中,这样属性local.server.port就可以直接通过@Value注入到测试中,或者通过环境属性Environment获取
Android ApplicationTestCase使用MockContext
AppTests.java
package com.myProject.test; import android.test.ApplicationTestCase; public class AppTests extends ApplicationTestCase<MyApplication> { public AppTests() { super(MyApplication.class); } @Override protected void setUp() throws Exception { final RenamingMockContext mockContext = new RenamingMockContext(getContext()); setContext(mockContext); createApplication(); } }
MyApplication.java
package com.myProject.test; import android.app.Application; public class MyApplication extends Application { public MyApplication() { } @Override public void onCreate() { super.onCreate(); } }
RenamingMockContext.java
package com.myProject.test; import android.content.Context; import android.content.SharedPreferences; import android.test.RenamingDelegatingContext; import android.test.mock.MockContext; public class RenamingMockContext extends RenamingDelegatingContext { private static final String PREFIX = "test."; public RenamingMockContext(Context context) { super (new DelegatedMockContext(context),PREFIX); //super(context,PREFIX); } private static class DelegatedMockContext extends MockContext { private Context mDelegatedContext; public DelegatedMockContext(Context context) { mDelegatedContext = context; } @Override public String getPackageName() { return mDelegatedContext.getPackageName(); } @Override public SharedPreferences getSharedPreferences( String name,int mode) { return mDelegatedContext.getSharedPreferences( PREFIX + name,mode); } } }
失败追踪:
junit.framework.AssertionFailedError at android.test.ApplicationTestCase.setupApplication(ApplicationTestCase.java:102) at android.test.ApplicationTestCase.createApplication(ApplicationTestCase.java:118) at com.myApplication.test.AppTests.setUp(AppTests.java:14) at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:190) at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:175) at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1710)
请注意,如果我在注释掉的RenamingMockContext构造函数中使用第二个super()调用(所以不要使用扩展的MockContext类)它可以正常工作.
这是一个对我来说不起作用的参考UnsupportedOperationException while calling getSharedPreferences() from unit test,我还读了一下Android应用程序测试指南这本书,它给出了一个完全相同的例子,但是当我下载源代码并直接运行它时它给出了同样的错误.
解决方法
必须注释几行Setup方法才能使测试正常工作:
protected void setUp() throws Exception { super.setUp(); // final RenamingMockContext mockContext = new RenamingMockContext( // getContext()); // setContext(mockContext); createApplication(); mApplication = getApplication(); }
Android context(Application/Activity)与内存泄露
android中的context可以做很多操作,但是最主要的功能是加载和访问资源。
在android中有两种context,一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
比如一个activity的onCreate:public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); mGameView = new GameView(this); setContentView(mGameView); }把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity UI占有的资源:view , resource, SensorManager等。
但是这样如果context发生内存泄露的话,就会泄露很多内存,这里泄露的意思是gc没有办法回收activity的内存(当前Activity为活动或finish后还没来得及回收)。
Leaking an entire activity是很容易的一件事。
当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息再创建一个新的。
比如我们写了一个应用程序,需要加载一个很大的图片,我们不希望每次旋转屏幕的时候都销毁这个图片重新加载。
实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中,访问速度会很快。
实现类似:public class myactivity extends Activity { private static Drawable sBackground; protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); if (sBackground == null) { sBackground = getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground);//drawable attached to a view 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":
<application android:icon="@drawable/icon" android:label="@string/app_name" android:name=".GApplication"> <activity android:name=".WordSearch" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:screenOrientation="portrait" android:configChanges="keyboardHidden|orientation|keyboard|screenLayout"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context (继承类:public class GApplication extends Application)
3. 尽量使用静态类(全局),避免非静态的内部类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化
原文链接: http://blog.csdn.net/sunboy_2050/article/details/6891665
android – ApplicationContext或Activity Context是否适合Adapter?
我在我的项目中使用适配器进行ListView / RecycleView.但我想知道哪种上下文应该传递给适配器? ApplicationContext或Activity Context(它意味着活动上的这个)?
据我所知,即使活动被杀死,系统也不会杀死适配器.所以我在这里有一些困惑:
>如果我将活动上下文传递给适配器,则适配器具有对活动的隐式引用.活动可以被杀死吗?
>另一方面,我传递ApplicationContext.适配器还能存在多长时间?活动被杀后GC会收集吗?
>在特定情况下我应该传递哪种背景?
谢谢,
解决方法:
If I pass the Activity Context to the adapter, so the adapter have an
implicit reference to the activity. Can the activity be killed?
更正它是一个显式引用,因为您手动传递它.所以基本上你的问题的答案可能是YES,因为持有适配器的人是活动本身,即使适配器持有对你的活动的引用,一旦活动完成,它们都将被垃圾收集.
除非您正在处理线程,否则建议使用WeakReference,因为线程可以比活动本身更长寿.
In the other hand, I pass ApplicationContext. How long does the
Adapter still live? Does it collected by GC after the activity be
killed?
是
Which kind of Context I should pass in specific case?
两者都可以工作,但应用程序上下文更安全.
As I kNow that the system does not kill the adapter even if the
activity being killed.
代码中的某些东西是不正确的,可能是你正在使用静态或线程.此处需要其他代码或您的分析器证明!
今天的关于android – 我在哪里可以找到初始化ORMLite所需的ApplicationContext?和android中初始化sharedpreferences的分享已经结束,谢谢您的关注,如果想了解更多关于1、ApplicationContextInitializer初始化器解析、Android ApplicationTestCase使用MockContext、Android context(Application/Activity)与内存泄露、android – ApplicationContext或Activity Context是否适合Adapter?的相关知识,请在本站进行查询。
本文标签: