activity启动->onCreate()->onStart()->onResume()
点击home键回到主界面(activity不可见)->onPause()->onStop()
当我们再次回到原activity时->onRestart()->onStart()->onResume()
退出当前activity时->onPause()->onStop()->onDestroy()
onCreate :Activity第一次被实例化的时候系统会调用,整个生命周期只调用1次该方法。
通常用于初始化设置: 1、为Activity设置所要使用的布局文件。2、为安卓控件绑定监听器等静态的设置操作。
onStart(可见不可交互
):当Activity可见未获得用户焦点不能交互时系统会调用。
onResume(可见可交互
) :当Activity和用户发生交互的时候,触发该方法。
onPause (有一点可见不能交互
):当一个正在前台运行的Activity因为其他的Activity需要前台运行而转入后台运行的时候,触发该方法。
onStop(不可见不能交互
):当Activity被其他的Activity完全覆盖不可见时,触发该方法,如果内存紧张,系统会直接结束这个Activity,而不会触发 onStop 方法。
onRestart (由不可见到可见
):当处于停止状态的Activity需要再次展现给用户的时候,触发该方法。
onDestroy :当Activity(用户调用finish()或系统由于内存不足)被系统销毁时调用,(整个生命周期只调用1次)用来释放onCreate ()方法中创建的资源,如结束线程,清空数据,注销广播等。和 onStop 方法一样,如果内存紧张,系统会直接结束这个Activity而不会触发该方法。
具体区别 https://blog.csdn.net/superjunjin/article/details/44674917
参考自:https://blog.csdn.net/qinxiandiqi/article/details/51744782
android对于所有进程的处理态度都是尽可能不杀死
。然而,资源总共就那么多,要是对所有进程都保持宽容的话,资源总会有消耗殆尽的时候。因此,在内存不足的情况,android系统需要根据一定的策略,选择性的杀死部分进程。这个策略就是对所有的进程标记优先级,优先级低的先杀死
。
android将进程的优先级分为5个层次,按照优先级由高到低排列如下:
(1)前台进程(Foreground process)。
它表明用户正在与该进程进行交互操作
,android系统依据下面的条件来将一个进程标记为前台进程:
一般情况下,不会有太多的前台进程
。杀死前台进程是操作系统最后无可奈何的做法。当内存严重不足的时候,前台进程一样会被杀死。
(2)可见进程(Visible process)。
它表明虽然该进程没有持有任何前台组件
,但是它还是能够影响到用户看得到的界面。android系统依据下面的条件将一个进程标记为可见进程:
(3)服务进程(Service process)。
除了符合前台进程和可见进程条件的Service,其它的Service都会被归类为服务进程。
(4)后台进程(Background process)。
持有不可见Activity(调用了onStop()方法)的进程即为后台进程
。通常情况下都会有很多后台进程,当内存不足的时候,在所有的后台进程里面,会按照LRU(最近使用)规则,优先回收最长时间没有使用过的进程
。
(5)空进程(Empty process)。不持有任何活动组件的进程
。保持这种进程只有一个目的,就是为了缓存,以便下一次启动该进程中的组件时能够更快响应
。当资源紧张的时候,系统会平衡进程缓存和底层的内核缓存情况进行回收。
如果一个进程同时满足上述5种优先级中的多个等级条件,android系统会优先选取其中最高的等级作为该进程的优先级
。例如,一个进程持有一个Service(服务进程等级)和一个前台Activity(前台进程等级),那么操作系统会将这个进程标记为前台进程。
另外需要注意的是,如果一个进程为另外一个进程提供服务,那么这个进程的优先级不会低于享受服务的进程
。例如,假设进程A中的content provider为进程B提供服务,或者进程A中有一个Service与进程B中的组件进程绑定,那么进程A的优先级至少要与进程B一致,或者高于进程B。
参考自:https://blog.csdn.net/mynameishuangshuai/article/details/51491074
实际应用时,取类的TaskId查看所属栈id
,类的hashCode查看类实例id
(1)standard-标准模式
这个模式是默认
的启动模式,即标准模式。每次启动一个Activity都会重写创建一个新的实例
,不管这个实例存不存在,这种模式下,谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中
。这个Activity它的onCreate(),onStart(),onResume()方法都会被调用。
(2)singleTop-栈顶复用模式
这个模式下,如果新的activity已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent方法会被调用
(onCreate(),onStart()方法不会被调用),通过此方法的参数我们可以去除当前请求的信息。如果栈顶不存在该Activity的实例,则情况与standard模式相同。
taskAffinity
standard和singleTop启动模式都是在原任务栈中新建Activity实例,不会启动新的Task,即使你指定了taskAffinity属性
。
那么什么是taskAffinity属性呢,可以简单的理解为任务相关性。
没明白
)(3)singleTask-栈内复用模式
这个模式十分复杂,有各式各样的组合。在这个模式下,如果栈中存在这个Activity的实例就会复用这个Activity
,不管它是否位于栈顶,复用时,会将它上面的Activity全部出栈
,并且会回调该实例的onNewIntent方法。其实这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定
。如果这个任务栈不存在,则会创建这个任务栈。
singleTask启动模式启动Activity时,首先会根据taskAffinity去寻找当前是否存在一个对应名字的任务栈
此外,我们可以将两个不同App中的Activity设置为相同的taskAffinity,这样虽然在不同的应用中,但是Activity会被分配到同一个Task中去。
(4)singleInstance-全局唯一模式
该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性
,即整个系统中就这么一个实例,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
总结:
standard,创建一个新的Activity。
singleTop,栈顶不是该类型的Activity,创建一个新的Activity。否则,onNewIntent。
singleTask,回退栈中没有该类型的Activity,创建Activity,否则,onNewIntent+ClearTop。
singleInstance,回退栈中,只有这一个Activity,没有其他Activity。
应用场景:
参考自:https://blog.csdn.net/qq_35114086/article/details/52614714
参考自:https://blog.csdn.net/CodeEmperor/article/details/50481726
singleTop
1,适合接收通知启动的内容显示页面。
比如新闻客户端收到了100个推送,你每次点一下推送他都会走一遍某个activiy(显示新闻只用一个activity,只是内容不同而已)的oncreate,onstart,代价就是创建了那么多的activity(不要以为只有推送,比如qq消息提醒)
a,耗内存
b, 走了100次的跳转动画 ,也是醉了
2,某些业务需求是自己的activity跳转到自己的。
比如 歌曲搜索 你又不会用actionbar,toolbar,那就在activity上面弄个假的呗,搜索完了自己跳转自己现实搜索结果,那就直接用该模式,变化都在onNewIntent()里面对控件进行赋值之类的。而且也没有跳转动画,人们以为这个activity没有动了,多high。
singleTask
适合作为程序入口点。
例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
singleInstance
适合需要与程序分离开的页面。
例如闹铃提醒,将闹铃提醒与闹铃设置分离。打电话 接通的时候。地图显示的时候。
他们都有一个特点 就是你做完这件事了都会返回到上一界面 而没有下一界面。
singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,再次启动,首先打开的是B。(ac在一个栈,退出c后,退出a,退出ac的栈,再退出b,最后b置于栈顶
)
http://stackoverflow.com/questions/2626218/examples-for-android-launch-modes
参考自:android-Scheme与网页跳转原生的三种方式
(1)什么是 URL Scheme?
android中的scheme是一种页面内跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便跳转app中的各个页面;通过scheme协议,服务器可以定制化告诉App跳转那个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等
。
(2)URL Scheme应用场景:
客户端应用可以向操作系统注册一个 URL scheme(在activity中添加scheme的信息
),该 scheme 用于从浏览器或其他应用中启动本应用。通过指定的 URL 字段,可以让应用在被调起后直接打开某些特定页面,比如商品详情页、活动详情页等等。也可以执行某些指定动作,如完成支付等。也可以在应用内通过 html 页来直接调用显示 app 内的某个页面。综上URL Scheme使用场景大致分以下几种:
服务器下发跳转路径,客户端根据服务器下发跳转路径跳转相应的页面
H5页面点击锚点,根据锚点具体跳转路径APP端跳转具体的页面
APP端收到服务器端下发的PUSH通知栏消息,根据消息的点击跳转路径跳转相关页面
APP根据URL跳转到另外一个APP指定页面
例:大型公司通过其热门app的一个链接跳转到其公司的其他app(微信-->腾讯新闻)
深入学习:Android产品研发(十一)–>应用内跳转Scheme协议
Fragment有自己的生命周期,但是不能独立使用,要加载到activity中使用。
优点
(1)fragment相比activity更节省内存。
(2)能动态灵活的加载到Activity中去配合viewpager使用,UI切换更方便舒适。
(1)静态加载,fragment作为标签加载到activity的布局文件中
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
(2)动态加载
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
DemoFragment fragment = new DemoFragment();
fragmentTransaction.add(R.id.content, fragment);//容器资源作为标志位,把fragment添加到对应的位置
fragmentTransaction.addToBackStack("DemoFragment");
fragmentTransaction.commit();
FragmentPagerAdapter适用于页面较少的情况
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
mCurTransaction.detach((Fragment)object);
}
FragmentStatePagerAdapter适用于页面较多的情况,每次切换回收内存
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment)object).getView());
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
mSavedState.set(position, fragment.isAdded()
? mFragmentManager.saveFragmentInstanceState(fragment) : null);
mFragments.set(position, null);
mCurTransaction.remove(fragment);
}
参考自:https://blog.csdn.net/i_wait_for_you/article/details/70240075
https://www.cnblogs.com/LangZXG/p/6501839.html
https://blog.csdn.net/superjunjin/article/details/44783279
由于Fragment依赖Activity的存在而存在,故在创建时Activity生命周期中的方法均先于Fragment生命周期中的方法执行;相反,在销毁时,是先执行Fragment生命周期中的方法再执行Activity生命周期中的方法。
在Fragment中调用Activity中的方法 getActivity
在Fragment中调用Fragment中的方法 接口回调
在Fragment中调用Fragment中的方法 findFragmentById
在Fragment间利用广播
参考自 https://blog.csdn.net/u012702547/article/details/49786417
参考自 https://blog.csdn.net/harvic880925/article/details/44927375(详细清晰 写的太棒了)
add:添加Fragment,置于栈顶
replace:替换Fragment,清空对应容器Fragment,置于栈顶
remove:移除Fragment,显示下层Fragment
addToBackStack:添加事务
到回退栈,置于栈顶
popBackStack:将最上层的事务
弹出回退栈(根据具体参数,可以回退到对应的事务)
Fragment回滚以事务
(FragmentTransaction)为单位,一个事务可能包含一个或多个Fragment
Fragment拓展阅读
Fragment全解析系列(一):那些年踩过的坑
Square:从今天开始抛弃Fragment吧!
service是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件,可由其他组件启动,一旦启动可在后台长时间运行,即使启动它的组件已经被销毁,也不会受影响。
参考自:https://blog.csdn.net/wei_chong_chong/article/details/52251193
1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。thread是由本应用程序托管
。可以用 Thread 来执行一些异步的操作。可做耗时操作
。
2). Service:Service 是android的一种机制,系统的组件,它由系统进程托管(servicemanager)
。当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。不可做耗时操作
,如果要做,service中添加Thread去做
Thread的使用
典型的应用中,Thread可以在以下三个位置被创建,不同的位置,其生命周期不一样,所以,我们应该根据该Thread的目标生命周期来决定是在Service中创建Thread还是在Activity中创建它。
(1) 在Activity中被创建
这种情况下,一般在onCreate时创建,在onDestroy()中销毁,否则,Activity销毁后,Thread是会依然在后台运行着。
这种情况下,Thread的生命周期即为整个Activity的生命周期。所以,在Activity中创建的Thread只适合完成一些依赖Activity本身有关的任务,比如定时更新一下Activity的控件状态等
。
核心特点:该Thread的就是为这个Activity服务的,完成这个特定的Activity交代的任务,主动通知该Activity一些消息和事件,Activity销毁后,该Thread也没有存活的意义了。
(2)在Application中被创建
这种情况下,一般自定义Application类,重载onCreate方法,并在其中创建Thread,当然,也会在onTerminate()方法中销毁Thread,否则,如果Thread没有退出的话,即使整个Application退出了,线程依然会在后台运行着。
这种情况下,Thread的生命周期即为整个Application的生命周期。所以,在Application中创建的Thread,可以执行一些整个应用级别的任务,比如定时检查一下网络连接状态等等
。
核心特点:该Thread的终极目标是为这个APP的各个Activity服务的,包括完成某个Activity交代的任务,主动通知某个Activity一些消息和事件等,APP退出之后该Thread也没有存活的意义了。
以上这两种情况下,Thread的生命周期都不应该超出整个应用程序的生命周期,也就是,整个APP退出之后,Thread都应该完全退出,这样才不会出现内存泄漏或者僵尸线程。那么,如果你希望整个APP都退出之后依然能运行该Thread,那么就应该把Thread放到Service中去创建和启动了。
(3)在Service中被创建
这是保证最长生命周期的Thread的唯一方式,只要整个Service不退出,Thread就可以一直在后台执行,一般在Service的onCreate()中创建,在onDestroy()中销毁。
所以,在Service中创建的Thread,适合长期执行一些独立于APP的后台任务,比较常见的就是:在Service中保持与服务器端的长连接
。
(1),startService
(2),bindService
android开发之service详解
在android中,broadcast是一种广泛运用在应用程序内部或之间传输信息的机制,Android中要发送的广播内容是一个Intent,这个Intent中可以携带我们要传送的数据。
参考自:https://www.cnblogs.com/lwbqqyumidi/p/4168017.html
1.同一app内部的同一组件内的消息通信(单个或多个线程之间);(可用handler解决
)
2.同一app内部的不同组件之间的消息通信(单个进程);(可用EventBus
)
3.同一app具有多个进程的不同组件之间的消息通信;
4.不同app之间的组件之间消息通信;
5.Android系统广播在特定情况下与App之间的消息通信。
后三种常用广播解决
参考自:https://blog.csdn.net/carson_ho/article/details/53160580
参考自:https://blog.csdn.net/u012702547/article/details/46955787
(1),自定义广播接收器BroadcastReceiver,并复写onReceive方法
(2),通过Binder机制向AMS(Activity Manager Service
)进行注册
(3),广播发送者通过Binder机制向AMS发送广播
(4),AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般是activity)相应的消息循环队列中
(5),消息循环执行,拿到此广播,回调BroadcastReceiver的onReceive方法
具体说明 https://blog.csdn.net/carson_ho/article/details/53160580
源码分析
WebView是一个基于webkit引擎、展现web页面的控件。Android的Webview在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用了Chrome。
WebView控件功能强大,除了具有一般View的属性和设置外,还可以对url请求、页面加载、渲染、页面交互进行强大的处理。
webView.onResume();激活WebView为活跃状态
webView.onPause(); 暂停WebView所有动作
webView.pauseTimers();结合webView.onPause()使用
webView.resumeTimers();结合
webView.onResume()使用
总结:onResume和onPause是针对当前webview,pauseTimers和resumeTimers是针对应用所有webview,常配套使用
参考自https://blog.csdn.net/goldenfish1919/article/details/38435799
参见
https://blog.csdn.net/carson_ho/article/details/52693322
常见方法1:shouldOverrideUrlLoading()
作用:打开网页时不调用系统浏览器, 而是在本WebView中显示;在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作。
常见方法2:onPageStarted()
作用:开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。
常见方法3:onPageFinished()
作用:在页面加载结束时调用。我们可以关闭loading 条,切换程序动作。
常见方法4:onLoadResource()
作用:在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
常见方法5:onReceivedError()
作用:根据错误类型,处理错误信息
常见方法6:onReceivedSslError()
作用:处理https请求
常见方法1: onProgressChanged()
作用:获得网页的加载进度并显示
常见方法2: onReceivedTitle()
作用:获取Web页中的标题
参考自:https://blog.csdn.net/carson_ho/article/details/64904691
对于Android调用JS代码的方法有2种:
1. 通过WebView的loadUrl()
2. 通过WebView的evaluateJavascript()
对于JS调用Android代码的方法有3种:
1. 通过WebView的addJavascriptInterface()进行对象映射
2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
(1),动态添加WebView,对传入WebView中使用的Context使用弱引用
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mWebView = new WebView(getApplicationContext());
mWebView.setLayoutParams(params);
mLayout.addView(mWebView);
@Override
protected void onDestroy() {
if (mWebView != null) {
mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
(2),独立进程
此方法简单暴力,就是开启单独一个进程给WebView,不过可能涉及到进程间通信,这会比较麻烦。
WebView使用完后直接干掉此进程,使app的主进程减少一些内存容量。
(1),WebView的 onPageFinished方法
问题描述: WebView加载的页面完成时会回调onPageFinished方法,但是此方法有很多坑,它会判断此网页是否真的加载完毕,若此时在加载过程中产生跳转,此方法会被调用无数次
。
解决方法:所以当你的WebView需要加载各种网页并且需要在网页上完成一些操作时,推荐使用WebView 的 onProgressChanged 方法,此方法相较于之前的更为稳定、靠谱。
(2),WebView带来的 后台耗电隐患
问题描述:当我们使用到WebView加载网页时,WebView会自己开启线程,如果在使用完后没有彻底销毁,这些残余的线程会一直在后台运行导致应用程序大幅度耗电。
解决方法:这里提供一个方法,有些暴力,仅做思考:在Activity的onDestory方法中调用System.exit直接把虚拟机关闭。
(3),WebView硬件加速导致 页面渲染问题
问题描述:硬件加速开始于Android 系统3.0,开启硬件加速后,WebView渲染页面加速,拖动起来效果更加顺滑。但是这里有一个问题,容易出现加载页面白块、界面闪烁的现象。
解决方法:设置WebView暂时关闭硬件加速
。
(4),jsbridge
在此简介其概念:它通过JavaScript来构建桥,桥的其中一端是Web端,另一端是客户端native,而搭桥的目的是为了本地native端调用Web的js代码,同时Web端可以调用本地native代码,仅做了解即可。
是H5页面中全局对象window的一个属性,形如:
var JSBridge = window.JSBridge || (window.JSBridge = {});
https://blog.csdn.net/ejinxian/article/details/66971175
(5),WebView 的 addJavascriptInerface方法带来的 安全漏洞
Android API level 16以及之前的版本存在远程代码执行安全漏洞,该漏洞源于程序没有正确限制使用 WebView.addJavascriptInerface方法,远程攻击者可通过使用 Java Reflection API 利用该漏洞执行任意Java对象的方法。
此方法addJavascriptInerface给WebView加入了一个Javascript桥接口,而此桥接口可以通过调用来操纵本地的Java接口。这是前几年WebView出现问题十分显著的一次,攻击者利用反射机制调用未注册的其它Java类,导致操纵JavaScript能力无限增强,攻击者利用此漏洞对客户端任意篡改,甚至进行违法行为。