Android开发系列之Activity

号外号外,一只Android菜鸟的第一篇博客面世了。
享受着各种大牛前辈博客的恩惠,我也开始将自己所学所想分享出去,同时也提醒自己不断进步,早日成为一只老鸟!
作为一个“developer”,其学习过程正如同古代剑客要想成为绝世高手一样分为四个阶段:

  1. 手里有剑:学会使用某个工具,了解其方方面面
  2. 心中有剑:如何用好工具,理解其独特特性
  3. 人剑合一:你掌握的够深入吗?剖析其本质
  4. 十年磨剑:你是否可以创造工具?

    好了,话有点多,下面进入正文,开始练贱吧。~~

Activity作为四大组件之首,是使用最为频繁的一种组件,那么不得不将其放在开篇来讲。

1 、Activity使用—手里有剑

活动(Activity),将其理解为“界面”会更方便一些,在创建一个Android程序时,IDE会要求输入一个活动名,之后会自动生成一个MainActivity。打开MainActivity即可以看到如下主要代码:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

setContentView(R.layout.activity_main);为我们指定了此Activity的布局文件。打开AndroidManifest.xml文件,可以看到MainActivity已被注册,主要代码如下:

<activity
            android:name="com.example.demo1.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
</activity>

其中 intent-filter 标签中的两行表明了此Activity会被当做启动页面,即点击桌面App icon之后第一个显示的页面。

1.1 启动Acivity

1.1.1 使用显式Intent

Intent类的构造函数

注意:这里仅仅是为了方便所以采用Eclipse截图的,实际开发中墙裂建议大家用AS!

Intent有多个构造函数的重载,我们使用的那一个如上图所示,传入的第一个参数为启动活动的上下文,第二个参数则是要启动的目标活动。只需两行代码即可调转Activity:

Intent intent = new Intent(当前活动.this,目标活动.class);
startActivity(intent);

注意:一定要在AndroidManifest.xml文件中注册将要启动的Activity,不过现在IDE已经可以帮我们完成,但仍然需要记住。

1.1.2 使用隐式Intent:

你一定注意到过:当我们进行某个操作时,可能会跳出一个页面供你选择要打开此操作的App,如进行分享操作。这里就用到了隐式Intent,它指定了一系列更为抽象的action和category,再由系统去分析这个Intent并找出合适的Activity去启动。
通过在< activity >标签下配置 < intent-filter >可以指定当前Activity能够响应的action和category。创建SecondActivity,部分代码片段如下:

<activity
            android:name="com.example.demo1.SecondActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="com.example.demo1.SecondActivity.ACTION_TEST" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
</activity>

修改MainActivity当中的点击按钮的事件:

注意:一些简单的步骤被省略掉了,如创建布局、添加按钮等等,请自行添加

Intent intent = new Intent("com.example.demo1.SecondActivity.ACTION_TEST");
startActivity(intent);

点击Button之后会跳转至SecondActivity,这说明隐式Intent已经起了作用。

同样,我们也可以在代码中添加category,并在要启动的活动的< intent-filter >中注册,只要此活动当中有一个category匹配成功即可。

更多隐式Intent的用法

在很多情况下我们需要调用系统的Activity,比如从应用中调用手机自带 App拨打电话、发送短信等(注意添加响应权限),这是我们就要用到隐式的Intent以及系统内置的action。如以下示例:

//拨打电话
Intent  intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("110"));
startActivity(intent);

//加载网页
Intent  intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("Http://www.google.com"));
startActivity(intent);

关于内置的Intent有很多,大家可以参考官方文档实现不同的效果。

1.2 Activity之间传递数据

1.2.1 向下一个Activity传递数据

向下一个Activity传递数据的思路非常简单,用Intent的一系列putExtra()方法的重载即可。部分代码如下:

Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("extra_data","");//传递不同的参数
startActivity(intent);

在SecondActivity的onCreate()方法中使用

Intent intent=getIntent();
Xxx data=intent.getXxxExtra("extra_data");

即可将数据取出。如果传递的是int型数值则用getIntExtra,等等以此类推。

1.2.2 向上一个Activity返回数据

返回上一个活动时只需按一下Back键即可,并没有一个Intent来传递数据,那我们怎么传递数据呢?通过查看官方文档我们可知Activity有一个startActivityResult方法用来启动活动,并且在活动注销时会返回一个结果给上一个活动。如下所示,首先在MainActivity中启动SecondActivity:

Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivityResult(intent, 1);

其中第二个参数是请求码,用于在后面的回调中判断数据的来源。
接着,在SecondActivity中返回事件的逻辑如下(比如点击按钮事件等):

Intent intent = new Intent();
intent.putExtra("data_return","data returned to last activity");
setResult(RESULT_OK,intent);    //向上一个Activity返回数据
finish();

最后,在MainActivity当中重写onActivityResult方法来处理返回的数据,如下所示:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case 1:
                if (resultCode == RESULT_OK) {
                    String returnData = data.getStringExtra("data_return");
                }
                break;
            default:
        }
    }

1.3 Activity的生命周期

Activity的生命周期可以分为两部分:

  1. 典型情况下:指的是有用户参与的情况下,正常的生命周期
  2. 异常情况下:Activity被系统回收或由于当前设备的Configuration(如:旋转屏幕、更改系统设置等)发生改变所导致的Activity被销毁重建

两种情况下的生命周期关注点略有差别。

1.3.1 典型情况下的生命周期

正常情况下的生命周期如下所示:

  1. onCreate():表示Activity正在被创建,这是生命周期的第一个方法。通常在里面进行一些初始化工作,如加载布局、绑定事件等。这个阶段Activity处于不可见状态。
  2. onRestart():表示Activity当前正在重新启动,当前Activity从不可见变为可见状态时会调用。一般是由用户操作造成的,比如返回桌面后又回到App中。此阶段Activity由不可见变为可见(位于后台),但是并未获取焦点,无法和用户交互。可以将其看做一个短暂的加载阶段。
  3. onStart():表示Activity正在启动,还并未出现在前台,处于不可见状态。(可认为是一个从不可见转态变为可见状态的短暂阶段)
  4. onResume():当前Activity可见并且位于前台,可以和用户交互。
  5. onPause():表示Activity正在暂停中。当跳转到另一个Activity时,会首先执行当前活动的onPause(),当另一个活动onResume()调用后,才会调用当前Activity的onStop()方法。因此,为了下一个Activity流畅显式,在当前Activity的onPause方法中不能执行耗时操作,仅仅保存关键数据!
  6. onStop():Activity正在停止,可以做一些稍微重量级的回收工作。Activity变为完全不可见状态。
  7. onDestroy():表示Activity即将销毁,这是最后一个回调。应该做完回收工作和释放资源。

根据以上分析,我们很容易知道:

  1. 针对一个特定的Activity,第一次启动,回调如下:onCreate()->onStart()->onResume()
  2. 当用户启动一个新Activity或返回桌面时,当前活动回调如下:onPause()->onStop,特别的:是当新的Activity为透明主题时,第一个活动不会回调onStop(为什么呢?如果之前的Activity 调用onStop了,那么第二个活动的背景会是什么)
  3. 当用户返回Activity时,回调为onRestart()->onStart()->onResume()
  4. 当按下back键时,回调为onPause()->onStop()->onDestroy()

1.3.2 异常情况下的生命周期

  1. 资源相关的系统配置发生改变导致Activity被杀死并重新创建
    当Activity被异常终止的话,系统会调用onSaveInstanceState()来保存当前Activity的状态,这个方法的调用时机是在onStop之前,和onPause无固定的时序关系。
    当Activity重建时,系统会调用onRestoreInstanceState(),并且把Activity销毁时onSaveInstanceState()方法所保存的Bundle对象作为参数同时传递给onRestoreInstanceState()和onCreate()方法。onRestoreInstanceState()的调用时机在onStart()之后。

  2. 资源内存不足导致低优先级的Activity被杀死
    数据存储和数据恢复同情况1一样,会杀死低优先级的Activity。
    前台活动-优先级最高;可见但非前台活动-中级;后台活动(如执行了onStop的)-优先级最低

系统配置改变,不重新创建Activity的方法:
给Activity指定configChanges属性,如:android:configChanges=”oriention”可用|组合多个属性。设置此属性后,Activity不会重新创建,即不会调用生命周期、数据存储恢复,取而代之会调用onConfigurationChanged()方法,在此方法中进行其他处理!

1.4 Activity的启动模式

说到启动模式(Launch mode)就不得不讲讲返回栈(back stack),Android是使用任务(task)来管理Activity的,一个任务就是一组存放在栈里的Activity的集合,这个栈被称为返回栈。
启动模式一共有4中,下面一一进行分析:

  1. standard:标准模式,也是默认模式。每当启动一个Activity时,系统都会重建一个新的实例
  2. singleTop:栈顶复用,解决了标准模式重复创建栈顶Activity实例的问题。如果新的Activity已经位于任务栈的栈顶,那么不会重建此Activity的实例,同时它的onNewIntent()方法会被回调
  3. singleTask:栈内复用,单实例模式,突破了栈顶复用模式只能在栈顶复用Activity实例的限制,使整个Activity在返回栈中只有一个实例。只要Activity在这个栈中,那么就不会重新创建此Activity的实例,系统也会调用其onNewIntent()方法
  4. singleInstance:单实例模式。可以认为是加强型的singleTask,具有此模式的Activity系统会为其创建一个新的返回栈。(可用于多个应用共享一个Activity)

在具体的开发中,我们应该根据具体的情景合适的选用相关的启动模式。

1.5 Activity使用小技巧

1.5.1 使用BaseActivity&获取当前Activity名称

在大多数的开发当中,App当中并不止一个Activity,有一些可以复用的代码(如设置样式、加载资源、判断网络等)如果写入每一个Activity中会很麻烦也不便于修改维护。所以创建一个BaseActivity继承于Activity或AppCompatActivity 等等,并让其他所有Activity继承BaseActivity就很有必要了。

public class BaseActivity extends Activity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity",getClass().getSimpleName());
    }
    ...
}

1.5.2 退出程序(清除所有Activities)

如果你的应用在某一个页面时,你想退出App,此时点击Home键App会在后台挂起,并未真正退出。那么应该怎样做,使得可以注销所有Activity后退出呢?

答案就是:我们可以新建一个类ActivityCollector,并在其内部维护一个List、增加删除Activity的方法、清空List的方法(即finish所有Activity)。当新建一个Activity时在onCreate中调用List的add方法,在onDestroy中调用其remove方法,要退出程序是调用List的清空方法即可!部分代码如下:

 public class ActivityCollector{

        public static List<Activity> activities =new ArrayList<Activity>();

        public static void addActivity(Activity activity ){
            activities.add(activity);
        }
        public static void removeActivity(Activity activity){
            activities.remove(activity);
        }
        public static void finishAllActivities()
            for(Activity activity:activities){
            if(!activities.isFinishing()){
                activity.finish();
            }
        }
    }

接下来修改BaseActivity中的代码,如下所示:

public class BaseActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity",getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }

最后,在需要退出App的地方调用清除所有活动的方法即可:

ActivityCollector.finishAllActivities();

1.5.3 启动活动的最佳写法-传参

假如从MainActivity跳转进入SecondActivity时需要传递一些参数,我想我们会很容易写出以下代码:

    intent.putExtra("param1","data1");
    intent.putExtra("param2","data2");
    startActivity(intent);

这样写完全没有问题,但是试想一下如果是在实际项目当中有很多的Activity,有的我们并不知道它需要传递什么数据(甚至是不久之前自己写的),如果去阅读代码会很费事。又没有什么改进的办法呢?请看下面的代码片段:

public class SecondActivity extends BaseActivity {

    public static void actionStart(Context context, String data1, String data2) {
        Intent intent = new Intent(context, SecondActivity.class);
        intent.putExtra("param1", data1);
        intent.putExtra("param2", data2);
        context.startActivity(intent);
    }

我们可以在每个Activity中添加一个actionStart方法,指明需要传进来的数据,然后在要跳转至此的Activity中调用即可:

SecondActivity.actionStart(FirstActivity.this, "data1", "data2");

如此一来,跳转需要传入的数据就很清晰了,我们可以大量的节约去阅读代码的时间,就可以多码几块砖了。哈哈···

写了这么长时间,第一篇博文终于好了。由于是第一次写,还是感觉不太容易,虽然写的自己都很熟悉了。鄙人才疏学浅,欢迎各位读者拍砖、指点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值