Android基础知识总结

Activity

先附上图(来自官方文档)

activity_lifecycle.png

生命周期方法介绍:

  • onCreate

    作为Activity的第一个生命周期方法,表示正在被创建,此方法一般用来加载布局文件和初始化一些控件(findviewbyId),在Activity的生命周期中它只会执行一次

  • onStart

    Activity正在启动,在此期间,用户可以在屏幕上看到Activity,但是它不在前台,无法与用户进行交互;该方法时Activity重新回到前台第一个要回调的方法,与它相应的方法时onStop

  • onResume

    Activity已经进入运行状态,用户可以与它进行交互,和它相应的是onPause,当Activity切换到后台时,一般都要在onPause中去释放资源,然后重新回到前台时需要在onResume中重新恢复已经释放调的资源,例如Camera的开启与关闭

  • onPause

    Activity可见但不在前台,因为无法与用户进行交互
    该方法需要持久化用户数据、暂停动画、暂停正在播放的视频等不太耗时的操作

  • onStop

    Activity即将停止,不可见耗时的清理工作要放在onStop方法中;如果在系统内存不够时,系统接下来很快会销毁掉该Activity,在极端情况下,直接 kill Activity 且不执行onDestroy()函数。所以务必在onStop()函数中就清理掉可能引起内存泄露的资源,当然更极端的时系统内存已严重不足,导致系统无法保留该进程的情况下,onStop() 可能都不会被执行

  • onDestory

    Activity即将被销毁
    很多情况下 Activity 是不需要定义这个函数,因为在onPause()和onStop()中,大多数的清理工作都已经完成了。但是,如果在onCreate()中定义了后台线程,或者可能引起内存泄露的代码,那就需要在onDestroy()中清理,如,静态对象持有其他Activity的引用,广播注销等操作;

  • onRestart

    Activity正在被重新启动
    在原Activity没有销毁时重新要回到该Activity时会回调该方法,紧接着会回调onStart方法,一般在该方法中恢复用户数据;

Activity生命周期变化

  • 启动Activity

    onCreate() > onStart() > onResume()

  • 调用finish方法/按back键

    onPause() > onStop() > onDestory()

  • 按Home键/启动另一个Activity

    onPause() > onStop()

  • 从ActivityA进入ActivityB,再按back键返回A,A中的生命周期变化

    onRestart() > onStart() > onResume()

Intent传递数据

使用Intent进行Activity跳转时,可以携带参数,将需要的数据传递给目标Activity,IntentputExtra(...)方法可
以传递基本数据和基本数据的数组,putExtras(...)方法可以传递对象,前提是对象需要实现序列化,即实现SerializableParcelable。例如:

  • 向目标Activity传递基本数据,如下传递int类型的数据

    intent.putExtra("type",1);
    
  • 向目标Activity传递对象

    实现序列化
    class A implements Serializable{
     ...
     ... 
    }
    使用Bundle进行传递
    Bundle bundle = new Bundle();
    bundle.putSerializable("obj",new A());
    intent.putExtras(bundle);
    

Activity的启动模式

首先涉及到一个任务栈的概念,在Android中每启动一个Activity,该Activity就会被放入任务栈的栈顶,当在代码中调用finish方法或者按back键时,栈顶的Activity就会出栈,因此任务栈所遵循的原则就是先进后出,而每次启动一个Activity,无论之前是否已经启动过此Activity,系统都会实例化一个Activity,并把它放到栈顶,这样就造成了在任务栈中有多个相同的Activity实例,这样就比较浪费内存,为了解决这个问题,谷歌引入了启动模式这个概念,目前有四种启动模式(在清淡文件中指定launchMode属性):

standard、singleTop、singleTask、singleInstance

  • standard(标准模式)

系统的默认启动模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。在这种模式下,谁启动了这个Activity,那么这个Activity就会运行在启动它的那个Activity所在的栈中。

  • singleTop(栈顶复用模式)

这种模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity将不会重新创建,而它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。另外需要注意的是:该ActivityonCreateonStart并不会被系统调用,因为它并没有发生改变。如果新的Activity不是位于栈顶,那么新的Activity仍会被重新创建。

  • SingleTask(栈内复用模式)

这是一种单实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和singleTop一样,系统也会回调onNewIntent。当一个具有singleTask模式的Activity请求启动后,比如ActivityA,系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放到栈中。如果存在A所需的任务栈,这时要看A是否在栈中有实例存在,如果有实例存在,那么系统就会把A调到栈顶并调用它的onNewIntent方法,如果实例不存在,就创建A的实例并把A压入栈中。

  • singleInstance(单实例模式)

这是一种加强后的singleTask模式,它除了具有singleTask模式的所有特性外,还加强了一点,那就是具有此种模式的Activity只能单独地位于一个任务栈中,换句话说,比如ActivityAsingleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。

Intent的Flags

  • FLAG_ACTIVITY_NEW_TASK

    这个标记位的作用是为Activity指定singleTask启动模式,其效果和在XML中指定该启动模式相同

  • FLAG_ACTIVITY_SINGLE_TOP

    这个标记位的作用是为Activity指定singleTop启动模式,其效果和在XML中指定该启动模式相同

  • FLAG_ACTIVITY_CLEAR_TOP

    具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。这个标记位一般会和singleTask启动模式一起出现,在这种情况下,被启动Activity的实例如果已经存在,那么系统就会调用它的onNewIntent。如果被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。而singleTask启动模式默认就具有此标记位的效果。

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

    具有这个标记的Activity不会出现在历史Activity的列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用。它等同于在XML中指定Activity的属性android:excludeFromRecents="true"

Activity数据的保存与恢复

OnSaveInstanceState

当Activity被系统异常杀死后,会调用onSaveInstanceState(Bundle outState)方法,此方法中有一个参数Bundle,开发者可以使用它来保存当前的临时数据,那么到底是什么情况下此方法会被调用呢?

此方法被调用会遵循一个原则,就是系统未经你同意时销毁你的Activity,一般会有如下几种情况:

  • 按下Home键
  • 长按Home键,选择打开其它程序
  • 按下电源键
  • 从一个Activity中启动另一个Activity
  • 切换屏幕方向(如果不指定configchange属性),在屏幕切换前,系统会销毁该Activity,切换完成后又会重新创建这个Activity,因此onSaveInstanceState一定会执行

OnRestaoreInstanceState

首先此方法和onSaveInstanceState方法不一定是成对出现的,
OnRestoreInstanceState被调用的前提是: Activity确实被销毁了,而仅仅是有这种可能的情况下,该方法并不会被调用。

例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行

另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原。 还有onRestoreInstanceState在onstart之后执行。

应用被强杀,如何处理?

  • 如何判断应用被强杀

    在Application中定义一个static常量,赋值为-1,在欢迎界面改为0,如果被强杀,application重新初始化,在父类Activity判断该常量的值

  • 应用被强杀如何解决

    如果在每一个Activity的onCreate里判断是否被强杀,冗余了,封装到Activity的父类中,如果被强杀,跳转回主界面,如果没有被强杀,执行Activity的初始化操作,给主界面传递intent参数,主界面会调用onNewIntent方法,在onNewIntent跳转到欢迎页面,重新来一遍流程。

IntentFilter匹配规则

  • IntentFilter的过滤信息有actioncategorydata

    为了匹配过滤列表,需要同时匹配过滤表中的 action、category、data 信息,否则匹配失败。一个过滤列表中的 action、category、data 可以有多个,只有一个Intent同时匹配action类别、category类别、data类别才算完全匹配,只有完全匹配才能成功启动目标Activity。另外一点,一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。

  • 详细的匹配规则可在此链接查看:

    https://www.jianshu.com/p/d2446661cd4c

Fragment

先附上图

fragment_lifecycle

Activity&Fragment 关系图如下

activity&fragment

各生命周期方法介绍

  • onAttach

    当该Fragment被添加到Activity时回调,
    该方法只会被调用一次。

  • onCreate

    创建Fragment时被回调。该方法只会被调用一次。

  • onCreateView

    创建Fragmetn的View组件时回调,并显示该方法返回的View组件。

  • onActivityCreate

    当Fragment所依附的Activity被启动完成后回调该方法

  • onStart

    启动Fragment时被回调

  • onResume

    Fragment进入运行状态或者说恢复Fragment时被回调,在onStart方法后一定会回调此方法

  • onPause

    暂停Fragment时被回调

  • onStop

    停止Fragment时被回调

  • onDestroyView

    销毁该Fragment中的View组件时调用

  • onDestroy

    销毁Fragment时被回调,该方法只会被调用一次

  • onDetach

    将该Fragment从Activity中删除、替换完成时回调该方法,在onDestroy方法后一定会回调onDetach方法,该方法只会被调用一次

将Fragment添加到Activity中有如下两种方式

  • 在布局文件中使用<fragment.../>元素添加Fragment,<fragment.../>元素的android:name属性指定Fragment的实现类

  • 在Java代码中通过FragmentTransaction对象的add()replace()方法来添加Fragment

Fragment与Activity交互方式

  • Fragment获取它所在的Activity

    调用Fragment的getActivity()方法即可返回它所在的Activity

  • Activity获取它包含的Fragment

    调用Activity关联的FragmentManager的findFragmentById(int id)findFragmentByTag(String tag)方法即可获取指定的Fragment

Fragment与Activity数据传递

  • Activity向Fragment传递数据

    创建Bundle数据包,调用Fragment的setArguments(Bundle bundle)方法

  • Fragment向Activity传递数据或Activity需要在Fragment运行中进行实时通信

    在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口,通过该回调接口将数据传给Activity

Fragment管理与Fragment事务

  • 使用findFragmentById()findFragmentByTag()方法来获取指定Fragment
  • 调用popBackStack()方法将Fragment从后台栈中弹出(模拟用户按下Back键)
  • 调用addOnBackStackChangedListener()注册一个监听器,用于监听后台栈的变化
  • 如果需要添加、删除、替换Fragment,则需要借助于FragmentTransaction对象

ContentProvider

自定义ContentProvider

需要实现以下几个方法

  • public boolean onCreate()

    该方法在ContentProvider创建后会被调用,其它应用程序第一次访问ContentProvider时,该ContentProvider会被创建出来,并立即回调该onCreate()方法

  • public Uri insert(Uri uri,ConentValues values)

    根据该Uri插入values对应的数据

  • public int delete(Uri uri,String selection,String[] selectionArgs)

    根据Uri删除selection条件所匹配的全部记录

  • public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs)

    根据Uri修改selection条件所匹配的全部记录

  • public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder)

    根据Uri查询出selection条件所匹配的全部记录,其中progection就是一个列名列表,表明只选择出指定的数据列

UriMatcher 关联Uri和Code

使用它的addUri方法将Uri和Code关联到一起,外界通过Uri获取对应的Code,然后根据Code去访问对应的表

BroadCastReceiver

注册广播的两种方式

  • 静态注册

    在AndroidManifest.xml文件中使用<receiver.../>元素完成注册
  • 动态注册

    在Java代码中通过Context.registerReceiver()方法注册BroadcastReceiver

有序广播

  • 普通广播

    是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,效率比较高。缺点是不可以将处理结果传递给下一个接收者,并且无法终止Broadcast Intent的传播

  • 有序广播

    Ordered Broadcast的接收者将按预先声明的优先级依次接收Broadcast。优先级声明在<intent-filter.../>元素的android:priority属性中,数值越大优先级别越高,在java代码中使用IntentFilter对象的setPriority()设置优先级别。Ordered Broadcast接收者可以终止Broadcast Intent的传播,Broadcast Intent的传播一旦终止,后面的接收者就无法接收到Broadcast。在onReceiver(...)方法中通过abortBroadcast()方法来取消Broadcast的继续传播。

发送广播的两种方法

  • sendBroadcast()
    发送 Normal Broadcast

  • sendOrderedBroadcast()
    发送 Ordered Broadcast

通过代码Bundle bundle = getResultExtras(true)可以获取上一个接收者存入的数据。

  • 提示
    系统收到短信,发出的Broadcast属于Ordered Broadcast。如果想阻止用户收到短信,可以通过设置优先级,让自定义的BroadcastReceiver先获取到Broadcast,然后终止Broadcast。

Service

生命周期

  • startService方式启动服务,client的生命周期与service没有任何关联,在client中通过stopService()或在service内部通过stopSelf()方式来停止此服务,生命周期图如下所示:
  • bindService方式启动服务,使用此方式将client和service建立绑定关系,当client销毁后,service也将被销毁,通过在client中调用unbindService()方式来解除client与service之间的绑定关系,而Client与Service之间的通信主要通过Binder对象来实现,在Service内部的onBind()方法中返回此Binder对象,生命周期图如下所示:

注意
有一种特殊的情况,就是当同时以startService()bindService()两种方式开启服务时,在销毁此服务的时候需要同时调用stopService()unbindService()方法来停止服务。

onStartCommand返回值

  • START_STICKY
    如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由 于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传 递到service,那么参数Intent将为null;
  • START_NOT_STICKY
    “非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务;
  • START_REDELIVER_INTENT
    重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入;
  • START_STICKY_COMPATIBILITY
    START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

如何保证Service不被杀死

Service 设置成 START_STICKY
service被杀死后会重启(等待5秒钟左右),重传intent,保证与重启前一样

提升Service优先级

  • 在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。(目前好像这个属性只对broadcast有效,对于service可能无效)

提升Service进程优先级

  • Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收
  • 当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以在startForeground()使用startForeground()将service放到前台状态。这样在低内存时被kill的几率会低一些。
  • 【注意】在极低内存的压力下,service还是会被kill掉的,并且不一定会重启

onDestory方法里重启service

  • service +broadcast 方式,就是当service走onDestory()的时候,发送一个自定义的广播,当收到广播的时候,重新启动service
  • 也可以直接在onDestroy()里startService
  • 当使用类似口口管家等第三方应用或是在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容