《第一行代码》阅读记录—四大组件

本文是《第一行代码》的阅读记录,重点探讨了Android的四大组件:Activity、BroadcastReceiver、Service和Content Provider。首先,文章详细介绍了Activity的Intent用法,包括显式和隐式Intent,以及如何传递数据和接收返回值。接着,讲解了Activity的生命周期,包括各种状态和对应的回调方法。然后,阐述了BroadcastReceiver的系统广播和自定义广播的使用。最后,讨论了Service的基本用法和生命周期,以及Content Provider的内容解析。通过对四大组件的深入理解,有助于提升Android开发能力。
摘要由CSDN通过智能技术生成

一、前提概要

《第一行代码—Android》是Android初学者的最佳入门书。全书由浅入深、系统全面地讲解了Android软件开发的方方面面。这本书是2014年8月上市,到现在我写下这篇博客为止,已经过了两年,目前,它还是很畅销。可见,在一批新的android开发者眼中,它还是一本启蒙书的存在。这本书的作者郭霖,Android软件开发工程师。从事Android开发工作,有着丰富的项目实战经验,负责及参与开发过多款移动应用与游戏,对Android系统架构及应用层开发有着深入的理解,活跃于CSDN,在CSDN上发表Android技术相关博文,受到大量好评。

接下来,我会记录关于阅读《第一行代码》的学习见解与体会,内容框架并不是按照书上目录而来,如有不妥错误之处,可以评论指正以及补充。

二、四大组件之活动-Activity

(一)Intent

Intent 是 Android 程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent 一般可被用于启动活动、启动服务、以及发送广播等场景。Intent 的用法大致可以分为两种,显式 Intent 和隐式 Intent,我们先来看一下显式 Intent如何使用。

1.显式Intent

Intent 有多个构造函数的重载,其中一个是 Intent(Context packageContext, Class<?> cls)。这个构造函数接收两个参数,第一个参数 Context 要求提供一个启动活动的上下文,第二个参数 Class 则是指定想要启动的目标活动, 通过这个构造函数就可以构建出 Intent 的 “意图” 。
然后我们应该怎么使用这个 Intent 呢?Activity 类中提供了一个 startActivity()方法, 这个方法是专门用于启动活动的, 它接收一个 Intent参数, 这里我们将构建好的 Intent传入 startActivity()方法就可以启动目标活动了。

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

2.隐式Intent

相比于显式 Intent,隐式 Intent 则含蓄了许多,它并不明确指出我们想要启动哪一个活动, 而是指定了一系列更为抽象的 action 和 category 等信息, 然后交由系统去分析这个 Intent,并帮我们找出合适的活动去启动。

通过在标签下配置的内容,可以指定当前活动能够响应的 action和 category,打开AndroidManifest.xml,添加如下代码:

<activity android:name=".SecondActivity" >
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

action 标签中我们指明了当前活动可以响应com.example.bin.helloworld.ACTION_START 这个action,而category标签则包含了一些附加信息,更精确地指明了当前的活动能够响应的Intent 中还可能带有的category。只有actioncategory中的内容同时能够匹配上Intent 中指定的action 和category 时,这个活动才能响应该Intent。

每个Intent 中只能指定一个action,但却能指定多个category。

Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);

android.intent.category.DEFAULT 是一种默认category, 在调用startActivity()方法的时候会自动将这个category 添加到Intent 中。可以调用Intent 中的addCategory()方法来添加一个category

3.更多隐式Intent用法

使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android 多个应用程序之间的功能共享成为了可能。比如调用系统的浏览器打开网页。

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);

首先指定了 Intent 的 action 是 Intent.ACTION_VIEW, 这是一个 Android 系统内置的动作,其常量值为android.intent.action.VIEW。然后通过 Uri.parse()方法,将一个网址字符串解析成一个 Uri 对象,再调用 Intent 的 setData()方法将这个 Uri 对象传递进去。我们还可以在<intent-filter>标签中再配置一个<data>标签,用于更精确地指定当前活动能够响应什么类型的数据。<data>标签中主要可以配置以下内容。

  1. android:scheme
    用于指定数据的协议部分,如上例中的 http 部分。
  2. android:host
    用于指定数据的主机名部分,如上例中的 www.baidu.com 部分。
  3. android:port
    用于指定数据的端口部分,一般紧随在主机名之后。
  4. android:path
    用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
  5. android:mimeType

除了http 协议外,我们还可以指定很多其他协议,比如geo 表示显示地理位置、tel 表示拨打电话。调用系统拨号界面。

 Intent intent = new Intent(Intent.ACTION_DIAL);
 intent.setData(Uri.parse("tel:10086"));
 startActivity(intent);

4.向下一个活动传递数据

Intent 中提供了一系列putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent 中,启动了另一个活动后,只需要把这些数据再从Intent 中取出就可以了。putExtra()方法接收两个参数,第一个参数是键,用于后面从Intent中取值,第二个参数才是真正要传递的数据。

 String data = "I am from FirstActivity";
 Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
        intent.putExtra("extra_data",data);
startActivity(intent);
 //获得传递过来的意图
    Intent intent = getIntent(); 
    //获得意图中的信息,getStringExtra获得字符串类型,getBooleanExtra获得布尔类型。
    String data = intent.getStringExtra("extra_data");

另外,通过intent来传递对象有两种方式Serializable方式和Parcelable方式,这里暂且不提,有兴趣得可以Googel用法。

5.返回数据给上一个活动

Activity 中还有一个 startActivityForResult()方法也是用于启动活动的,但这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。毫无疑问,这就是我们所需要的。
startActivityForResult()方法接收两个参数,第一个参数还是 Intent,第二个参数是请求码,用于在之后的回调中判断数据的来源。

Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
//第一个参数还是Intent
//第二个参数是请求码,用于在之后的回调中判断数据的来源
startActivityForResult(intent,1);
Intent intent = new Intent();
intent.putExtra("data_return","hello FirstActivity");
//setResult()方法接收两个参数
//第一个参数用于向上一个活动返回处理结果, 一般只使用RESULT_OK 或 RESULT_CANCELED(按Back键后返回)
//第二个参数则是把带有数据的Intent 传递回去,
setResult(RESULT_OK,intent);
finish();

由于我们是使用 startActivityForResult()方法来启SecondActivity 的,在 SecondActivity被销毁之后会回调上一个活动的onActivityResult()方法,因此我们需要在 FirstActivity 中重写这个方法来得到返回的数据:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//第一个参数requestCode,即我们在启动活动时传入的请求码。
//第二个参数resultCode,即我们在返回数据时传入的处理结果。
//第三个参数data,即携带着返回数据的Intent
    switch (requestCode) {
        case 1:
            if (resultCode == RESULT_OK) {
                String returnData = data.getStringExtra("data_return");
                Toast.makeText(FirstActivity.this, "返回的值:" + returnData, Toast.LENGTH_SHORT).show();
            }
            break;
        default:
    }
}

如果用户点击Back键,也需要返回值,我们可以重写SecondActivity中的onBackPressed()方法。

@Override
public void onBackPressed() {
    Intent intent = new Intent();
    intent.putExtra("data_return", "Hello FirstActivity");
    setResult(RESULT_OK, intent);
    finish();
}

也可以重写onKeyDown()方法

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // 是否触发按键为back键
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        Intent intent = new Intent();
        intent.putExtra("data_return", "Hello FirstActivity");
        setResult(RESULT_OK, intent);
        this.finish();
        return true;
    }else {
        return super.onKeyDown(keyCode, event);
    }
}

(二)活动的生命周期

1.返回栈
Android 中的活动是可以层叠的。我们每启动一个新的活动,就会覆盖在原活动之上,然后点击 Back 键会销毁最上面的活动,下面的一个活动就会重新显示出来。其实 Android 是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack) 。栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的活动,它会在返回栈中入栈,并处于栈顶的位置。而每当我们按下 Back 键或调用 finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户。

2.活动状态

每个活动在其生命周期中最多可能会有四种状态。

1.运行状态
当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验。

2.暂停状态
当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。你可能会觉得既然活动已经不在栈顶了,还怎么会可见呢?这是因为并不是每一个活动都会占满整个屏幕的,比如对话框形式的活动只会占用屏幕中间的部分区域,你很快就会在后面看到这种活动。处于暂停状态的活动仍然是完全存活着的,系统也不愿意去回收这种活动(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种活动。

3.停止状态
当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能会被系统回收。

4.销毁状态
当一个活动从返回栈中移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足。

3.活动的生存期

Activity 类中定义了七个回调方法,覆盖了活动生命周期的每一个环节,下面我来一一介绍下这七个方法。

1.onCreate()
这个方法你已经看到过很多次了,每个活动中我们都重写了这个方法,它会在活动第一次被创建的时候调用。你应该在这个方法中完成活动的初始化操作,比如说加载布局、绑定事件等。

2.onStart()
这个方法在活动由不可见变为可见的时候调用。

3.onResume()
这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。

4.onPause()
这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗CPU 的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。

5.onStop()
这个方法在活动完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()方法并不会执行。

6.onDestroy()
这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。

7.onRestart()
这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。

4.活动被回收了怎么办

打个比方,MainActivity 中有一个文本输入框,现在你输入了一段文字,然后启动NormalActivity,这时MainActivity 由于系统内存不足被回收掉,过了一会你又点击了Back 键回到MainActivity,你会发现刚刚输入的文字全部都没了,因为MainActivity 被重新创建了。
Activity 中还提供了一个onSaveInstanceState()回调方法,这个方法会保证一定在活动被回收之前调用。

@Override
protected void onSaveInstanceState(Bundle outState) {
   super.onSaveInstanceState(outState);
   String tempData = "Something you just typed";
   outState.putString("data_key", tempData);
}

onSaveInstanceState()方法会携带一个Bundle 类型的参数,Bundle 提供了一系列的方法用于保存数据,比如可以使用putString()方法保存字符串,使用putInt()方法保存整型数据,以此类推。同样可以使用putParcelable()putSerializable()保存对象。每个保存方法需要传入两个参数,第一个参数是键,用于后面从Bundle 中取值,第二个参数是真正要保存的内容。

恢复数据,使用的onCreate()方法有一个Bundle 类型的参数。这个参数在一般情况下都是null,但是当活动被系统回收之前有通过onSaveInstanceState()方法来保存数据的话,这个参数就会带有之前所保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。修改onCreate()方法,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG, tempData);
}
……
}

Intent 还可以结合Bundle 一起用于传递数据的,首先可以把需要传递的数据都保存在Bundle 对象中,然后再将Bundle 对象存放在Intent 里。到了目标活动之后先从Intent 中取出Bundle,再从Bundle中一一取出数据。


(三)活动的启动模式

启动模式一共有四种,分别是 standard、singleTop、singleTask 和 singleInstance , 可 以 在 AndroidManifest.xml 中 通 过 给 <activity> 标 签 指 定android:launchMode 属性来选择启动模式。

standard,默认启动模式,系统不管此 Activity 是否已经在返回栈中存在,每次启动 Activity 都会创建该 Activity 的一个新的实例。

这里写图片描述

singleTop,在启动 Activity 时,如果发现返回栈的栈顶是该 Activity&#x

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值