Activity
Activity A 启动另一个Activity B 会调用哪些方法?
https://blog.csdn.net/speverriver/article/details/78402912
如果B是透明主题的又或则是个DialogActivity呢 ?
https://blog.csdn.net/qq_29092191/article/details/80901610
说下onSaveInstanceState()方法的作用 ? 何时会被调用?
Activity意外被回收,保存数据的作用。用onRestoreInstanceState(Bundle savedInstanceState)获取存的数据,系统onRestoreInstanceState()只有在存在保存状态的情况下才会恢复,因此您不需要检查是否Bundle为空。
按home退出。按home进入其他应用,Aactivity跳转Bactivity,按电源键关闭屏幕,屏幕方向切换。
Activity的四种启动模式、应用场景 ?了解哪些Activity常用的标记位Flags?
http://www.cnblogs.com/claireyuancy/p/7387696.html
onNewIntent触发时机
- standard 被启动就会创建一个新的
- singleTop 栈顶单实例(当该activity处于task栈顶时,可以复用,直接onNewIntent)
- singleTask 栈中单实例(oncreate该activity并销毁在他之上的其他activity)
- singleInstance 全局单实例(应用场景:地图,Activity初始化需要大量资源)
Intent的标志位FLAG:
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具有这个标记的Activity不会出现在历史Activity列表中(这里点击手机除back和home键的另外一个键就会出现recent列表了),当某些情况下我们不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用。它等同于在清单文件xml中指定Activity的属性android:excludeFromRecents = "true";
Intent.FLAG_ACTIVITY_SINGLE_TOP 与加载模式singleTop功能相同
Intent.FLAG_ACTIVITY_CLEAR_TOP 销毁目标Activity和它之上的所有Activity,重新创建目标Activity
Intent.FLAG_ACTIVITY_NEW_TASK
说下 Activity跟window,view之间的关系?
https://blog.csdn.net/u011733020/article/details/49465707
横竖屏切换的Activity生命周期变化?
android5.0:
1.横屏/竖屏---什么也不设置、设置:android:configChanges="orientation|keyboardHidden"或者android:configChanges="orientation"时:
shenm
2.android:configChanges="orientation|keyboardHidden|screenSize"时
只走onConfigurationChanged方法
android8.0
1.横屏/竖屏---什么也不设置
shenm
2.android:configChanges="orientation|keyboardHidden|screenSize"时、android:configChanges="orientation|keyboardHidden"时、android:configChanges="orientation"时:
只走onConfigurationChanged方法
如何启动其他应用的Activity?
首先在调用的时候一定要保证在Manifest.xml中设置被启动Activity的exported=true,否则会报错Activity is not found.
image.png
方法1intent.setComponent
//第一个参数是Activity所在的package包名,第二个参数是完整的Class类名(包括包路径)
Intent intent = new Intent();
ComponentName comp = new ComponentName("com.linxcool","com.linxcool.PlaneActivity");
intent.setComponent(comp);
intent.setAction("android.intent.action.MAIN");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
方法2 intent.setClassName
Intent intent=new Intent();
//包名 包名+类名(全路径)
intent.setClassName("com.linxcool", "com.linxcool.PlaneActivity");
startActivity(intent);
Activity的启动过程?
Fragment
谈一谈Fragment的生命周期 ?与Activity生命周期的不同 ?
ragment中add与replace的区别(Fragment重叠)
https://www.cnblogs.com/genggeng/p/6780014.html
https://blog.csdn.net/qq_34490018/article/details/80205967
实现原理
因为replace()方法是先将存在的Fragment删除再添加新的Fragment,所以内存波动大,网络请求消耗大。
因此我们常用add()方法、hide()和show()方法配合使用,达到Fragment切换效果。如选中想显示的Fragment,先利用hide()方法隐藏所有的Fragment,当Fragment不存在时,利用add()方法添加Fragment;当Fragment存在时,利用show()方法显示选中的Fragment。
Fragment重叠问题
由于内存重启,导致的frgament重叠,其原因就是FragmentState没有保存Fragment的显示状态,即mHidden,导致页面重启后,该值为默认的false,即show状态,所以导致了Fragment的重叠。
那么解决方案就是自己写一些代码去保存fragment的显示状态。
(2)解决方法
在之前,我们先来回顾下两个知识点,一个是onSaveInstanceState()和onRestoreInstanceState()调用机制,另一个是add()方法的参数add(int containerViewId, Fragment fragment, String tag)。tag为Fragment的标识,用于恢复数据时,findFragmentByTag()寻找相关tag标识。
谈谈Activity和Fragment的区别?
1.Activity是系统的四大组件之一,由activityManager管理,生命周期由系统控制。着Activity的生命周期变化,Fragment也随之相应不同的生命周期函数。onAttach(Activity activity) onCreate onCreateView onActivityCreate onStart onResume onPause onStop onDestroyView onDestroy onDetach同时受到activity生命周期的影响,activity onPause Fragment也会执行相应的onPause
2.Fragment是在3.0后引入的组件,由FragmentManager管理,可以由Activity自由控制,引入或者删除,更方便。
3.Activity 代表了一个屏幕的主体,而Fragment可以作为Activity的一个组成元素。Fragment不能脱离Activity而存在,只有Activity才能作为接收intent的载体。其实两者基本上是载体和组成元素的关系
3.由于Fragment是Activity管理,所以在使用的时候,要格外注意,创建之前需要getFragmentByTag或者ById查看一下是否已经有存在的,FragmentManager也跟ActivityManager一样有一个缓存机制。同一个TAG的fragment如果多次被添加到activity中,那么通过getFragmentBytag获取Fragment的时候返回的是最后一次被添加的Fragment4.fragment在显示到销毁的过程中会执行自己的生命周期。
getFragmentManager、getSupportFragmentManager 、getChildFragmentManager之间的区别?
https://blog.csdn.net/qq_34581102/article/details/52793683
FragmentPagerAdapter与FragmentStatePagerAdapter的区别与使用场景?
https://blog.csdn.net/u014763302/article/details/52718642
二者都继承PagerAdapter.
FragmentPagerAdapter的每个Fragment会持久的保存在Fragment Manager中,用户访问过的每一个fragment实例都会保存到内存不销毁。生命周期只走到onDestroyView。
- viewPage.setOffscreenPageLimit()设置的是缓存多少个Fragment的View,但所以Fragment实例会一直缓存不销毁。
- 适用于:显示一些不会变化的View,静态View,不请求网络,Page数量不多;不适合一般app的主页,因为主页tab切换要求保持各Fragment生命周期只会在执行一次。
- 使用场景:
FragmentStatePagerAdapter当页面不可见时,该Fragment就会被销毁,只保留Fragment的状态。生命周期走完。
- viewPage.setOffscreenPageLimit()设置的是缓存多少个Fragment实例(当然包括它的View了),Fragment离开缓存就是执行onDestroy-->onDetach。
- 适用于:Page数量多的情况。其它和FragmentPagerAdapter无差别。
- 使用场景:
总结:当page数量少,用FragmentPagerAdapter;反之则用FragmentStatePagerAdapter;它们两个的Fragment生命周期在ViewPage的切换过程中都会重复执行多次,所以它都不适用于App主页Tab。
Service
Service简介
Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现(或者用系统提供的IntentService,它继承了Service,它处理数据是用自身新开的线程)。【当然你也可以在新的线程中startService,这样Service就不是在MainThread了】
谈一谈Service的生命周期?
https://www.cnblogs.com/huihuizhang/p/7623760.html
Android中Service使用bindService
https://blog.csdn.net/zjws23786/article/details/51865238
Android中startService的使用及Service生命周期
https://blog.csdn.net/oudetu/article/details/79279701
如何保证Service不被杀死 ?
https://blog.csdn.net/chenliguan/article/details/54603611
能否在Service开启耗时操作 ? 怎么做 ?
https://blog.csdn.net/qq_21937107/article/details/79966295
Android IntentService的使用和源码分析
用过哪些系统Service(SystemService)?
https://www.cnblogs.com/huolongluo/p/6340743.html
//判断Wifi是否开启
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
boolean enabled = wm.isWifiEnabled();
// 如果软键盘已经显示,则隐藏
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getWindow().getDecorView().getWindowToken(), 0);
//剪切板
ClipboardManager cm = (ClipboardManager) WebViewActivity.this.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setText(data);
//windown service
public static Point getScreenSize(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Point point = new Point(wm.getDefaultDisplay().getWidth(), wm.getDefaultDisplay().getHeight());
return point;
}
//定位
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
// 通过GPS卫星定位,定位级别可以精确到街(通过24颗卫星定位,在室外和空旷的地方定位准确、速度快)
boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
// 通过WLAN或移动网络(3G/2G)确定的位置(也称作AGPS,辅助GPS定位。主要用于在室内或遮盖物(建筑群或茂密的深林等)密集的地方定位)
boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
//电话
public static String getPhoneNumber(Context mContext) {
TelephonyManager phoneMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
return phoneMgr.getLine1Number();
}
//wifi
public static String getMacAddress(Context mContext) {
WifiManager wifi = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
String address = info.getMacAddress();
if (address != null && address.length() > 0) {
address = address.replace(":", "");
}
return address;
}
//keyguard service
public static boolean screenLocked(Context ctx) {
KeyguardManager mKeyguardManager = (KeyguardManager) ctx.getSystemService(Context.KEYGUARD_SERVICE);
boolean status = mKeyguardManager.inKeyguardRestrictedInputMode();
return status;
}
/**
* 获取手机电量
*
* @param context
* @return
*/
public static int getBatteryLevel(Context context) {
BatteryManager batteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
int battery = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
Log.i("wang", "=b==" + battery);
return battery;
}
了解ActivityManagerService(AMS)吗?发挥什么作用
https://www.cnblogs.com/kevincode/p/3940783.html
https://blog.csdn.net/caohang103215/article/details/79597260
Broadcast Receiver
广播有几种形式 ? 都有什么特点 ?
Android广播分为两个方面:广播发送者和广播接收者。
- 广播发送: 广播中分为 无序广播和有序广播
1.无序广播: 通过Context.sendBroadcast()方法来发送,它是完全异步的。
所有的receivers(接收器)的执行顺序不确定,因此所有的receivers(接收器)接收broadcast的顺序不确定。
这种方式效率更高,但是BroadcastReceiver无法使用setResult系列、getResult系列及abort(中止)系列API
特点:
1、无法终止广播
2、无法修改数据
3、效率更高
2.有序广播:是通过Context.sendOrderedBroadcast来发送,所有的receiver依次执行。
BroadcastReceiver可以使用setResult系列函数来结果传给下一个BroadcastReceiver,通过getResult系列函数来取得上个BroadcastReceiver返回的结果,并可以abort系列函数来让系统丢弃该广播,使用该广播不再传送到别的BroadcastReceiver。
可以通过在intent-filter中设置android:priority属性来设置receiver的优先级,优先级相同的receiver其执行顺序不确定。
如果BroadcastReceiver是代码中注册的话,且其intent-filter拥有相同android:priority属性的话,先注册的将先收到广播。
有序广播,即从优先级别最高的广播接收器开始接收,接收完了如果没有丢弃,就下传给下一个次高优先级别的广播接收器进行处理,依次类推,直到最后。如果多个应用程序设置的优先级别相同,则谁先注册的广播,谁就可以优先接收到广播。
特点:
1、可以终止广播
2、可以修改数据
3.系统广播
Android系统中内置了多个系统广播,只要涉及到手机的基本操作,基本上都会发出相应的系统广播。如:开启启动,网络状态改变,拍照,屏幕关闭与开启,点亮不足等等。每个系统广播都具有特定的intent-filter,其中主要包括具体的action,系统广播发出后,将被相应的BroadcastReceiver接收。系统广播在系统内部当特定事件发生时,有系统自动发出。
广播的两种注册方式 ?
- BroadcastReceiver用于监听被广播的事件,必须被注册,有两种方法:
1、在应用程序的代码中注册
注册BroadcastReceiver:registerReceiver(receiver,filter);
取消注册BroadcastReceiver:unregisterReceiver(receiver);
当BroadcastReceiver更新UI,通常会使用这样的方法注册。启动Activity时候注册BroadcastReceiver,Activity不可见时候,取消注册。
2、在androidmanifest.xml当中注册
<receiver>
<intent-filter>
<action android:name = "android.intent.action.PICK"/>
</intent-filter>
</receiver>
1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。使用这样的方法注册弊端:它会始终处于活动状态,毕竟是手机开发,cpu和电源资源比较少,一直处于活动耗费大,不利。
广播发送和接收的原理了解吗 ?(Binder机制、AMS)
//////////////////////////////////////////////
ContentProvider
ContentProvider了解多少?
四大组件之一
ContentProvider的权限管理?
https://blog.csdn.net/anddlecn/article/details/51733690
ContentProvider、ContentResolver、ContentObserver 之间的关系?
https://blog.csdn.net/weixin_34082177/article/details/85968402
数据存储
描述一下Android数据持久存储方式?
https://www.jianshu.com/p/b64ca52d5d41
IPC(Inter-Process Communication,进程间通信)(重点)
Binder机制
https://blog.csdn.net/carson_ho/article/details/73560642
Android中进程和线程的关系? 区别?
https://blog.csdn.net/u012221046/article/details/78010365
如何开启多进程 ? 应用是否可以开启N个进程 ?
https://droidyue.com/blog/2017/01/15/android-multiple-processes-summary/
https://github.com/qmsggg/qmsggg_BlogCollect/issues/158
性能优化(重点)
性能优化的目的是为了让应用程序App 更快、更稳定 & 更省。具体介绍如下:
更快:应用程序 运行得更加流畅、不卡顿,能快速响应用户操作
更稳定:应用程序 能 稳定运行 & 解决用户需求,在用户使用过程中不出现应用程序崩溃(Crash) 和 无响应(ANR)的问题
更省:节省耗费的资源,包括 内存占有、电池量、网络资源等
内存检测工具
1.Androidstudio用Memory monitor 看内存
2.Allocation Tracker内存分配追踪器,可以方便的检测到内存抖动。
image.png
布局优化
https://www.jianshu.com/p/4e665e96b590
1.选择耗费性能较少的布局:FrameLayout、LinearLayout
ps:宁选择 1个耗费性能高的布局,也不采用嵌套多个耗费性能低的布局
2.减少布局的层级(嵌套):<merge>、<include>
3.合适选择布局类型:完成 复杂的UI效果时,尽可能选择1个功能复杂的布局(如RelativeLayout)完成,而不要选择多个功能简单的布局(如LinerLayout)通过嵌套完成。
4.提高 布局 的复用性
5.使用<ViewStub>减少初次测量 & 绘制时间
6.尽可能少用布局属性 wrap_content:布局属性 wrap_content 会增加布局测量时计算成本,应尽可能少用,所以在已知宽高为固定值时,不使用wrap_content。
内存优化
ANR:
1.尽量避免 Static 成员变量引用资源耗费过多的实例(如 Context)
若需引用 Context,则尽量使用Applicaiton的Context或者使用 弱引用(WeakReference) 代替 强引用 持有实例
2.非静态内部类 / 匿名类
储备知识:
非静态内部类 / 匿名类 默认持有 外部类的引用;而静态内部类则不会
-
非静态内部类的实例 = 静态:若 非静态内部类所创建的实例 = 静态(其生命周期 = 应用的生命周期),会因 非静态内部类默认持有外部类的引用 而导致外部类无法释放,最终 造成内存泄露。
解决方案:
I 将非静态内部类设置为:静态内部类(静态内部类默认不持有外部类的引用)
II 该内部类抽取出来封装成一个单例
III 尽量 避免 非静态内部类所创建的实例 = 静态 -
多线程:AsyncTask、实现Runnable接口、继承Thread类:
储备知识:
多线程的使用方法 = 非静态内部类 / 匿名类;即 线程类 属于 非静态内部类 / 匿名类
泄露原因:
当工作线程正在处理任务的时候遇上外部类需销毁, 由于 工作线程实例 持有外部类引用,将使得外部类无法被垃圾回收器(GC)回收,从而造成 内存泄露
解决方案:
I 将内部类(eg:Thread的子类)设置成 静态内部类
II 当外部类结束生命周期时,强制结束线程,原理:使得工作线程实例的生命周期与外部类的生命周期同步。
3.单例模式
单例模式由于其静态特性,其生命周期的长度 = 应用程序的生命周期。若1个对象已不需再使用,而单例对象还持有该对象的引用,那么该对象将不能被正常回收,从而导致内存泄漏。解决:传递Application的Context,因为Application的生命周期 = 整个应用的生命周期。
4.Handler
储备知识:
主线程的Looper对象的生命周期 = 该应用程序的生命周期;
在Java中,非静态内部类 & 匿名内部类都默认持有外部类的引用。
泄露原因:
当Handler消息队列 还有未处理的消息 / 正在处理消息时,存在引用关系: “未被处理 / 正处理的消息 -> Handler实例 -> 外部类”。
若出现 Handler的生命周期 > 外部类的生命周期 时(即 Handler消息队列 还有未处理的消息 / 正在处理消息 而 外部类需销毁时),将使得外部类无法被垃圾回收器(GC)回收,从而造成 内存泄露。
解决方案:
I 将Handler的子类设置成 静态内部类(同时,还可加上 使用WeakReference弱引用持有Activity实例,因为弱引用的对象拥有短暂的生命周期。在垃圾回收器线程扫描时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存)
II当 外部类(此处以Activity为例) 结束生命周期时(此时系统会调用onDestroy()),清除 Handler消息队列里的所有消息(调用mHandler.removeCallbacksAndMessages(null))
原理:不仅使得 “未被处理 / 正处理的消息 -> Handler实例 -> 外部类” 的引用关系 不复存在,同时 使得 Handler的生命周期(即 消息存在的时期) 与 外部类的生命周期 同步
5.资源对象使用后关闭
泄露原因:
对于资源的使用(如 广播BraodcastReceiver、文件流File、数据库游标Cursor、图片资源Bitmap等),若在Activity销毁时无及时关闭 / 注销这些资源,则这些资源将不会被回收,从而造成内存泄漏
解决方案:
在Activity销毁时 及时关闭 / 注销资源
解决方案:
集合类 添加集合元素对象 后,在使用后必须从集合中删除。
// 释放objectList
objectList.clear();
objectList=null;
webview优化
在客户端刚启动时,就初始化一个全局的WebView待用,并隐藏,当用户访问了WebView时,直接使用这个WebView加载对应网页,并展示。
减少APK包大小
减少应用的耗电量
Java进阶
Java的GC机制 、 分代回收策略
https://www.cnblogs.com/prophet-it/p/7599760.html
-
GC回收机制--如何回收
标记清除算法
清除算法分成2个阶段--标记和清除; 标记阶段对所有存活的阶段进行标记,标记完成后,再扫描整个空间未标记对象,直接回收不存活的对象.
优点:大多数情况下比较高效,缺点是会造成内存碎片,碎片太多导致后面过程中对大内存的分配无足够空间时而提前猝发一次垃圾回收动作;
复制算法
将可用内存将容量划分成大小相等的2块,每次清理时将其中A内存还存活的对象复制到B内存里面,然后再把A中清理掉;
优点高效且并不产生碎片,缺点牺牲了一半的内存为代价
适用存活对象少,回收对象多
标记整理算法
该算法标记阶段和标记清除算法一样,完成标记后它不是直接清理可回收对象,而是将存活对象都向一端移动最后清理掉端边界意外的内存;
适用于存活对象多,回收对象少的情况
分代收集算法
整合了复制算法和标记整理算法,根据新生代和老年代的不同特性采取上面的不同算法
新生代 生命周期短,每次回收时都有大量垃圾对象需要回收 复制算法
老年代 每次只有少量的对象需要回收 标记整理算法
java中的堆栈
https://www.cnblogs.com/iliuyuet/p/5603618.html
Java内存分配主要包括以下几个区域:
- 寄存器:我们在程序中无法控制
- 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中
- 堆:存放用new产生的数据
- 静态域:存放在对象中用static定义的静态成员
- 常量池:存放常量
- 非RAM(随机存取存储器)存储:硬盘等永久存储空间
https://www.cnblogs.com/SaraMoring/p/5687466.html
[Java四种引用包括强引用,软引用,弱引用,虚引用。(https://www.cnblogs.com/yw-ah/p/5830458.html)
⑴ 强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。 ps:强引用其实也就是我们平时A a = new A()这个意思。
⑵ 软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
⑶ 弱引用(WeakReference)
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
⑷ 虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
网友评论