GVKun编程网logo

android – 我在哪里可以找到初始化ORMLite所需的ApplicationContext?(android中初始化sharedpreferences)

12

如果您想了解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)

android – 我在哪里可以找到初始化ORMLite所需的ApplicationContext?(android中初始化sharedpreferences)

我正在使用 android和ormlite.我有一个初始化ForeignCollection的问题.

我找到了这个,初始化它: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;

感谢帮助

解决方法

您的问题不是关于外国收藏品,而是关于 ORMLite如何在Android下连线.所有这些都在文档中解释:

07001

你特别问:

But for the dao,i need the DatabaseHelper,and for the database helper i need the application Context,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、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

Android ApplicationTestCase使用MockContext

我是 Android测试的新手,我正在尝试使用MockContext创建一个ApplicationTestCase(实际上我正在尝试使用重命名模拟上下文).但我不断收到AssertionFailedError.到目前为止,这是我的基本代码:

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应用程序测试指南这本书,它给出了一个完全相同的例子,但是当我下载源代码并直接运行它时它给出了同样的错误.

解决方法

作为该书样本的解决方法,请查看ApplicationTestCase的android开发人员指南:“如果只是按原样运行测试,那么将为您的应用程序注入一个功能齐全的上下文”( http://developer.android.com/reference/android/test/ApplicationTestCase.html).

必须注释几行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(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?

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?的相关知识,请在本站进行查询。

本文标签: