Android四大核心组件——汇总

一、Activity

生命周期
在这里插入图片描述
七大方法详解
onCreate:Activity创建时第一个调用的方法,通常我们在该方法中加载布局文件,初始化UI组件,事件注册等等
onStart:在onCreate方法之后调用,用于显示界面,但用户还不能进行交互

onRestart:当一个stoped状态的Activity被返回时调用,之后再调用onStart进入运行状态

onResume:在onStart之后调用,该方法执行完成后,用户可以进行交互,当前Activity进入resumed状态。当一个paused状态的activity被重新返回时,会再次调用该方法,让Activity进入运行状态

onPause:当其它Activity(透明或窗口模式)进入时,该方法会被调用,让当前Activity进入paused状态(暂停状态)。当前Activity还可见但不可交互,如果其它更高优先级的APP需要内存时,当前Activity可能会被销毁(kill)。当前Activity被返回时会调用onResume方法

onStop:当其它Activity覆盖该Activity时,会被调用,当前Activity进入stoped状态(停止状态)。不可见,如果其它更高优先级的APP需要内存时,当前Activity可能会被销毁(kill)。 当前Activity被返回时会调用onRestart方法

onDestroy:当前Activity被销毁时调用,通常在该方法中用来释放资源,当前Activity killed

四个重要状态
在这里插入图片描述
横竖屏切换时Activity的生命周期

此时的生命周期跟清单文件里的配置有关系。

①不设置 Activity 的 android:configChanges 时,横竖屏切换会重新调用各个生命周期,销毁当前 activity,然后重新加载,跟系统配置有关。

②onSaveInstanceState()方法会在当前页面销毁前被调用存储数据,onRestoreInstanceState()方法会被执行去取出保存的Bundle对象中的内容,进行一次横竖屏切换时Activity所执行的生命周期方法以及在onSaveInstanceState与onRestoreInstanceState打印相应日志

Activity的启动模式

standard模式:默认模式,以这种模式加载必定会构造一个新的Activity实例放到目标Task的activity栈顶,不管当前task的栈顶是什么情况。

singleTop:这种模式与standard模式类似,区别在于加载activity会多个判断步骤。判断需要加载的新activity与当前task栈顶的activity是不是同一个,相同的话就不再构造新的activity,并调用这个activity的newInstance()方法,不相同就还是会构造新的activity放到栈顶。

singleTask:这种模式下,会创建一个新的task来加载这个activity,并且这个task中只允许存在一个Activity的一个实例(以后可以加载其他Activity的实例)。

singleInstance:这种模式下,会创建一个新的task并且这个task中只能存在一个需要加载的这个Activity实例,即除了这个activity之外,不允许其他activity。

可以在清单文件中activity的launchMode中设置该activity的加载模式

图解standard模式
在这里插入图片描述
在这里插入图片描述

点击一次ActivityA按钮,会重新创建一个ActivityA进入栈,点击ActivityB按钮会创建一个ActivityB进入栈,所以是不断的重新创建Activity。
图解singleTop模式
在这里插入图片描述

修改了Activity的launchMode为singleTop
当此时的Activity为ActivityB时,即栈顶为ActivityB,点击按钮不会创建一个新的ActivityB出来,但是,如果是以下情况
在这里插入图片描述

点击ActivityB按钮,不会去调用下面的B,而是重新创建一个ActivityB放入栈顶,如图
在这里插入图片描述

图解singleTask模式
在这里插入图片描述

修改ActivityB的launchMode为singleTask,当这种情况下,点击ActivityB按钮,发现栈内已经有ActivityB时,会把ActivityB之上的Activity清除出栈。
在这里插入图片描述

图解singleInstance模式
在这里插入图片描述
修改ActivityB的launchMode为singleInstance,此时点击ActivityB按钮是,会新建一个Task,如图,
在这里插入图片描述

此时显示的是ActivityB,点击ActivityA按钮后,会返回之前的task并创建一个ActivityA,过程如下
在这里插入图片描述

点击返回,会先返回任务栈里的所以Activity,再切换到ActivityB,再返回就退出。

二、Service
定义与作用
— Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行,以上是Google文档的解释,资料来源于大神博客
— Service还有一个作用就是提升进程(每个应用都是一个进程)的优先级,进程的优先级指的是在Android系统中,会把正在运行的应用确定一个优先级,当内存空间不足时,系统会根据进程的优先级清理掉一部分进程占用的内存空间,以获得足够的内存空间以供新启用的应用运行。详细的进程优先级划分如下,
1)前台进程:应用程序存在Activity正位于前台,可见并可控
2)可见进程:应用程序存在Activity处于局部可见状态,即局部可见却不可控
3)服务进程:应用程序存在正在运行的Service
4)后台进程:应用程序的所有Activity均被置于后台,没有任何Activity可见
5) 空进程:已经退出的应用程序

生命周期
在这里插入图片描述
状态
1)启动
【启动service】
用Context类定义的startService(Intent)即可启动Service组件,其中intent定义方法与跳转Activity类似,只需把Actvity类换成Service类即可。其生命周期为启动时onCreate()–>onStartCommand()–>销毁时onDestroy(), 反复调用startService()只会导致Service反复执行onStartCommand()
【停止service】
调用Context类定义的stopService(Intent)即可停止Service组件,反复调用并没有任何效果,亦不会报告错误,即:即使停止没有启动的Service也不会出错。也可以在Service类的内部,调用Service定义的stopSelf()方法,停止当前Service。

2)绑定
主要作用是实现组件间的通信,实质的表现是Activity可以调用Service中的方法,使Service执行特定的业务,并且这些方法可以是带返回值的方法,进而Activity可以通过获取这些返回值,这样就实现与Service的通信。
【生命周期】
– onCreate() -> 当第1次绑定时执行
– onBind() -> 当第1次绑定时执行
– onDestroy() -> 当解除绑定时执行

启动一个服务

public void startClick(View v){
        Intent intent=new Intent(this,MyService.class);
        startService(intent);

    }

停止一个服务

public void stopClick(View v){
        Intent intent=new Intent(this,MyService.class);
        stopService(intent);
    }

service特性
(1)Service的粘性:
当Service被意外终止(非正常停止,即不是通过stopService()或stopSelf()停止)后,会在未来的某一刻自动重启。
Service的粘性是通过onStartCommand()方法的返回值确定的,可用的值有:
—–Service.START_REDELIVER_INTENT -> 粘性的,且在自动重启时,会重新给Service发送Intent对象。
—–Service.START_STICKY -> 粘性的
—–Service.START_NOT_STICKY -> 非粘性的
—–Service.START_STICKY_COMPATIBILITY -> 粘性的,并且兼容的
当需要Service是非粘性的,取值Service.START_NOT_STICKY;当需要Service是粘性的,并且还需要获取Intent对象时,取值Service.START_REDELIVER_INTENT;否则,只是需要粘性的,不需要Intent时,取值super.onStartCommand()默认值。
(2)Service是单例的,在程序中一个Service类只会存在一个对象
(3)Service是没有界面的,适合于在后台进行耗时操作,但要注意Service仍然是运行在主线程中的,故耗时的操作还是需要开启子线程来进行。

三、ContentProvider
.作用
中文意思是内容提供者,ContentProvider可以将应用程序自身的数据对外(对其它应用程序)共享,使得其它应用可以对自身的数据进行增、删、改、查操作。
Android系统使用了许多ContentProvider,将系统中的绝大部分常规数据进行对外共享,例如:联系人资料、通话记录、短信、相册、歌曲、视频、日历等等,一般这些数据都存放于一个个的数据库中。
应用程序可以在Content Provider中执行如下操作:

查询数据

修改数据

添加数据

删除数据

查询记录:
在Content Provider中使用的查询字符串有别于标准的SQL查询。很多诸如select, add, delete, modify等操作我们都使用一种特殊的URI来进行,这种URI由3个部分组成, “content://”, 代表数据的路径,和一个可选的标识数据的ID。以下是一些示例URI:

	content://media/internal/images  这个URI将返回设备上存储的所有图片
     content://contacts/people/  这个URI将返回设备上的所有联系人信息
     content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)

尽管这种查询字符串格式很常见,但是它看起来还是有点令人迷惑。为此,Android提供一系列的帮助类(在android.provider包下),里面包含了很多以类变量形式给出的查询字符串,这种方式更容易让我们理解一点,参见下例:

MediaStore.Images.Media.INTERNAL_CONTENT_URI
Contacts.People.CONTENT_URI

因此,如上面content://contacts/people/45这个URI就可以写成如下形式:

Uri person = ContentUris.withAppendedId(People.CONTENT_URI,  45);

然后执行数据查询:

Cursor cur = managedQuery(person, null, null, null);

修改记录:
我们可以使用ContentResolver.update()方法来修改数据,我们来写一个修改数据的方法:

private void updateRecord(int recNo, String name) {
    Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo);
    ContentValues values = new ContentValues();
    values.put(People.NAME, name);
    getContentResolver().update(uri, values, null, null);
}

添加记录:
要增加记录,我们可以调用ContentResolver.insert()方法,该方法接受一个要增加的记录的目标URI,以及一个包含了新记录值的Map对象,调用后的返回值是新记录的URI,包含记录号。
上面的例子中我们都是基于联系人信息簿这个标准的Content Provider,现在我们继续来创建一个insertRecord() 方法以对联系人信息簿中进行数据的添加:

private void insertRecords(String name, String phoneNo) {
    ContentValues values = new ContentValues();
    values.put(People.NAME, name);
    Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
    Log.d(”ANDROID”, uri.toString());
    Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
    values.clear();
    values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE);
    values.put(People.NUMBER, phoneNo);
    getContentResolver().insert(numberUri, values);
}

删除记录:
Content Provider中的getContextResolver.delete()方法可以用来删除记录,下面的记录用来删除设备上所有的联系人信息:

private void deleteRecords() {
    Uri uri = People.CONTENT_URI;
    getContentResolver().delete(uri, null, null);
}

创建Content Provider
要创建我们自己的Content Provider的话,我们需要遵循以下几步:

  1. 创建一个继承了ContentProvider父类的类

  2. 定义一个名为CONTENT_URI,并且是public static final的Uri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称, 如:
    public static final Uri CONTENT_URI = Uri.parse( “content://com.google.android.MyContentProvider”);

  3. 创建你的数据存储系统。大多数Content Provider使用Android文件系统或SQLite数据库来保持数据,但是你也可以以任何你想要的方式来存储。

  4. 定义你要返回给客户端的数据列名。如果你正在使用Android数据库,则数据列的使用方式就和你以往所熟悉的其他数据库一样。但是,你必须为其定义一个叫_id的列,它用来表示每条记录的唯一性。

  5. 如果你要存储字节型数据,比如位图文件等,那保存该数据的数据列其实是一个表示实际保存文件的URI字符串,客户端通过它来读取对应的文件数据,处理这种数据类型的Content Provider需要实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供ContentResolver使用。客户端可以调用ContentResolver.openOutputStream()方法来处理该URI指向的文件资源,如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件。

  6. 声明public static String型的变量,用于指定要从游标处返回的数据列。

  7. 查询返回一个Cursor类型的对象。所有执行写操作的方法如insert(), update() 以及delete()都将被监听。我们可以通过使用ContentResover().notifyChange()方法来通知监听器关于数据更新的信息。

  8. 在AndroidMenifest.xml中使用标签来设置Content Provider。

  9. 如果你要处理的数据类型是一种比较新的类型,你就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。MIME类型有两种形式:一种是为指定的单个记录的,还有一种是为多条记录的。这里给出一种常用的格式:

vnd.android.cursor.item/vnd.yourcompanyname.contenttype (单个记录的MIME类型)
比如, 一个请求列车信息的URI如content://com.example.transportationprovider/trains/122 可能就会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型。

vnd.android.cursor.dir/vnd.yourcompanyname.contenttype (多个记录的MIME类型)
比如, 一个请求所有列车信息的URI如content://com.example.transportationprovider/trains 可能就会返回vnd.android.cursor.dir/vnd.example.rail这样一个MIME 类型。

四、BroadcastReceiver

BroadcastReceive简介
BroadcastReceive也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播。

广播接收器的类型
(1)Normal broadcasts:默认广播
发送一个默认广播使用Content.sendBroadcast()方法,普通广播对于接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。
(2)Ordered broadcasts:有序广播
发送一个有序广播使用Content.sendOrderedBroadcast()方法,有序广播比较特殊,它每次只发送到优先级较高的接收者那里,然后由优先级高的接收者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播
(3)Sticky Broadcast:粘性广播
当处理完之后的Intent,依然存在,直到你把它去掉。
广播接收器的创建步骤
构建Intent,使用sendBroadcast方法发出广播。
定义一个广播接收器,该广播接收器继承BroadcastReceive,并且覆盖onReceive()方法来响应事件
注册该广播接收器,我们可以在代码中注册,也可以在清单文件中注册。

自定义的广播接收器

public class MyReceiver1 extends BroadcastReceiver {
    public MyReceiver1(){

    }

    //接收
    @Override
    public void onReceive(Context context, Intent intent) {
        String info=intent.getStringExtra("info");
        Toast.makeText(context,info,Toast.LENGTH_SHORT).show();
    }
}

发送一个普通的广播

public void sendNormalClick(View v){
        Intent intent=new Intent("com.example.action.MY_BROADCAST");
        intent.putExtra("info","姑娘约否");
        this.sendBroadcast(intent);
    }

注册文件中添加对应的action
在这里插入图片描述
册广播接收器的两种方式
静态注册
静态注册是在AndroidManifest.xml文件中配置。
动态注册
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播

MyReceiver receiver=new MyReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("android.intent.action.MY_BROADCAST");
registerReceiver(receiver,filter);

解除注册

unregisterReceiver(receiver);

有序广播的创建
先创建两个接收器

public class MyReceiver3 extends BroadcastReceiver {
    public MyReceiver3(){

    }
    @Override
    public void onReceive(Context context, Intent intent) {
       Bundle data= getResultExtras(false);
      String info= data.getString("info");
        Toast.makeText(context,"有序广播-1----"+info,Toast.LENGTH_SHORT).show();
    }
}
public class MyReceiver4 extends BroadcastReceiver {
        public MyReceiver4(){

        }
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"有序广播-2",Toast.LENGTH_SHORT).show();

        Bundle data=new Bundle();
        data.putString("info","广播-2");
        this.setResultExtras(data);
    }
}

发送一个有序广播

 public void sendOrderClick(View v){
        Intent intent=new Intent("com.example.action.MY_BROADCAST2");
        //参数:intent ,接收权限
        this.sendOrderedBroadcast(intent,null);
    }

在这里插入图片描述
其中priority表示优先级,属性范围(-1000,1000),数值越大,优先级越高。
中断有序广播

this.abortBroadcast();

同级别接收先后是随机的,再到级别低的收到广播;如果先接收到的把广播截断了,同级别以外的接收者是无法收到该广播的。
在这个方法发来的广播中(代码注册方式中),收到广播先后次序为:注明优先级的、代码注册的、没有优先级的;如果都没有优先级,代码注册收到为最先。

粘性广播的创建
创建一个广播接收器

public class MyReceiver5 extends BroadcastReceiver {
public MyReceiver5(){

}
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"接收一个粘性的广播",Toast.LENGTH_SHORT).show();
    }
}

发送一个粘性广播

public void sendStickyClick(View v){
            Intent intent=new Intent("com.example.action.MY_BROADCAST3");
        this.sendStickyBroadcast(intent);
    }

粘性广播必须要权限
在清单文件中加入

 <uses-permission android:name="android.permission.BROADCAST_STICKY" />

至此告一段落,写这篇汇总主要是方便自己的查看,为之后的实习做准备,加油呀少年。

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值