扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
我这边也在做Android和硬件设备的串口通信。
为长宁等地区用户提供了全套网页设计制作服务,及长宁网站建设行业解决方案。主营业务为网站设计、成都网站设计、长宁网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
我的通信方式很简单,我这边发送数据,接收数据(接收数据的内容中有标识位让我判断这次接收到的数据的相应处理动作)
读数据的时候我做的是一个清空的办法,每一次读取数据,如果读到的数据准确则进行处理,如果有误就清空了在读。
如果说接收的数据要对应上发送的数据,你可以在Android这边发送数据后不在发送数据只读取,并开启一个计时器,当这段时间内么有接收到返回值就继续你的发送和读取功能
你所谓的线程阻塞是指的ui线程吗?这应该是从你在开发的经验以及测试当中去体验的,如果你说是用代码去判断线程阻塞的话,估计比较复杂,也没那个必要,android的机制在出现ui线程阻塞的话会出现anr给予用户提示,出现这样的情况是开发者在开发过程中就得去避免的!
最近项目中,多次碰到app研发人员反馈广播从发送到接收器接收,间隔时间太长,要求系统进行优化,特别是开机阶段。对此,专门阅读了一下广播从发送到接收这个流程的源码,以彻底搞明白怎样让自己发送的广播尽快到达接收器。
涉及到的源码类不多,主要就是ActivityManagerService.java 和 BroadcastQueue.java。发送广播进程调用发送接口,通过IPC到达AMS,AMS根据Intent是否配置Intent.FLAG_RECEIVER_FOREGROUND,选择当前广播加入前台广播队列还是后台广播队列。根据当前广播是否有序,将广播加入广播队列的串行列表还是并行列表。广播队列和广播队列中的广播列表是影响广播接收时间的主要因素。
BroadcastQueue广播队列,负责将广播发送给广播接收器。AMS中有两个成员变量,
BroadcastQueue mFgBroadcastQueue;//前台广播队列
BroadcastQueue mBgBroadcastQueue;//后台广播队列
前台广播队列和后台广播队列的区别有两处:1 超时时间,前台10s,后台60s. 2 是否延迟广播等待前一个广播进程完成。这两个区别已经说明前台广播对广播接收器要求更高,响应时间更短,如果广播要排队,时间上前台广播更短。同时系统默认使用后台广播队列,所以前台广播队列处理的广播要少,避免了可能的大量广播排队情况。
广播队列中的列表
//存放无序并发送给动态广播接收器的广播任务
final ArrayListBroadcastRecord mParallelBroadcasts = new ArrayListBroadcastRecord();
//存放无序发送给静态广播接收器的广播任务或者存放有序广播任务
final ArrayListBroadcastRecord mOrderedBroadcasts = new ArrayListBroadcastRecord();
mParallelBroadcasts 此列表中存放的是无序广播动态广播接收器任务,广播队列会在处理任务时通过嵌套循环,把每个广播通过ipc发送到关注它的所有进程。所有无序广播+动态广播接收器,广播不需要排队。这种情况是最快能让广播到达目标进程的方式。
mOrderedBroadcasts存放的广播任务特点:广播有序,或者广播接收器是静态注册的。此种类型的广播全部要在mOrderedBroadcasts中排队,广播之间按时间先后,同一个广播不同广播接收器按优先级。mOrderedBroadcasts存放的广播必须等一个广播任务处理完毕才能处理下一个,中间可能包含进程的启动等。
由此可见,广播最快的情况是前台广播、无序广播、动态注册广播接收器。最糟糕的情况是:后台广播、有序或静态注册广播接收器、广播接收器优先级低。如果一个应用只是简单的靠注册一个静态广播接收器拉起进程,对应的正是最糟糕的情况。如果又发生在开机阶段,自然延迟严重。
如果必须注册静态广播接收器,缩短时间的办法为:配置Intent.FLAG_RECEIVER_FOREGROUND,加入前台广播队列,设置广播优先级
源码:
广播发送:Context .sendBroadcast -ActivityManagerNative.broadcastIntent-ActivityManagerService.broadcastIntent-ActivityManagerService.broadcastIntentLocked.到此阶段,跟发送广播的进程通信结束。此阶段AMS完成的工作主要是根据Intent查找该广播对应的动态广播接收器、静态广播接收器、以此发送该广播使用的广播队列。
private final int broadcastIntentLocked(
......//权限检查
......//特殊系统广播进行必要处理
if (sticky) {//粘性广播处理
......
//查找静态注册的接收器
receivers = collectReceiverComponents(intent, resolvedType, users);
if (intent.getComponent() == null) {
// 查找动态广播接收器
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, userId);
}
//动态广播接收器
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered NR 0) {
//确定队列
final BroadcastQueue queue = broadcastQueueForIntent(intent);
//创建广播任务BroadcastRecord
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
appOp, registeredReceivers, resultTo, resultCode, resultData, map,
ordered, sticky, false, userId);
......
//广播任务加入并行列表中
queue.enqueueParallelBroadcastLocked(r);
//启动异步发送广播任务
queue.scheduleBroadcastsLocked();
registeredReceivers = null;
NR = 0;
......
while (it NT ir NR) {
......
//根据优先级排序
if (curt == null) {
curt = (ResolveInfo)receivers.get(it);
}
if (curr == null) {
curr = registeredReceivers.get(ir);
}
if (curr.getPriority() = curt.priority) {
// Insert this broadcast record into the final list.
receivers.add(it, curr);
//获取广播队列
BroadcastQueue queue = broadcastQueueForIntent(intent);
//创建广播任务
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
requiredPermission, appOp, receivers, resultTo, resultCode,
resultData, map, ordered, sticky, false, userId);
//加入到广播队列串行列表中
queue.enqueueOrderedBroadcastLocked(r);
//启动异步发送任务
queue.scheduleBroadcastsLocked();
广播队列处理广播:
final void processNextBroadcast(boolean fromMsg) {
......
//并行列表,遍历广播任务
while (mParallelBroadcasts.size() 0) {
final int N = r.receivers.size();
//遍历接收器
for (int i=0; iN; i++) {
//IPC调用发送给目标进程
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
}
//有串行广播任务正在执行
if (mPendingBroadcast != null) {
//接收广播的目标进程正常
if (!isDead) {
// It's still alive, so keep waiting 继续等待目前进程反馈
return;
}
}
//取出第一个广播
r = mOrderedBroadcasts.get(0);//判断是否超时,
if ((numReceivers 0)
(now r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
//广播超时
broadcastTimeoutLocked(false);//超时处理,终止当前广播,启动下一个任务。
}
if (r.receivers == null || r.nextReceiver = numReceivers
|| r.resultAbort || forceReceive) {
//所有广播任务执行完毕
}
int recIdx = r.nextReceiver++;//下一个广播接收器
r.dispatchTime = r.receiverTime;//设置派发时间
setBroadcastTimeoutLocked(timeoutTime);//启动超时计时
if (nextReceiver instanceof BroadcastFilter){//动态广播接收器
deliverToRegisteredReceiverLocked(r, filter, r.ordered);//发送
return;
}
.//静态广播
ResolveInfo info =
(ResolveInfo)nextReceiver;
......
//检查进程是否已启动
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);
if (app != null app.thread != null) { /进程启动
processCurBroadcastLocked(r, app);//发送静态广播
return;
}
if ((r.curApp=mService.startProcessLocked(targetProcess,//启动进程
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent,
(r.intent.getFlags()Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
== null) {
//进程启动失败
}
//标志正在发送的串行广播
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;//正在发送的广播任务对应的接收器索引
}
首先查看是否是网络问题或者是系统问题。
1、CPU使用过高;
2、系统内存使用过高;
3、UI阻塞。
android开发中卡顿问题一直是个比较棘手又重要的问题,严重影响了用户的体验感。解决卡顿的问题就要对APP进行优化了,而优化是一个任重而道远的过程,必须在意每一个环节,否则当你想要优化的时候,发现到处都是坑,已经不知道填补哪里了,所以我们必须一点一滴的做起。
android是一个多任务的系统,每个APP都会有自己的堆内存,一般的UI 阻塞不会出现死机或重启的,5秒会出现ANR, 即程序无响应,只会造成APP本身挂掉。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流