首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

《Android应用开发攻略》——第3章 测试 3.1 导言:测试

第3章 测试 3.1 导言:测试 Ian Darwin讨论“尽早并经常测试”是测试倡导者们的常用口号。最重要的问题是,“如果你没有测试,如何知道代码能够正常工作?”测试有许多种类型。单元测试单独检查各个组件(不访问网络或者数据库)。JUnit和 TestNG是这方面处于领先地位的框架。在需要与其他组件交互时,单元测试使用模拟对象,有多个好的Java模拟框架。Android提供了许多特殊的测试技术,我们在这里要讨论其中的一些技术。先介绍一下本章中出现的NPE、ANR和FC等术语,后面不再进一步解释。NPE是指Null Pointer Exception(空指针异常),是“传统Java”缩略语。ANR是Android特有的缩略语——Application Not Responding(应用程序未响应),这是当你的应用程序对请求的响应被判断

优秀的个人博客,低调大师

《Android应用开发攻略》——2.15 用提示代替工具提示

2.15 用提示代替工具提示 Daniel Fowler2.15.1 问题Android设备的屏幕可能很小,没有空间供帮助文本使用,而工具提示不是平台的一部分。2.15.2 解决方案Android为View提供了hint属性。2.15.3 讨论有时候,输入字段需要对输入值加以说明。例如,一个要求货物数量的库存订货应用可能需要说明最小的订单数量。在桌面程序中,屏幕空间较大并且使用鼠标,附加的信息可以工具提示(鼠标移过字段时弹出的一个标签)形式显示,也可以使用长的描述性标签。而Android设备的屏幕可能很小,通常也不使用鼠标。替代方案是在View上使用android:hint属性,这能够在输入字段为空时显示包含提示文本的“水印”;用户开始输入时这个“水印”将会消失。android:hint对应的函数是setHint(int resou

优秀的个人博客,低调大师

《Android应用开发攻略》——3.5 测试项目的创建和使用

3.5 测试项目的创建和使用 Adri醤 Santalla3.5.1 问题你需要创建和使用新的测试项目,以测试Android应用程序。3.5.2 解决方案下面是测试项目的创建和使用方法:1 . 在IDE中,创建一个与你的Android应用程序项目关联的新Android项目。2 . 配置测试项目的AndroidManifest.xml文件,加入测试Android应用程序必需的代码行。3 . 最后,编写并运行测试。3.5.3 讨论下面更详细地描述了前述的步骤。第1步:在Android应用项目中创建新的Android测试项目首先,你必须在主应用项目中创建一个新的Android项目以保存测试。如果使用Eclipse,测试是一个项目,如果使用IntelliJ,则是一个模块。IntelliJ IDEA允许在现有项目中嵌套

优秀的个人博客,低调大师

《Android和PHP开发最佳实践 》一3.3 使用JSON通信

3.3 使用JSON通信 实际上,第1章中介绍如何结合Android和PHP学习时,我们就曾经提到过JSON协议,本节我们就来学习一下这个协议的基本内容。JSON是JavaScript对象表示法(JavaScript Object Notation)的简称,JSON协议源自JavaScript脚本语言的对象持久化表示方法,由于这种表示法比较简单易懂,而且传输的数据也比较小巧(相对于XML来说应该算是非常小巧了),因此,近年来被广泛地用于互联网应用的数据封装。首先,我们来学习一下JSON协议的数据表示方法。在JSON协议中,最基本的数据结构只有两种。第一种是数组结构,该结构类似于PHP中的列表数组,结构如下。 ["james","iris"] 第二种是对象结构,该结构非常类似于PHP中的散列数组,结构如下。 {"id":1,"name":

优秀的个人博客,低调大师

《企业级ios应用开发实战》一3.5 块编程

3.5 块编程 C语言的运行时特性中包括了块,标准C工作组的 N1370: Apple’s Extensions to C 中(其中也包括垃圾回收)对块进行了定义。作为C语言的扩展,Objective-C在OSX 10.6及iOS 4.0以后支持块语法。块运行时也会被集成到LLVM的compiler-rt子项目存储库中。 3.5.1 块的特点 一些面向对象的动态语言如ruby、groovy,都提供了对块的支持(在groovy中,块被称作为闭包“closure”)。块是用一对{}括号括起来的多个语句的集合。类似于函数,但不同于函数,可以把块作为表达式或变量的一部分,或者作为参数传递。在作为参数传递块时,代码被作为数据的一部分进行传递。块具有以下特征:同函数一样,有类型化参数列表。有返回结果或者要申明返回类型。能获取同一作用域(与块所在同一作用域)内的状态。可以修改同一作用域的状态(变量)。与同一范围内的其他块同享变量。在作用域释放后能继续共享和改变同一范围内的变量。除以上特点外,甚至可以复制块并传递到其他后续执行的线程,编译器和运行时负责把所有块引用的变量保护在所有块的拷贝的生命周期内。当然,这已经超出了本章的范围,可以参考苹果官方文档来了解这些内容。 3.5.2 Objective-C 中的块 对于C和C++,块是变量,但对于Objective-C,块仍然是对象。下面简单介绍Objective-C中的块。1.块变量声明用^操作符声明一个块变量的开始,分号表示块结束,如下代码所示: int multiplier = 7; int (^myBlock)(int) = ^(int num) { return num multiplier; }; 块语法比较奇怪,块变量声明的解释如图3-2所示。 块变量的声明语句从前至后分为了几部分:返回值类型,如int、double,如果未显式地声明块的返回值类型,可能会自动从块代码中推断返回类型(通过return语句)。块变量名用括号括住,块变量名前加^符号。参数类型用括号括住,多个参数以逗号分隔,如果参数列表为void,而且返回类型依靠推断,可以省略参数列表的void。等号,将后面的块赋值给前面的块变量(即myBlock)。以^开头并以;结束的块定义。块定义中又分为以下两个部分(除去开头的^和结尾的;外):参数列表,同函数的参数列表。块体,同函数体。值得注意的是,块可以使用同一作用域内定义的变量,而函数不行。一旦声明了块,你可以像使用函数一样调用它: int multiplier = 7; int (^myBlock)(int) = ^(int num) { return num multiplier; }; printf ( "%d", myBlock(3)); 2.行内块有时候,你不准备重复使用某个块,因此你不必为它想一个名称。那你可以使用行内块而不用声明为块变量。以下代码来自苹果文档:// gsort_b类似标准的 gsort_r 函数,但它最后一个参数是一个块。 char myCharacters[3] = { "TomJohn", "George", "Charles Condomine" }; qsort_b(myCharacters, 3, sizeof(char ), ^(const void l, const void r) { char left = (char )l; char right = (char )r; return strncmp(left, right, 1); }); // myCharacters 现在是 { "Charles Condomine", "George", TomJohn" } 在qsort_b 方法调用中,第4个参数就是一个匿名的块(行内块)。匿名块跟块变量不同,它没有变量名,因此你无法重用匿名块。下次调用这个块时,必须把整个块定义的代码再复制一遍。3.__block关键字块允许访问本地变量。这很重要。它使得我们在线程间共享变量变得简单,而且,你可以规定一个本地变量是否可以写,这可通过使用__block关键字,这是一种类类似register、auto和static存储类型修饰符。用__block修饰的变量,可以在所有同一作用域内的块,以及块复制之间共享数据。在指定作用域内的多个块能同时使用共享变量。如同块,__block变量也使用栈存储。如果使用block_copy拷贝块(或者向块发送copy消息),变量被拷贝到堆里。而且,__block变量的地址随后就会改变。__block变量有两个限制:不能是可变长度的数组,也不能是包含C99可变长度数组的结构体。下面显示了__block变量的使用: __block int x = 123; // x 是块可写的 void (^printXAndY)(int) = ^(int y) { x = x + y; printf("%d %d\n", x, y); }; printXAndY(456); // 打印出: 579 456 // x 现在的值是:579 下面显示了在块中使用多种类型的变量: extern NSInteger CounterGlobal; static NSInteger CounterStatic; { NSInteger localCounter = 42; __block char localCharacter; void (^aBlock)(void) = ^(void) { ++CounterGlobal; ++CounterStatic; CounterGlobal = localCounter; localCharacter = 'a'; }; ++localCounter; localCharacter = 'b'; aBlock(); }

优秀的个人博客,低调大师

《企业级ios应用开发实战》一3.4 KVO模型

3.4 KVO模型 KVO(key-value observer,“键-值”观察)模型是Cocoa绑定技术中常用的一种编程模型,它可以使一个对象在属性值发生变化时主动通知另一个对象并触发相应的方法。与NSNotification 不同,KVO没有所谓的中心对象来为所有观察者提供变化通知。当“被观察者”对象状态发生变化时,通知被直接发送至“观察者”对象,如图3-1所示。 在图3-1中,观察者是aButton,被观察者是modelObject。aButton是一个按钮控件,它是一个UI对象,有一个BOOL型的enabled属性,表示按钮是否可被点击。modelObject对象是一个模型对象,它没有可以呈现给用户的界面,同样,它有一个BOOL属性selected。通过KVO模型,modelObject的selected属性可以绑定到UIButton的enabled属性。即当modelObject的selected属性发生变化时(这是可以被编程的),KVO会主动通知aButton这种改变,因此按钮的外观随之可发生相应的呈现。比如由不可点击的灰色改变为可点击的着色状态。KVO是一种很有用的绑定技术(Cocoa还提供另外一种绑定技术:Dynamic bingding)。而且它是由被观察的对象主动通知观察者的,并不需要经过一个统一的通知中心(如后面章节介绍的通知技术所述),它的执行效率和适用场景要更佳。为了实现KVO,你需要进行如下操作:注册观察者。所谓观察者即对象状态变化时需要通知的对象。接收变更通知。接收变更通知主要是让观察者实现指定方法,在指定方法中,你可以接收到对象状态变更的消息,并在方法中进行处理。取消所注册的观察者。观察者处理完状态变更消息之后,需要取消原先的注册状态。 3.4.1 注册KVO 对象要将自己注册为观察者,必须发送一个addObserver:forKeyPath:options:context:消息至被观察对象: [account addObserver:inspector forKeyPath:@"name" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL]; 以上例子将inspector对象注册为account对象的观察者,并表明观察者将对名为“name” 的属性变更感兴趣。forKeyPath参数“name”注明了需要观察的属性的关键路径KeyPath。关键路径KeyPath实际是一个字符串,用于表示某个属性,你可以直接用属性名。但如果某属性是一个对象,则KeyPath可以用“.”语法的形式表示对象成员,如“account.name”。options参数注明了对该属性的何种状态感兴趣。NSKeyValueObservingOptionNew表示属性在变更后的新值,NSKeyValueObservingOptionOld表示属性未改变之前的值。以上例子中的option参数设置表明,当name属性变更时,会将这两个值以NSDictionary的方式(即change参数)提交给观察者,观察者可以从NSDictionary中以键-值对的方式检索到这两个值。context参数用于传递一个对象,该对象(或指针)会在属性变化时通过变更通知传递给观察者(通过context参数)。移除观察者的注册,使用方法removeObserver forKeyPath: [subject removeObserver:observer forKeyPath:@"name"]; 3.4.2 接收变更通知 观察者要想收到对象的属性变更通知,需要实现方法observeValueForKeyPath:ofObject: change:context:,并在其中进行通知的处理。例如: - (void)observeValueForKeyPath:(NSString )keyPath ofObject:(id)object change:(NSDictionary )change context:(void )context { NSLog(@"%@",keyPath); if ([keyPath isEqual:@"name"]) { NSLog(@"name is changed:%@", [change objectForKey:NSKeyValueChangeNewKey]); }else [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } 3.4.3 发送变更通知 NSObject支持两种属性变更通知,一种是自动变更通知,一种是手动变更通知。一般情况下,使用自动变更通知则更为简单,因此我们主要介绍自动变更通知。1.自动变更通知要使用自动变更通知,需要实现被观察者的 automaticallyNotifiesObserversForKey方法,在此方法中明确说明需要使用自动变更通知的属性。对于需要使用自动变更通知的属性,返回YES,如下代码所示: + (BOOL) automaticallyNotifiesObserversForKey:(NSString)key { // 对于属性name ,使用自动通知 if ([key isEqualToString:@"name"]) { return YES; } // 确保调用了父类的automaticallyNotfiesObserversForKey方法 return [super automaticallyNotifiesObserversForKey:key]; } 然后,在name属性发生变化的时候通知观察者,比如调用以下语句之一: subject.name=newName; [subject setValue:newName forKey:@"name"]; [subject setValue:newName forKeyPath:@"name"]; 如果属性是集合类型,则可以使用方法mutableSetValueForKey来支持以下集合方法导致的自动变更通知:添加:insertObject:InKey:或者insertObject:AtIndex:替换:replaceObject:InKey:或者replaceObject:AtIndex:删除:removeObjectFromKey:或者removeObjectAtIndex:2.手动变更通知对于手动变更通知,除了需要在automaticallyNotifiesObserversForKey:方法中将要使用的手动变更通知返回NO外,还需要 在改变值之前调用willChangeValueForKey:并在更改它之后调用didChangeValueForKey:。为了便于你理解KVO模型,我做了一个示例程序,放在光盘“source/第3章/TestKVO”文件夹,它使用了本节所介绍的知识点,可供参考和学习。

优秀的个人博客,低调大师

《企业级ios应用开发实战》一3.6 可变参数

3.6 可变参数 我们知道,C和C++语言支持可变参数的函数,例如我们常用的NSLog和printf函数。Objective-C作为C语言的超集,当然毫无例外地也支持可变参数。迄今为止,我们至少用过了一种使用可变参数的方法,即NSString的stringWithFormat:方法。C语言通过stdarg.h库支持可变参数,Objective-C 也不例外。在C语言中,如果你要使用可变参数,必须包含头文件stdarg.h,但在Cocoa中却不必,因为苹果已经在 NSObjC Runtime.h中包含了stdarg.h。stdarg.h的定义如下: typedef __void va_list; #define va_start(ap, param) __builtin_va_start(ap, param) #define va_end(ap) __builtin_va_end(ap) #define va_arg(ap, type) __builtin_va_arg(ap, type) 首先定义了一个va_list类型,其实就是一个void,即可以指向任何类型的指针。你可以把它看成是char,因为char*实际上也可以指向任何内存单元的地址。然后是3个预定义宏,va_start、va_end和va_arg。可以看出stdarg.h完全是以“预定义宏”这种“古老”的方式来支持可变参数的。接下来我们看一个例子,该方法使用了一个可变参数,并将这些可变参数进行了累加,然后返回一个NSNumber: - (NSNumber ) addValues:(int) count, ... { va_list args; va_start(args, count); NSNumber value; double retval; for( int i = 0; i < count; i++ ) { value = va_arg(args, NSNumber ); retval += [value doubleValue]; } va_end(args); return [NSNumber numberWithDouble:retval]; } 代码说明:第1行是方法定义,该定义应当加到头文件中。省略号...表明方法接收一系列数目不定的参数,在...前面至少需要指定一个任意类型的参数。有时我们必须知道参数的个数以防止出现无效的引用,但在某种情况下,参数个数是可以通过其他参数推断出来的(例如NSLog或printf函数可以通过计算%号的个数推断可变参数的个数),或者对于NSMutableArray来说,它总是以nil终止。如果是最后一种方法,我们可以把方法重新定义为: - (NSNumber ) addValues:(NSNumber ) firstNumber, ... 这样,我们就可以用以下调用方式代替“addValues:3,num1,num2,num3”: addValues:num1,num2,num3; 这样,我们就可以省略第1个表示可变参数个数的int参数。第2行中的va_list是void *类型,因此它实际上是一个可变的对象数组。第3行用args来存放可变参数列表,而count则表示函数最后一个参数(即第一个“固定参数”)。这将使编译器把args指向第1个参数后的位置(通过count地址加上count变量的长度)。很奇怪吗?可变参数中第1个参数的位址为什么是“count地址+count的长度”?因为对于大多数C编译器,函数栈中参数的存放顺序是从右到左的,也就是说先放入可变参数的最后一个参数,再放可变参数的倒数第2个参数……,然后放可变参数的第1个参数,最后是固定参数count。而与此同时,栈的方向是向下的,即先入栈的数据位于高地址,后入栈的数据则位于栈的起始地址。这样,实际上最后放入的固定参数count的地址变成了栈的起始地址。而紧随count之后的地址则是可变参数的第1个参数地址,即“count地址+count的长度”,因此编译器要能找到第1个可变参数的地址,只要知道1个参数:count就够了,由count取得函数栈的起始地址,加上sizeof(count),得到第1个可变参数的地址。va_start的第1个参数args是一个输出参数,经过va_start调用之后,args将等于arg_start计算出来的第1个可变参数的地址。第6行是一个for循环,因为我们无法通过 args 自身推断 args 的大小,因此必须显式地用count来指定args的大小。或者可以使用nil终止的列表来检索可变参数。如果你使用nil终止的数组作为可变参数,则应该用下面一行来代替第6~7行: while( value = va_arg( args, NSNumber ) ) 第 7 行将 args 中的下一个参数放入 value,并显式地转为 NSNumber*(如果不知道类型,可以用id)。第10行表明,一旦使用完args列表,就关闭它 。提示:如果你使用va_arg(args,double)(或者float等其他原始类型),那么当你试图传递一系列整数作为参数时(例如:addValues:4,4,3,2,1),可能会出现一些古怪的结果。而如果你显式地将这些参数说明为double(例如,double num1,double num2,double num3,double num4)则不会有什么问题。这是因为,如果编译器看到一个方法有一个double参数但你却传递了一个整数给这个方法时,它会进行类型转换。但如果方法使用了可变参数,编译器无法知道参数所使用的类型,因此编译器只会简单地把参数作为整型处理。

优秀的个人博客,低调大师

《企业级ios应用开发实战》一3.7 本章小结

3.7 本章小结 Objective-C是C语言的扩展和超集。本章重点从C语言特性和面向对象特性两个方面对Objective-C的语言特性进行论述,包括基本语法(数据类型、常量/变量、分支与循环)、运行时特性(反射支持)和一些特有属性(NS类、类别和协议、消息、KVO和块)。通过这些介绍,我们对Objective-C的一些重要特性有了最基本的了解,从而为后续的学习打下坚实的基础。接下来,本书将陆续介绍iOS SDK中的一些重要框架,如UIKit、Core Animation、Quartz Core,以及其他一些第三方的开源框架。

优秀的个人博客,低调大师

SpringBoot开发案例之整合定时任务(Scheduled)

来来来小伙伴们,基于上篇的邮件服务,定时任务就不单独分项目了,天然整合进了邮件服务中。 不知道,大家在工作之中,经常会用到那些定时任务去执行特定的业务,这里列举一下我在工作中曾经使用到的几种实现。 任务介绍 Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。Timer的优点在于简单易用;缺点是Timer的所有任务都是由同一个线程调度的,因此所有任务都是串行执行的。同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务,不过这种实现已经被项目所废弃。 开源集群任务框架Quartz,这是一个功能比较强大的的调度器,适合做任务集群,解决单点故障,目前项目中在使用。 Spring家族自带的Scheduled,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多,适用于简单的任务,微服务使用很方便。 项目应用 创建任务 代码中,可以发现,sendMail方法上注解被注释掉了,目前我们采用的是xml配置实现的。 import org.springframework.stereotype.Component; /** * 统计失败邮件定时重新发送 * 创建者 科帮网 * 创建时间 2017年7月21日 * */ @Component("sendMail") public class SendMail { //@Scheduled(cron = "0/5 * * * * ?") public void sendMail() { System.out.println("统计失败邮件定时重新发送开始"); } } 配置文件 <!-- 配置任务线性池 --> <task:executor id="executor" pool-size="5" /> <task:scheduler id="scheduler" pool-size="5"/> <!-- 启用注解驱动的定时任务 --> <task:annotation-driven executor="executor" scheduler="scheduler" proxy-target-class="true"/> <task:scheduled-tasks scheduler="scheduler"> <!-- 统计失败邮件定时重新发送 --> <task:scheduled ref="sendMail" method="sendMail" cron="0/5 * * * * ?"/> </task:scheduled-tasks> 启动项目 /** * 启动类 * 创建者 科帮网 * 创建时间 2017年7月19日 * */ @EnableAutoConfiguration @ComponentScan(basePackages={"com.itstyle.main"}) @ImportResource({"classpath:spring-context-dubbo.xml","classpath:spring-context-task.xml"}) public class Application { private static final Logger logger = Logger.getLogger(Application.class); public static void main(String[] args) throws InterruptedException { SpringApplication.run(Application.class, args); logger.info("项目启动 "); } } 启动后,控制台会每5s打印"统计失败邮件定时重新发送开始"。当然Scheduled的功能不仅仅如此,我们查找源码Scheduled类,可以发现还有一些注解属性,这里就不一一为大家介绍了。总之,要养成查看源码API的习惯。 @Target({ java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(Schedules.class) public @interface Scheduled { public abstract String cron(); public abstract String zone(); public abstract long fixedDelay(); public abstract String fixedDelayString(); public abstract long fixedRate(); public abstract String fixedRateString(); public abstract long initialDelay(); public abstract String initialDelayString(); } 项目:http://git.oschina.net/52itstyle/spring-boot-mail 作者: 小柒 出处: https://blog.52itstyle.com 本文版权归作者和云栖社区所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 如有问题, 可邮件(345849402@qq.com)咨询。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册