长虹厂商反馈的问题:
当通过intent外部调起的详情页面,按home键回到launcher,再次通过intent调起播放页面,按back键返回,会发现上次调用过的详情页。
想了想,这个问题其实是Activity和Task堆栈的问题。正好回顾一下task,launch mode这几个概念,高手直接略过。
Task是执行用户工作,与用户交互的一组Activity的集合。 当用户在应用启动器中触击一个应用的图标,系统会内存中寻找有没有该应用打开过的堆栈
如果有,这个应用就会回到前台。如果没有这个应用的任务存在,那么创建一个新的 task,这个应用的 “main” Activity打开,并且作为这个 task栈的根 activity。Activity被安排到同一个栈 (back stack)中,其中的 activity按顺序的打开的。
在同一个应用中,打开Activity和按back按键,Activity在堆栈中的变化过程如下:
一般情况下,我们不用担心Activity怎么和task关联,不需要关系Activity如何存在于stack中。但是比如我们现在遇到的问题,厂商明显是想中断这种常态行为,希望按home键离开应用的task时,应用自动清除task内的所有activity。
这个时候,我们就需要使用launch mode和Intent flag来改变activity与task的这种默认行为。
关于launch mode和intent flag不在做详细的解释,参考这里,讲解的很细致。
Activity的四种加载模式 http://marshal.easymorse.com/archives/2950
android之intent的Flag详解 http://hi.baidu.com/jieme1989/item/6e5f41d3f65be848ddf9beb9
画一个流程图,复现厂商说的问题既然是要求按home按键,清空堆栈。可以有两种做法。
1.监听Home按键,当用户按下Home按键时,结束自己的进程。
这里有两个问题:
第一个就是Home按键的捕获,一般是捕获不到的。
:可以使用一个线程去监视系统日志(有点笨,不过还算有效)
第二个是如果是android厂商的话,一般都会修改Framework,可以让他们在home键按下的时候,发一个广播出来。App
可以根据此广播,处理相应的逻辑。
2.可以使用launch Mode配合Intent Flag完成第三方调起应用时,可以在getIntent()中,加入Intent.FLAG_ACTIVITY_CLEAR_TASK ,同时调起的Activity的launch mode设置为singleTask
也就是第三方调起的每个页面,在启动前都会对Task进行清空,从而避免上述问题。
原文链接:http://www.67tgb.com/?p=628
转载注明:望月听涛
原文地址:http://www.raywenderlich.com/2502/calayers-tutorial-for-ios-introduction-to-calayers-tutorial
如果你已经在iPhone上做过开发,你可能对UIView和它的子类-Button,text,slider等,非常熟悉。
// Import QuartzCore.h at the top of the file #import <QuartzCore/QuartzCore.h> // Uncomment viewDidLoad and add the following lines self.view.layer.backgroundColor = [UIColor orangeColor].CGColor; self.view.layer.cornerRadius = 20.0; self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20);
CALayer *sublayer = [CALayer layer]; sublayer.backgroundColor = [UIColor blueColor].CGColor; sublayer.shadowOffset = CGSizeMake(0, 3); sublayer.shadowRadius = 5.0; sublayer.shadowColor = [UIColor blackColor].CGColor; sublayer.shadowOpacity = 0.8; sublayer.frame = CGRectMake(30, 30, 128, 192); [self.view.layer addSublayer:sublayer];
sublayer.contents = (id) [UIImage imageNamed:@"BattleMapSplashScreen.jpg"].CGImage; sublayer.borderColor = [UIColor blackColor].CGColor; sublayer.borderWidth = 2.0;
CALayer *sublayer = [CALayer layer]; sublayer.backgroundColor = [UIColor blueColor].CGColor; sublayer.shadowOffset = CGSizeMake(0, 3); sublayer.shadowRadius = 5.0; sublayer.shadowColor = [UIColor blackColor].CGColor; sublayer.shadowOpacity = 0.8; sublayer.frame = CGRectMake(30, 30, 128, 192); sublayer.borderColor = [UIColor blackColor].CGColor; sublayer.borderWidth = 2.0; sublayer.cornerRadius = 10.0; [self.view.layer addSublayer:sublayer]; CALayer *imageLayer = [CALayer layer]; imageLayer.frame = sublayer.bounds; imageLayer.cornerRadius = 10.0; imageLayer.contents = (id) [UIImage imageNamed:@"BattleMapSplashScreen.jpg"].CGImage; imageLayer.masksToBounds = YES; [sublayer addSublayer:imageLayer];
CALayer *customDrawn = [CALayer layer]; customDrawn.delegate = self; customDrawn.backgroundColor = [UIColor greenColor].CGColor; customDrawn.frame = CGRectMake(30, 250, 128, 40); customDrawn.shadowOffset = CGSizeMake(0, 3); customDrawn.shadowRadius = 5.0; customDrawn.shadowColor = [UIColor blackColor].CGColor; customDrawn.shadowOpacity = 0.8; customDrawn.cornerRadius = 10.0; customDrawn.borderColor = [UIColor blackColor].CGColor; customDrawn.borderWidth = 2.0; customDrawn.masksToBounds = YES; [self.view.layer addSublayer:customDrawn]; [customDrawn setNeedsDisplay];
void MyDrawColoredPattern (void *info, CGContextRef context) { CGColorRef dotColor = [UIColor colorWithHue:0 saturation:0 brightness:0.07 alpha:1.0].CGColor; CGColorRef shadowColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.1].CGColor; CGContextSetFillColorWithColor(context, dotColor); CGContextSetShadowWithColor(context, CGSizeMake(0, 1), 1, shadowColor); CGContextAddArc(context, 3, 3, 4, 0, radians(360), 0); CGContextFillPath(context); CGContextAddArc(context, 16, 16, 4, 0, radians(360), 0); CGContextFillPath(context); } - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context { CGColorRef bgColor = [UIColor colorWithHue:0.6 saturation:1.0 brightness:1.0 alpha:1.0].CGColor; CGContextSetFillColorWithColor(context, bgColor); CGContextFillRect(context, layer.bounds); static const CGPatternCallbacks callbacks = { 0, &MyDrawColoredPattern, NULL }; CGContextSaveGState(context); CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); CGContextSetFillColorSpace(context, patternSpace); CGColorSpaceRelease(patternSpace); CGPatternRef pattern = CGPatternCreate(NULL, layer.bounds, CGAffineTransformIdentity, 24, 24, kCGPatternTilingConstantSpacing, true, &callbacks); CGFloat alpha = 1.0; CGContextSetFillPattern(context, pattern, &alpha); CGPatternRelease(pattern); CGContextFillRect(context, layer.bounds); CGContextRestoreGState(context); }
Atomthreads像众多操作系统一样,在没有任务调度是会调用idle。
static void atomIdleThread (uint32_t param) { /* Compiler warning */ param = param; /* Loop forever */ while (1) { /** \todo Provide user idle hooks*/ } }
atomthreads中atomIdleThread()是以线程的形式存在,也就是最低优先级线程。作者默认没有填写这个函数。
uint8_t atomOSInit (void *idle_thread_stack_top, uint32_t idle_thread_stack_size) { uint8_t status; /* Initialise data */ curr_tcb = NULL; tcbReadyQ = NULL; atomOSStarted = FALSE; /* Create the idle thread */ status = atomThreadCreate(&idle_tcb, IDLE_THREAD_PRIORITY, atomIdleThread, 0, idle_thread_stack_top, idle_thread_stack_size); /* Return status */ return (status); }针对STM8我们最自然想到的是在其中加一个wfi,STM8进入wfi模式几乎不会影响任何外设的运行。以STM8S105K4为例,其进入该模式的典型电流是1.8mA。这个电流,用一节2000mA手机供电,理论上也最多能坚持46天,才一个月多点。这个记录太差了。
STM8还有一个HALT模式,这是该芯片的最低功耗模式,电流是uA级别。但是该模式有诸多限制,进入该模式系统几乎所有的clock都停止,你的timer,adc,uart等等全部停止,除了AWU。
atomthreads如果你在idle直接进入HALT,因为基本只有外部中断可以唤醒退出这个模式,当系统醒来了,请你想想,你的系统心跳还准么?你的应用线程如果使用了定时器,本来希望1秒钟后调用某个CALLBACK,结果HALT睡了5分钟,那还是定时器API本身参数的意义么?
对datasheet熟悉的读者可能,可能立刻想到了AWU,似乎可以解决这个问题。在idle进入HALT前,把还能睡的时间填入AWU,这样系统就可以在制定的时间被唤醒。粗略的一看,还以为问题解决了。
暂时不谈AWU的时间不是任意值都可以接受的,是一个非常不准确的唤醒时钟。
我给你举个其他例子,如果idle进入HALT前,系统还可以睡20分钟,我觉的一个设计优良的低功耗系统,应用层让系统有睡20分钟的可能性是很起码的。不幸的是,在5分钟的时候,一个外部中断进来了,系统很自然退出HALT。我想问你,从系统的角度看,系统之前睡了多久。不要告诉玩我是5分钟,大哥,那是我假设的,我问得是,从系统的角度。睡了多久?AWU这个唯一在运行的模块,上面是没有时间让你读的,你完全无法得知刚才睡了多久。
其实上面的这个理念不是我创造的,在linux中早就有了,它叫variable tick timer,什么意思?通常我们的心跳时钟,是有规律的触发中断,比如10ms一次,这导致系统最多能安静10ms,想多睡会儿?没门!10ms后中断就来了。这种设计对低功耗是不利的。后来就有大牛,引入了variable tick timer,这里tick timer就是我们上面一直说的心跳时钟。variable就是可变的罗!表面意思就是我们的心脏可以走走停停,这样想已经不符合人类的自然规律,所以也确实不能再叫heart beattimer。当系统醒的时候,是有规律的跳动,当系统睡眠的时候, timer就停跳。其实就是上面想实现的东西。