Android
四大组件
四大组件指Activity、Service、BroadcastReceiver、ContentProvider,这四大组件都需要在AndroidManifest文件中注册才可以使用。
Activity
什么是Activity?
- 它是一种可以包含用户界面的组件,主要用于和用户进行交互。
Activity之间是如何进行数据传递的?
- 六种传值方式
通常采用对象序列化的方式进行传值,因为通常传递的内容不会是简单的字符串。
Activity的启动流程?
Activity的生命周期?
- 7个:onCreate() - onStart() - onResume() - onPause() - onStop() - onRestart() - onDestory()
其中,
用户可见可操作的阶段:onResume()
界面可见或部分可见但不能进行操作:onPause()
用户不可见的阶段:onStop()
相关问题
ⅠActivity A 弹出Dialog 的时候,Activity A 所经历的生命周期
- Activity不会执行任何生命周期
Ⅱ Activity A 弹出Dialog ,Dialog中有按钮跳转到另一个Activity B
- Activity A 执行:onPause()
Activity B 执行 onCreate() ->onStart()-> onResume()
Activity A 执行 onStop()
Ⅲ 横竖屏切换的时候,Activity所经历的生命周期
- ①如果该Activity未进行任何设置,则 横屏切换,会执行两次生命周期,竖屏切换,会执行一次生命周期
②如果设置 Activity 的 android:configChanges=“orientation” 时,切横、竖屏时只会执行一次生命周期
③如果设置 Activity 的android:configChanges=“orientation|keyboardHidden” 时,不会执行生命周期
Ⅳ 活动状态
- 运行状态:活动处于栈顶,用于用户交互
- 暂停状态:活动不处于栈顶,但还是对用户可见,但不能进行操作,比如,一个Activity上面弹出一个dialog,则仍然可以看到dialog后面的activity,但此时的activity则处于暂停状态
- 停止状态:活动不处于栈顶且不可见时
- 销毁状态:当活动从返回栈中移除的后就变成销毁状态
Activity的几种启动方式?
- Standard :默认的启动模式,每次启动活动,都是一个新的活动,并且放入 返回栈S中,不会在乎这个活动是否已经在返回栈中了
- SingleTop :栈顶复用。在启动该活动的时候,如果发现该活动位于返回栈的栈顶,则直接使用它,不会再创建新的活动。
注意:复用时,由于不会创建新的活动,所以也不会走完整的生命周期,而是调用onNewIntent()方法。 - SingleTask:栈内复用。如果该活动不在栈顶,则清空该活动上的其他活动,弹出该活动。
- SingleInstance:活动存放在另一个栈中。
BroadcastReceiver
定义:
- Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的Broadcast进行过滤接受并响应的一类组件
特点:
- 广播机制最大的特点就是发送方并不关心接收方是否接到数据,也不关心接收方是如何处理数据的。
三要素:
- 广播(Broadcast) - 用于发送广播;
- 广播接收器(BroadcastReceiver) - 用于接收广播;
- 意图内容(Intent)-用于保存广播相关信息的媒介
类型
- 标准广播和有序广播
- 标准广播:异步执行的广播。所有广播接收器几乎在同一时间接收广播,他们之间没有接收顺序,这种广播的效率比较高,同时意味着它是无法进行截断的。
- 有序广播:同步执行的广播,在广播发出之后,同一时刻只有一个广播接收器能够收到这条消息,广播接收器再根据业务逻辑判断是否继续传递广播还是进行拦截。
广播接收器(BroadcastReceiver)
- 对自己感兴趣的广播进行注册,这样当有响应的广播时,广播接收器就能接收到广播。
注册类型
- 静态注册:在AndroidManifest.xml中注册,其中name 为自定义的广播接收器,action为我们要监听的广播类型,也可以自定义广播。
- 动态注册:在代码中注册为动态注册,动态注册,记得在activity销毁的时候,即onDestroy()中取消注册,unregisterReceiver()方法实现。
相关问题:
广播的分类?
- 有序广播和标准广播
广播的使用场景
- 用于接收网络状态
- 应用与应用之间的唤醒,比如淘宝唤醒支付宝支付
- 组件间通信,电量不足的提示
广播使用的方式
- demo1:发送静态注册的自定义的标准广播 


- demo 2 发送静态注册的自定义的有序广播 结合demo1
- 广播在MyBroadcastReceiver被截断,AnotherBroadcastReceiver则接收不到广播,如果需要常接受,则需去掉abortBroadcast()方法。

- demo3 发送动态注册的自定义的本地的标准广播
tip:本地广播:未防止其他应用也接收到自己应用发送的自定义广播,
相关问题
在manifest 和代码中如何注册和使用BroadcastReceiver?
- 看以上的静态注册和动态注册
本地广播和全局广播有什么差别?
- 本地广播:
- 只可以自己应用接收的广播
- 防止自己发送的广播被其他应用所拦截
- 防止接收垃圾广播攻击自己的应用
- 全局广播:
- 任何应用都可以接收到的广播
如何通过广播拦截和abort一条短信?
- 看上面的demo2,采用有序广播进行发送,并拦截。
广播是否可以请求网络?
- 可以,但需要在子线程中进行,主线程超过10s会造成ANR.
广播引起ANR的时间限制是多少?
- 当BroadcastReceiver在10秒内没有执行完毕,Android会认为该程序无响应,所以在 BroadcastReceiver里不能做一些比较耗时的操作,否则会弹出ANR(Application No Response)的对话框。
ContentProvider
定义
- 主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全
相关问题
- 谈谈你对ContentProvider的理解
同上 - 说说ContentProvider、ContentResolver、ContentObserver 之间的关系
Service
定义
- 服务是一个后台运行的组件,执行长时间运行且不需要用户交互的任务。
启动和停止服务
- 第一种:startService()/stopService()
- 第二种: bindService()/unbindService()
Activity 与 Service 之间的通信
- 通过Binder对象实现
在Service中,创建Binder对象,重写onBind方法,将自定义的Binder返回。
在Activity中,通过监听Service的绑定和解除绑定,在绑定中获取binder,向下转型为我们自定义的binder,便可以进行更多的操作service的行为了
Service的生命周期
onCreate() - onStartCommand() - onDestory()
注意:如果同时调用 bindService() 和 startServicee() 需要调用 unBindService()和 stopService/stopSelf()才可以将服务销毁,即onDestory()才会被调用。
IntentService
- 由于服务是在主线程中创建的,如果在服务中创建一些耗时操作,则会造成ANR。所以,创建服务后,需要在具体的子方法中,开启一个子线程,去处理耗时操作,操作完成后,才能停止服务。这一系列操作包含两点:①,需要创建子线程 ② 不能在外部控制停止服务的时间。所以引入IntentService解决这两个问题。 onHandleIntent()则自动在子线程中运行。
相关问题:
- Service与Activity的几种通信方式:
1.通过Binder进行通信。可看如上的Binder实例。
2.通过Service进行通信。
详细讲解 - 如何保证一个后台服务不被杀死?
1.用 sticky 粘性的 servcie:Service 设置成 START_STICKY kill后会被重启(等待 5 秒左右),重传 Intent,保持与重启前一样
2.多媒体锁:锁屏后循环播放无声音乐,解释后停止播放,实测在华为能永久保活,我们项目中就有用到。
3.在 onDestroy 中再次启动:service +broadcast 方式,就是当service 走 ondestory 的时候,发送一个自定义的广播,当收到广播的时候,重新启动 service;
4.提高进程优先级,将其设置为前台状态:通过 startForeground将进程设置为前台进程,做前台服务,优先级和前台应用一个级别 ,除非在系统内存非常缺,否则此进程不会被 kill
Android 进程保活之—— startForeground保活
5.用广播保持监听:注册高频率广播接收器,唤起进程。如网络变化,解锁屏幕,开机等
6. 一像素存活: 在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死
一像素存活//但这种方法可能不是很可行。
7.双进程 Service: 让 2 个进程互相保护,其中一个 Service 被清理后,另外没被清理的进程可以立即重启进程
代码详解:
ServiceOne.java
package com.example.servicedemo;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class ServiceOne extends Service {
public final static String TAG = "com.example.servicedemo.ServiceOne";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
thread.start();
return START_STICKY;
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.e(TAG, "ServiceOne Run: "+System.currentTimeMillis());
boolean b = MainActivity.isServiceWorked(ServiceOne.this, "com.example.servicedemo.ServiceTwo");
if(!b) {
Intent service = new Intent(ServiceOne.this, ServiceTwo.class);
startService(service);
Log.e(TAG, "Start ServiceTwo");
}
}
};
timer.schedule(task, 0, 1000);
}
});
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
ServiceTwo.java
package com.example.servicedemo;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class ServiceTwo extends Service {
public final static String TAG = "com.example.servicedemo.ServiceTwo";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
thread.start();
return START_REDELIVER_INTENT;
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.e(TAG, "ServiceTwo Run: " + System.currentTimeMillis());
boolean b = MainActivity.isServiceWorked(ServiceTwo.this, "com.example.servicedemo.ServiceOne");
if(!b) {
Intent service = new Intent(ServiceTwo.this, ServiceOne.class);
startService(service);
}
}
};
timer.schedule(task, 0, 1000);
}
});
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Handler 、Message 、MessageQueue、 Looper
HandlerMessage MessageQueue Looper详细讲解
UI
常见的几种布局
线性布局 LinearLayout
- 控件在线性方向进行排列。
- 通过android:orientation 设置垂直和水平布局
帧布局 FrameLayout
- 所用控件默认摆放在布局的左上角,相互覆盖。
相对布局 RelativeLayout
- 控件相对父布局或相对其他控件进行排布。
约束布局 ContraintLayout
- 新的一种布局方式,主要解决布局相互嵌套过多的问题,比如线性布局里放相对布局再放线性布局这样层层嵌套。
- 可以独立设置每个控件的位置。
自定义控件
- 自定义控件原理
- 自定义View如何提供获取View属性的接口?
Recyclerview的使用方法
- RecyclerView的基本使用
- 过程
①创建RecyclerView布局
②创建Adapter 其中包括ViewHolder的创建,建立重用机制。
③创建LayoutManager设置横纵布局。
相关问题:
Ⅰ ListView 与 RecyclerView 的区别?
ListView 与 RecyclerView的区别
- 布局效果: RecyclerView > ListView
RecyclerView 可以实现横纵布局,但ListView 的布局单一,只可以实现纵向布局 - 局部刷新 RecyclerView > ListView
RecyclerView 可以自带方法实现局部刷新(包括删除、更新数据、添加数据),ListView也可以实现,但需要代码手动书写。 - 动画效果 RecyclerView > ListView
RecyclerView 自带ItemAnimatior的动画效果方法,但ListView却没有 - 数据的头和尾的样式 ListView > RecyclerView
ListView 可以自定义头尾item样式,但RecyclerView全部是统一的ItemView,需要自己手动代码更改。 - 空数据处理 ListView > RecyclerView ListView
自带列表数据判空的方法,RecyclerView需要自己根据列表数据进行判断。
Ⅱ:RecyclerView中 ,如果一个itemView设置点击监听事件,itemView中包含TextView和ImageView,ImageView设置了点击监听,TextView没有设置点击监听。
问题:
1.点击itemview中的TextView,如图点击①位置,谁会响应监听?
2.点击itemView,如图②位置,谁会响应监听?
3. 点击itemView中的ImageView,如图③位置,谁会响应监听?
4.itemView的监听是否会被ImageView的监听覆盖,或者ImageVIew的监听是否会被覆盖监听呢?
答:
1.2.点击①和②的位置,都是有itemView响应监听,因为①的位置没有设置监听,所以由父布局,itemView进行响应监听。
3.点击③的位置,由ImageVIew响应,因为子布局设置了监听事件,根据View的事件分发机制,如果子布局进行消费,则该事件已经被消费,停止点击事件的事件分发。所以,子布局ImageView的点击事件会优先被执行。
4.该点击事件不会再分发给父布局ItemVIew进行处理,此题考察的是View的事件分发机制,并不是覆盖不覆盖的问题。
Fragment
碎片是什么?
- 碎片(Fragment)是一种可以嵌入在活动中的UI片段,它能让程序更加合理和充分的利用大屏幕的空间,因为在平板上应用的非常广泛。
生命周期:
相关问题
Ⅰ Activity与Fragment之间生命周期比较?
多了五种状态:
onAttach() 在Fragment 和 Activity 建立关联是调用(Activity 传递到此方法内)
onCreateView() 当Fragment 创建视图时调用
onActivityCreated() 在相关联的 Activity 的 onCreate() 方法已返回时调用。
onDestroyView() 当Fragment中的视图被移除时调用
onDetach() 当Fragment 和 Activity 取消关联时调用。
Ⅱ 如何实现Fragment的滑动?
通过ViewPager + Fragment
Tablayout + ViewPager + Fragment
Ⅲ Fragment中,返回上一个Fragment 如何实现?正常情况下并不能返回到上一个Fragment中。
和Activity相同的思路是,添加到回退栈中,但不同点方式,是,通过
transaction.addToBackStack(null)的方式,在替换ReplaceFragment提交之前,调用这个方法。
Ⅳ fragment之间传递数据的方式?
① Fragment1 与 Fragment2 传递数据
方法一:情景:Fragment1 跳转到Fragment2 并携带数据
通过 setArguments(bundle数据) getArguments() 设置 可取出参数
Fragment 与 Fragment 之间传递数据
步骤:
①Fragment2中,新建 一个 返回值类型为Fragment2的newInstance(String data)方法 //此步骤也可忽略
②Bundle携带数据,fragment.setArguments(bundle数据) 放入数据
③在Fragment1 中,通过Fragment2.newInstance(添加需要传递数据)
④在Fragment2 的onCreateView中,通过getArguments()的方法获取数据。
代码解释:
这两个方法都在Fragment2中,newInstance()是在Fragment1中需要传递数据的时候调用的。onCreateView是Fragment2的生命周期。
方法二:情景:Fragment1 与Fragment2在同一个Activity中,并且只静态使用。直接通过findViewById找到两个Fragment中的任意控件,进行赋值即可。
② Fragment 与Activity之间传递数据。
Fragment 可以通过getActivity().get可以随意获取到宿主Activity的数据。
Activity 可以通过接口回调的方式获取Fragment中的数据
接口回到的方式
Ⅵ Fragment的动态使用和静态使用?
动态,就是动态添加和替换。
静态,则是将<xxx.com.Fragment></xxx.com.Fragment>写到布局文件中。
更加详细的Fragment讲解
高级技巧
-
创建定时服务:
-
序列化对象之Serializable
-
序列化对象之Parcelable
Serializable 与 Parcelable 比较:Serializable使用简单,但会将整个对象进行序列化,效率较低,通常推荐使用Parcelable的方式传递Intent对象。 -
DOZE模式
当用户的设备是Android 6.0以上或以上的系统时,如果该设备未插接电源,处于静止状态,且屏幕关闭了一段时间后,就会进入DOZE模式。 -
Android 版本型号与targetSdkVersion的匹配:
-
设置Activity在以下的几种情况下不会重新创建
-
获取Activity当前状态发生变化回调
重写Activity中的onConfigurationChange() -
禁止程序的被切换成多窗口
-
允许应用多语言设置的时候可以从右到左编排布局
android:supportsRtl="false"