Android03--Context和Application

标签: Android


undefined

Context #

当我们访问当前应用的资源、获取系统服务、创建View、启动一个新的activity的时候都需要提供Context。

Context是一个抽象基类,我们通过它访问当前包的资源(getResources、getAssets)和启动其他组件(Activity、Service、Broadcast)以及得到各种服务(getSystemService),当然,通过Context能得到的不仅仅只有上述这些内容。

对Context的理解可以来说:Context提供了一个应用的运行环境,在Context的大环境里,应用才可以访问资源,才能完成和其他组件、服务的交互,Context是个抽象类,定义了一套基本的功能接口,可以理解为一套规范,而Activity和Service是实现这套规范的子类。

继承关系上,Activity、Service、Application都是Context的子类。

Application #

大家在需要Context的时候,如果是在Activity中,大多直接传个this,当在匿名内部类的时候,因为this不能用,需要写XXXActivity.this。有时候我们可能获取不到当前的Context,那么就需要使用ApplicationContext

首先,并没有ApplicationContext这个类。通过继承Application类,我们可以在整个项目共享一些数据,可以拿到ApplicationContext。

Application里有个onCreate()回调方法,这个方法会在我们的Activity的onCreate()前运行。利用这个特性,我们可以提前初始化些数据。

onCreate() 应用启动的时候
onTeminate() 终端模拟的时候
onLowMemory() 低内存的时候
onTrimMemory() 内存清理的时候
onConfigurationChanged() 配置改变的时候

现在我们编写App.java继承Application:

package com.a52fhy.learnapplicationcontext;

import android.app.Application;
import android.widget.Toast;

/**
 * Created by YJC on 2016/9/14 014.
 */
public class App extends Application {

    protected String defaultName = "default";

    public String getDefaultName() {
        return defaultName;
    }

    public void setDefaultName(String defaultName) {
        this.defaultName = defaultName;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        Toast.makeText(App.this, "Application:onCreate", Toast.LENGTH_SHORT).show();
    }
}

MainActivity里使用:

Toast.makeText(MainActivity.this, "MainActivity:onCreate", Toast.LENGTH_SHORT).show();

//获取默认值
String name = ((App)getApplicationContext()).getDefaultName();

//设置显示默认值
((TextView)findViewById(R.id.tv)).setText(name);

findViewById(R.id.btnSave).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String name = ((EditText)findViewById(R.id.editText)).getText().toString();
        ((App)getApplicationContext()).setDefaultName(name);

        ((TextView)findViewById(R.id.tv)).setText(name);
    }
});

Main2Activity里代码与MainActivity一样。

修改AndroidManifest.xml,application标签增加属性:

android:name=".App"

让APP使用我们写的App而不是Application

activity内容:

 <activity android:name=".MainActivity" android:label="Main">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name=".Main2Activity" android:label="Main2">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

这里标签为Main1和Main2的两个Activity的intent-filter是一样的,都可以作为启动入口。安装后会在桌面生成Main1Main2两个图标。

当我们运行APP后,在Main1里输入文字,返回桌面,打开Main2,发现直接修改的内容还在。

我们还发现程序里设置的toast,当app第一次启动的时候,Application:onCreate弹出,然后MainActivity:onCreate弹出;以后切换进入Main1Main2Application:onCreate不会再弹出,而MainActivity:onCreate依旧会弹出,说明Application:onCreate运行在APP启动的时候。

简化事件监听回调写法 #

之前代码里我们会在findViewById()后面以回调函数的方式写点击事件,事件多了不是很优雅。我们可以让MainActivity实现View.OnClickListener:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {}

然后onCreate里:

findViewById(R.id.editText).setOnClickListener(this);
findViewById(R.id.btnSave).setOnClickListener(this);

增加一个onClick()方法:

@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.editText:

            break;

        case R.id.btnSave:
            String name = ((EditText)findViewById(R.id.editText)).getText().toString();
            ((App)getApplicationContext()).setDefaultName(name);

            ((TextView)findViewById(R.id.tv)).setText(name);
            break;
    }
}

使用v.getId()获取各个id。这样看起来是不是优雅些了呢?

Build by Loppo 0.6.6