- Service启动的两种方式及区别
- Service如何使用及使用的场景
- BroadcastReceiver注册的两种方式及广播使用的场景
- ContentProvider怎么使用
- 启动Activity的几种方式及使用的场景
- 堆和栈的区别及各自的作用
- 怎么兼容不同安卓版本系统
- 广播静态注册和广播动态注册有什么区别?
- 解除绑定后,服务会不会立即停止?
- 隐式启动action和category的匹配规则
问题一
bindService
,服务的生命周期和Activity的生命周期绑定,Activity结束之前,需要注意解除绑定undindService()
,防止内存泄露。绑定服务会执行:onCreate
->onBind
->onUnBind
->onDestroy
startService
,服务启动后,多次调用startService
服务,onCreate
方法只会执行一次,onStartCommand
方法会被执行多次,停止服务需要开发者手动调用Context.stopService
或Service.stopSelf
方法。启动服务会执行:onCreate
->onstartCommand
->onDestroy
问题二
bindService
,启动一个后台服务,监听蓝牙连接的状态并获取传输过来的数据,把数据封装后广播发送,在Activity通过bindService()
启动服务,实现ServiceConnection
接口,服务连接或服务连接断开后执行对应操作startService
,启动一个后台服务,更新APP,在子线程中执行下载的任务,Handler更新下载的进度,下载完成调用Context.stopService
或Service.stopSelf
方法停止服务
问题三
- 动态注册的广播接收器不是常驻型的,会随着所注册的Activity的结束而结束,如果所在的Activity已经destroy了,那么该广播接收器也就不能再继续接收广播了。注意:在Activity结束前,要取消注册广播接收器,不然会导致内存泄露。应用场景:1、完成Activity和Service不同组件间的通信;2、实现不同进程间的通信
- 静态注册的广播接收器是常驻型的,即使所在的APP被关闭了,也是可以接收到广播的。应用场景:1、网络状态不佳时,系统发送一条广播,应用注册静态接收器,提示用户“当前网络异常,请检查联网状态”;2、电量不足时,系统发送一条广播,应用静态注册接收器,提示用户“当前电量不足,注意保存游戏进度”
https://blog.csdn.net/csdn_aiyang/article/details/68947014
https://www.jianshu.com/p/5a983578418e
问题四
ContentProvider是一个抽象类,继承该类后,重写onCreate
、query
、delete
、insert
、update
和getType
方法,作用实现跨进程数据共享,ContentProvider内部可以将数据写入sqlite或本地文件
应用使用ContentResolver
来操作另一个应用内的ContentProvider
,通过Uri
来定位需要访问的数据,使用UriMather
绑定Uri和整型值的关系,用户输入Uri,然后在ContentProvider内查询对应的整型值,存在该整型值返回对应的数据,否则查询失败
public class StudentContentProvider extends ContentProvider {
//这里的AUTHORITY就是我们在AndroidManifest.xml中配置的authorities
private static final String AUTHORITY = "com.jrmf360.studentProvider";
//匹配成功后的匹配码
private static final int MATCH_CODE = 100;
private static UriMatcher uriMatcher;
private StudentDao studentDao;
//数据改变后指定通知的Uri
private static final Uri NOTIFY_URI = Uri.parse("content://" + AUTHORITY + "/student");
static {
//匹配不成功返回NO_MATCH(-1)
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//添加我们需要匹配的uri
uriMatcher.addURI(AUTHORITY,"student", MATCH_CODE);
}
@Override
public boolean onCreate() {
studentDao = StudentDao.getInstance(getContext());
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
int match = uriMatcher.match(uri);
if (match == MATCH_CODE){
Cursor cursor = studentDao.queryStudent();
return cursor;
}
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
if (uriMatcher.match(uri) == MATCH_CODE){
studentDao.insertStudent(values);
notifyChange();
}
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
if (uriMatcher.match(uri) == MATCH_CODE){
int delCount = studentDao.deleteStudent();
notifyChange();
return delCount;
}
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
private void notifyChange(){
getContext().getContentResolver().notifyChange(NOTIFY_URI,null);
}
}
实现ContentProvider,在清单文件中配置。这里的authorities唯一标识该内容提供者,这样其它的应用才可以找到该内容提供者并操作它的数据;exported为true当前内容提供者可以被其它应用使用,默认为true。
<provider
android:authorities="com.jrmf360.studentProvider"
android:name=".StudentContentProvider"
android:exported="true"/>
https://www.jianshu.com/p/5e13d1fec9c9
问题五
standard
。每次创建一个Activity实例,应用最广的启动模式,需要注意在网络不佳的情况下有可能重复创建多个Activity实例,白白浪费过多的内存singleTop
,检查栈顶是否存在当前Activity实例,存在栈顶的实例会被重用,否则重新创建实例并入栈。应用场景:点击通知栏的推送消息进入详情界面,详情界面使用到singleTop
,当前详情界面位于栈顶会被重用该Activity,不会回调onCreate()
、onStart()
方法而会回调onNewIntent()
方法接收传递过来的信息;singleTask
,检查栈内是否存在当前Activity实例,栈内存在该实例则重用,并将位于当前实例之上的Activity出栈。应用场景:H5调起原生APP打开,点击【返回】按钮,回到了APP主界面,这里涉及隐式启动Activity的问题singleInstance
,Android系统中只会存在一个Activity实例,并且该实例独自处于一个任务栈中,使用情况比较罕见,在launcher可能使用
问题六
Java虚拟机将内存划分为方法区、堆、Java栈、程序计数器和本地方法栈
在运行时创建的类实例和数组放在同一个堆上,所有的线程共享同一块堆,堆的大小是有限的,内存不足可能会造成OOM,垃圾收集器需要不断地回收不被引用的对象
每个线程都独享一个Java栈,Java栈有栈帧组成,栈帧保存了方法调用的状态(包括局部变量和操作数栈)。线程调用方法,虚拟机会把栈帧压入Java栈,当方法返回时,栈帧从Java栈中出栈并抛弃
问题七
每个Android版本添加新的特性和相关的API,高版本的API在低版本系统中没法找到对应的方法,容易造成Crash,了解每个版本的差异性,有助于我们在代码中提供判断兼容不同系统,使用到的相关类Builder
系统版本 | 新增特性 | 描述 |
---|---|---|
Android 9.0 | 利用Wifi RTT 实现室内定位 | Pie |
Android 8.0 | findViewById() 签名变更 |
Oreo |
Android 7.0 | 多窗口支持 | Nougat |
Android 6.0 | 新增动态申请权限功能 | Marshmallow |
Android 5.0 | ART运行时代替Dalvik成为平台默认配置 | Lollipop |
Android 4.0 | 优化内存,提高应用运行速度 | KitKat |
问题八
静态注册,在清单文件中注册,静态注册的广播在应用程序没有启动,依然可以监听来自系统或其他应用程序发送的广播,常用的场景包括:多进程之间的通信,监听通知消息
动态注册,在代码中设置,组件的生命周期结束,广播停止,防止内存泄露,在组件退出时解注册广播,常用的场景包括:组件内实现消息互传(Activity和Fragment消息传递)
使用广播需要注意几个问题:
onReceive(Context,Intent)
方法内避免执行耗时操作,超过10s的耗时操作会出现ANRonReceive(Context,Intent)
使用Context时需要注意,静态注册Context代表ReceiverRestrictedContext
类的实例,启动Activity要给Intent设置标记:Intent.FLAG_ACTIVITY_NEW_TASK;动态注册Context代表Activity或Service的实例- 监听系统广播,除了需要申请对应的权限外,在高版本系统中,需要做兼容性的处理,比如:开机启动、电量变化、网络连接等
- 普通广播是并行无序执行,有序广播是按优先级串行有序执行
问题九
解除绑定后,服务不会立即停止。原因是ServiceConnection和Context解除绑定后,如果服务还在运行,服务不会回调Service.onDestroy()
方法
startService()
启动服务后,手动调用Context.stopService()
或Service.stopSelf()
才会停止服务;bindService()
启动服务后,和Activity的生命周期绑定,Activity退出后服务停止,应用与前台数据的交互
服务应用于不需要与用户交互且长时间运行的任务,同时Service运行在UI线程,不适合执行耗时的操作
执行耗时的操作可以考虑使用IntentService
,重写onHandleIntent()
方法,在方法内执行耗时的操作
服务分为前台服务和后台服务,后台服务的优先级比较低,在内存不足的时候可能会被回收。前台服务弥补了后台服务的缺点,一直保持运行状态而不被系统回收。
常用的系统服务包括:WifiManager
、AudioManager
和ConnectivityManager
https://www.cnblogs.com/huolongluo/p/6340743.html
问题十
应用启动分为隐式启动和显示启动,隐式启动需要给Intent设置action
、category
、data
,重点介绍隐式启动的规则:
action
,一对多,Intent必须设置ACTION,清单文件可以设置多个ACTION。只要Intent设置的ACTION在清单文件中被找到,配置成功category
,多对多或0对多,Intent可以设置多个CATEGORY或不设置,清单文件也可以设置多个CATEGORY或者设置android.intent.category.DEFAULT
。只要Intent设置的多个CATEGORY在清单文件中被找到,配置成功。data
,一对多,Intent设置DATA的内容包括:Uri、mimeType,Uri的结构为scheme://host/port/pathPrefix?params=value
你可能感兴趣的文章
转载请注明出处: https://www.teachcourse.cn/2724.html ,谢谢支持!