Android 四大组件相关知识点

Activity

1.当指定的Activity在用户可见后才进行广播注册,在用户不可见后对广播进行注销,那么应该在哪两个回调中做这个处理?

可见——onStart();

不可见——onStop();

2.如果有一些数据在Activity跳转(或者离开时)要保存到数据库中,在onPause()中执行比较好;

理由:onPause()方法是进程被杀死之前保证会执行的最后一个方法,简单来说,在执行了onPause()方法之后,直到执 行onResume()之前,该activity所在的进程都是有可能“突然死亡”的,onStop()和onDestroy()方法并不能保证一定会被执行。所以onPause()方法是持久化相关数据的最后的可靠时机。

3.ActivityA启动ActivityB,它们的生命周期变化:

ActivityA:onCreate()---onStart()---onResume()---启动ActivityB---onPause()---onStop()

ActivityB: onCreate()---onStart()---onResume()---Back---onPause()---ActivityA重新启动---onStop()---onDestory()

ActivityA: onRestart()---onStart()---onResume()---Back---onPause()---onStop()---onDestory()

注:如果内存不够,A可能执行onDestory(),建议在savedInstanceState中保存关键数据

4.ActivityA 通过intent显示启动了ActivityB ,当B处于可见时,A是否一定调用onStop()?

不一定,若B是dialog(对话框),当B处于可见时,A也可见(但不能与用户交互,处于onPause()),不会调用onStop() .

5.不是所有的数据存储要放在onPause()

当要执行比较耗时 的操作时,不要在onPause()中执行,因为会影响下一个活动的显示,onPause()不执行完,下一个活动的onResume()无法执行,无法正常显示。Service

开启服务有两种方式: StartService() BindService().

starService 开启一个服务,会执行onCreate()方法,和onStart()方法,如果服务已经开启,只会执行onStart()方法。

服务开启后,就会在后台长期运行,可以在设置界面找到,我们可以在设置界面手动关闭它,服务就会停止运行。

startService开启服务也叫做非绑定模式开启服务 ,生命周期 第一次执行的方法有 onCreate().onstartCommand(),到service关闭的时候执行onDestroy()方法。

bindService开启服务也叫做绑定模式开启服务,生命周期 第一次执行的方法有 onCreate(), onBind()方法,

销毁的时候执行onUnBind(),onDestroy()方法, bindService开启服务有个特点,它在设置界面时找不到的,所以我们无法手动在设置界面销毁它,不过它的生命周期依附于Activity,当Activity销毁的时候,这个服务也就跟着销毁。

上面两种生命周期实在相对单纯的模式下的情形,我们在开发的过程中还必须注意Service实例只会有一个,也就是说如果当前要启动的Service已经存在了那么就不会再次创建该Service当然也不会调用onCreate()方法;

一个Service可以被多个客户进行绑定,只有所有绑定对象都执行了onBind()方法后该Service才会销毁,不过如果有一个用户执行了onStart()方法,那么这个时候如果其他所有的bind客户都执行了unBind()。该Service也不会销毁,很多应用都是用startService和bindService混合开启服务,比如音乐播放器,第三方支付等

在前台运行服务

我们之前定义的服务都是运行在后台的,这样的服务当系统内存不足时将会被杀死,而用户却毫不知情。如果想要一个服务的状态可以被用户一眼看到,那么可以使用前台服务。

将一个服务设置为前台服务,只需要在绑定时调用startForeground将自己设置为前台服务即可,其中第二个参数是Notification对象,表示在通知栏中显示的通知。

@Override
public void onCreate() {
    super.onCreate();
    Log.d(TAG, "onCreate: ");
    Intent intent = new Intent(this,MainActivity.class);
    PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle("this is content title")
            .setContentText("this is content text")
            .setWhen(System.currentTimeMillis())
            .setSmallIcon(R.mipmap.ic_launcher)
            .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
            .setContentIntent(pi)
            .build();
    /**
     * 参数一:通知id,参数二:通知的对象
     */
    startForeground(1,notification);
}

服务是运行在主线程中,故不能执行耗时操作,具体实现是在服务具体方法内开启一个子线程去执行,而且如果想要实现让服务在执行完毕后自动停止的功能,需要调用stopSelf()方法。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "onStartCommand: ");
    //在服务具体方法中开启线程执行耗时操作
    new Thread(new Runnable() {
        @Override
        public void run() {
            //具体逻辑
            //实现让服务执行完毕后自动停止
            stopSelf();
        }
    }).start();
    return super.onStartCommand(intent, flags, startId);
}

而IntentService的出现实现了开启线程自动停止的功能

IntentService

服务和Activity一样,都是Android的组件,生命周期中的各个方法也都运行在主线程中。所以虽然服务名为“服务”,但是如果想要其中执行耗时任务,还是需要将任务放入到线程中。IntentService就是这样一种服务,Android已经为我们封装了创建线程的过程,只需要我们直接实现耗时任务的逻辑即可。IntentService的使用有如下限制

- 不可以直接和用户交互。如果需要将结果与UI交互,需要将结果返回给Activity

- 工作请求遵循线性,FIFO

- IntentService中的操作不能被打断

使用IntentService:

使用IntentService,只需要继承自IntentService类,需要实现onHandleIntent方法,在这个方法中就可以编写耗时任务。

public class MyIntentService extends IntentService {
    private static final String TAG = "MyIntentService";

    public MyIntentService() {
        super("MyIntentService");//调用父类有参构造函数
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "Thread id is " + Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: ");
    }
}

BroadCastReceiver

广播分两种: 有序广播和无序广播

无序广播:sendBroadcast()方法发送的广播为无序广播,无序广播逻辑上可以被任何广播接受者接收到,优点是效率高。缺点是一个接收者不能将处理结果传递给下一个接收者,传递的数据在传输过程中不能被修改,并无法终止广播的传播。

有序广播:sendOrderedBroadcast()方法发送的广播为有序广播,有序广播依次传播,列如有三个广播接收者A,B,C, 优先级是A>B>C, 此时发送一条广播,那这个消息先传给A,再传给B, 最后传给C,每个接收者都有权终止广播,比如B终止广播,C就无法接受到, 此外A接收到广播后可以对结果对象进行操作,当广播传给B时,B可以从结果对象中获取A存入的数据。

在通过context.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler,initialCode, initialData, initialExtras);时我们可以指定resultReceiver广播接收者,这个接收者我们可以认为是最终接收者,通常情况下如果比他优先级更高的接收者如果没有终止广播,那么他的onReceive方法会被执行两次,第一次是正常的按照优先级顺序执行,第二次是作为最终接收者接收,如果比他优先级高的接收者终止了广播,那么他依然能接收到广播。

BroadcastReceiver有两种注册方法

在Androidmainfest中注册广播接收者称为静态注册

在代码中注册称为动态注册

静态注册的广播接收者只要app在系统中注册则可以一直接收到广播消息,

动态注册的广播接收者当注册的activity或Service销毁了那么就接收不到广播了

注意:

1.BroadcastReceiver的生命周期是非常短暂的,在接收广播的时候创建,onReceiver()方法结束之后销毁

2. 广播接收者中不要做一些耗时的工作,否则会弹出Application No Response(应用无响应anr)错误对话框,,一般耗时的较长的操作最好放在服务中完成。

3.最好也不要在广播接收者中创建子线程做耗时操作,因为广播接收者被销毁后进程就成为空进程,而空进程很容易被系统杀掉。

相关问题:

1.动态广播注册与销毁在Activity那两个生命周期进行?

onCreate()---onDestory();

2.静态广播与动态广播的区别?特点和应用场景

生存期:静态广播的生存期可以比动态广播的长很多,因为静态广播很多都是用来对系统时间进行监听,比如我们可以监听手机开机。而动态广播会随着context的终止而终止

优先级:动态广播的优先级比静态广播高

使用方式:动态广播无需在AndroidManifest.xml中声明即可直接使用,也即动态;而静态广播则需要,有时候还要在AndroidManifest.xml中加上一些权限的声明

3.有时候基于数据安全考虑,我们想发送广播只有自己(本进程)能接收到,怎么处理?

使用本地广播

4.Android 中用广播来更新 UI 界面好吗?

大多数情况下可以采用广播来更新UI,但是不能太过耗时,还有频繁更新UI,使用广播是不推荐的。

5.BroadcastReceiver EventBus 有啥不同?

如果是和 Android 系统相关的通知,我们还得选择本地广播。广播相对于其他实现方式,是很重量级的,它消耗的资源较多。它的优势体现在和 SDK 的紧密联系,onReceive() 方法自带了 Context 和 Intent 参数,所以在一定意义上实现了便捷性,但如果对 Context 和 Intent 应用很少或者说只做很少的交互的话,使用广播真的就是一种浪费!!!

EventBus优点:

调度灵活,使用简单,快速且轻量;

缺点:EventBus 最大的缺点在于其逻辑性

和Android的 BroadcastReceiver/Intent 不同,EventBus 用了标准java类的事件,提供了更方便的API。当你要用很多case去区分事件时,EventBus很一个很好的解决方案,你不需要大量设置intent、给intent添加extras、实现大量broadcast receivers、再获得intent、从intent里提取数据。而且,EventBus 的开销低得多。

6.8.0之后广播的变化

Android 8.0的平台上,应用不能对大部分的广播进行静态注册

ContextProvider

(1)android平台提供了ContentProvider使一个应用程序的指定数据集提供给其他应用程序。其他应用可以通过ContentResolver类从该内容提供者中获取或存入数据。

(2)只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处是统一数据访问方式。

(3)ContentProvider实现数据共享。ContentProvider用于保存和获取数据,并使其对所有应用程序可见。这是不同应用程序间共享数据的唯一方式,因为android没有提供所有应用共同访问的公共存储区。

(4)开发人员不会直接使用ContentProvider类的对象,大多数是通过ContentResolver对象实现对ContentProvider的操作。

(5)ContentProvider使用URI来唯一标识其数据集,这里的URI以content://作为前缀,表示该数据由ContentProvider来管理。

重点理解和应用Content Provider API涉及到的相应参数:

利用这些参数和相应API完成数据的筛选。

/**

* @param uri 指定查询应用程序下具体表

* @param projection 指定查询的列名

* @param selection 指定where的约束条件

* @param selectionArgs 为where中的占位符提供具体的值

* @param sortOrder 指定查询的排序方式

*/

@Override

public Cursor query(Uri uri, String[] projection, String selection,

String[] selectionArgs, String sortOrder)

猜你喜欢

转载自blog.csdn.net/qq_34149526/article/details/81747986