首页 文章 精选 留言 我的

精选列表

搜索[腾讯云双十一抄作业],共10000篇文章
优秀的个人博客,低调大师

Python3入门(十一)OS文件/目录方法

os模块提供了非常丰富的方法用来处理文件和目录。常用的方法如下表所示 方法 描述 os.access(path, mode) 检验权限模式 os.chdir(path) 改变当前工作目录 os.chflags(path, flags) 设置路径的标记为数字标记。 os.chmod(path, mode) 更改权限 os.chown(path, uid, gid) 更改文件所有者 os.chroot(path) 改变当前进程的根目录 os.close(fd) 关闭文件描述符 fd os.closerange(fd_low, fd_high) 关闭所有文件描述符,从 fd_low (包含) 到 fd_high (不包含), 错误会忽略 os.dup(fd) os.dup(fd) os.dup2(fd, fd2) 将一个文件描述符 fd 复制到另一个 fd2 os.fchdir(f

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

Android开发 - 掌握ConstraintLayout(十一)复杂动画!如此简单!

介绍 本系列我们已经介绍了ConstraintLayout的基本用法。学习到这里,相信你已经熟悉ConstraintLayout的基本使用了,如果你对它的用法还不了解,建议您先阅读我之前的文章。 使用ConstraintLayout创建动画的基本思想是我们创建两个不同的布局,每个布局有其不同的约束,从而我们使用其动画框架来进行两种约束之间的切换。 传统动画 以往在我们创建简单动画时,通常我们会使用 视图动画(View Animation) 帧动画(Drawable Animation) 属性动画(Property Animation) 这三种在我们制作简单动画时非常简单和方便,特别是当我们只对某个特定的View制作动画时。但是当我们需要制作复杂动画时,特别是整个页面多个View同时执行动画时,这几种方式就显得力不从心了,需要大量的工作。 当然还有一种方式就是使用转场动画框架(Transition Framework),通过共享元素(Shared Element)制作动画,这个后面我们也会提到。 ConstraintLayout动画 我们这里通过一个示例来说明ConstraintLayout动画的创建。 首先,我们创建第一个布局(activity_main.xml),它是是我们的初始布局。 效果: 代码: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout android:id="@+id/cl_root" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/tv_score" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="评分:8.3分" app:layout_constraintStart_toStartOf="@+id/tv_name" app:layout_constraintTop_toBottomOf="@+id/tv_name" /> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="20dp" android:layout_marginTop="8dp" android:text="无敌破坏王2" android:textColor="#282828" android:textSize="20sp" app:layout_constraintStart_toEndOf="@+id/iv_poster" app:layout_constraintTop_toTopOf="@+id/iv_poster" /> <ImageView android:id="@+id/iv_poster" android:layout_width="120dp" android:layout_height="160dp" android:layout_marginStart="20dp" android:layout_marginTop="20dp" android:scaleType="centerCrop" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@mipmap/wreck_it_ralph" /> </android.support.constraint.ConstraintLayout> 我们的初始布局创建完毕后,我们需要创建一个动画结束布局,让动画框架知道执行完动画后布局是什么样的。 创建动画结束布局(activity_main_detail.xml)。 效果: 代码: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout android:id="@+id/cl_root" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/tv_score" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="52dp" android:text="评分:8.3分" app:layout_constraintBottom_toBottomOf="@+id/tv_name" app:layout_constraintStart_toEndOf="@+id/tv_name" app:layout_constraintTop_toTopOf="@+id/tv_name"/> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="20dp" android:layout_marginTop="20dp" android:text="无敌破坏王2" android:textColor="#282828" android:textSize="20sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/iv_poster" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="65dp" android:scaleType="centerCrop" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@mipmap/wreck_it_ralph" /> </android.support.constraint.ConstraintLayout> 这个页面是我们执行动画结束后的样子。那么开始和结束的布局我们都有了,我们怎样执行动画,让两个布局之间进行过渡呢? 答案是通过Android的TransitionManager来执行。 使用TransitionManager来执行动画 代码(MainActivity.java) package cn.examplecode.constraintlayoutdemo; import android.support.constraint.ConstraintLayout; import android.support.constraint.ConstraintSet; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.transition.TransitionManager; public class MainActivity extends AppCompatActivity { private ConstraintLayout mConstraintLayout; private boolean mIsDetail; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mConstraintLayout = findViewById(R.id.cl_root); ConstraintSet constraintSet1 = new ConstraintSet(); ConstraintSet constraintSet2 = new ConstraintSet(); constraintSet2.clone(this, R.layout.activity_main_detail); constraintSet1.clone(mConstraintLayout); findViewById(R.id.iv_poster).setOnClickListener(v -> { TransitionManager.beginDelayedTransition(mConstraintLayout); if (!mIsDetail) { constraintSet2.applyTo(mConstraintLayout); mIsDetail = true; } else { constraintSet1.applyTo(mConstraintLayout); mIsDetail = false; } }); } } 我们来解释以上代码。首先我们发现使用了这个类ConstraintSet,它是一个约束集合,保存了布局上所有元素的约束,因为我们需要在两个布局之间执行动画,所以我们需要创建两个约束集合的对象。 ConstraintSet constraintSet1 = new ConstraintSet(); ConstraintSet constraintSet2 = new ConstraintSet(); 创建完约束集对象后,我们需要设置每个约束集对应的约束: constraintSet2.clone(this, R.layout.activity_main_detail); constraintSet1.clone(mConstraintLayout); 这里我们将当前布局的约束应用到constraintSet1中,将目标布局的约束应用到constraintSet2中。 接下来我们执行动画: TransitionManager.beginDelayedTransition(mConstraintLayout); # 从constraintSet1过渡到constraintSet2 constraintSet2.applyTo(mConstraintLayout); # 从constraintSet2过渡到constraintSet1 constraintSet1.applyTo(mConstraintLayout); 最终效果: 只需简单的几行代码,就可以实现复杂的动画了!当然本示例为了说明ConstraintLayout动画的创建方法,布局比较简单。如果需要复杂布局的动画切换,这种方式的优势就非常明显。如果使用传统创建动画方法,则有可能需要大量的时间和代码来实现。 问题探讨 为什么需要创建两个布局文件? 可能有人认为创建两个布局文件不是一个好的方式,两个布局中存在重复的代码,这样好吗? 实际上可能并没有你想象的那么不好,创建两个布局文件的目的只是让动画框架知道不同的约束而已,然后将不同的约束应用在过渡动画中,你可以在布局中把与约束无关的属性去掉。如果你实在不喜欢创建两个布局文件的话,当然也可以在代码中来描述不同的约束。显然这样会大大增加复杂度和代码量。 与使用共享元素动画(Shared Element)有什么区别? 使用共享元素动画当然也可以实现这样的效果,但是使用共享元素动画你也需要创建两个布局,而且关键的不同是:使用ConstraintLayout执行动画时,动画前后的View是同一个View对象。而使用共享元素动画时动画前后的View是两个不同的View对象! 系列总结 本篇是本系列博客《掌握ConstraintLayout》的最后一篇。通过本系列的学习,相信你已经掌握了使用ConstraintLayout的大部分功能。 在实际开发的过程中,使用ConstraintLayout会使开发速度有不少的提升,再结合我的另一个系列《使用Data Binding》,会大大减少开发Android时的工作量,达到事半功倍的效果,提升生产力! 谢谢你的支持! 如有更多疑问,请参考我的其它Android相关博客:我的博客地址

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

swift4.1 系统学习十一 闭包

// // main.swift // swift11(闭包) // // Created by iOS on 2018/10/10. // Copyright © 2018年 weiman. All rights reserved. // import Foundation /* 闭包 闭包是swift中比较重要的一部分内容,也是个人认为比较难以理解的内容,也可能是之前没有 细细的研究的缘故。 1.闭包的概念 闭包是将一个函数与执行环境存放在一起的一条记录。 名字绑定:当闭包被创建的时候,它会将它所在的函数中的局部对象与它自己的执行环境中的对象名做一个值或者 引用的关联映射。这就是“名字绑定”。 捕获:如果闭包访问了它所在函数的局部对象,那么我们称它“捕获”了该局部对象。 注意: 由于闭包有自己的执行环境,我们称为上下文,因此即便当它所在的函数被返回值后,该闭包依然能正常调用。 问题:那么闭包什么时候被销毁呢? 我们之前提到过,捕获外部函数局部对象的嵌套函数属于命名闭包,它也是个闭包。但是,函数、闭包和方法还是各自独立的更好些。 */ do { func foo() { print("这是一个函数") } g_func = foo CTest() //打印结果: 这是一个函数 func boo() { var a = 10 func inner() { print("这是一个内部函数") } g_func = inner CTest() func closure() { a += 10 print("closure a = \(a)") } // 报错:A C function pointer cannot be formed from a local function that captures context // 函数指针不能指向闭包 //g_func = closure g_func = { print("哈哈哈哈哈") } CTest() struct MyStruct { let a: Int, b: Double func method() { print("a = \(a), b = \(b)") } static func typeMethod() { print("这是一个结构体") } } // 报错:A C function pointer can only be formed from a reference to a 'func' or a literal closure // g_func = MyStruct.typeMethod let obj = MyStruct(a: 10, b: 100.0) // 报错:A C function pointer can only be formed from a reference to a 'func' or a literal closure // g_func = obj.method } boo() /* 小结: 一个C函数指针对象只能指向一般的函数,包括不捕获其外部函数局部对象的嵌套函数,以及不捕获其外部函数局部对象的闭包。 */ } // 2. 闭包的定义与调用 /* 在swift中,一个闭包又称为“闭包表达式”。 基本语法形式: _ = { (参数1: 参数类型, 参数2: 参数类型....) -> 返回值类型 in 闭包执行代码 } */ do { _ = { () -> Void in print("这是一个简单的无参数的无返回值的闭包") } _ = { (a: Int) -> Void in print("这是一个有参数,无返回值的闭包,参数:a = \(a)") } // 有参数,有返回值的闭包,返回值是 () -> Void _ = { (a: Int, b: Int) -> () -> Void in let sum = a + b var x = sum * 2 return { () -> Void in print("sum = \(sum)") x += sum } } } // 闭包的调用 // 闭包的调用与函数的调用一样,可以直接在闭包表达式的后面使用函数调用操作符,形成完整的函数调用表达式。 do { print("\n ----------- 闭包的调用-------------") _ = { () -> Void in print("无参数无返回值的闭包") } () _ = { (a: Int) -> Void in print("a = \(a)") } (10) } // 3. 闭包表达式的简略表达(重点哟) /* 因为swift语言强大的类型推导特性,我们可以将闭包表达式简化。 */ do { //1.缺省返回类型的表达式 /* 如果一个函数的返回类型省略,则函数的返回类型就是Void,但是,如果闭包的返回类型省略, 则不一定是Void。 */ let ref = { (a: Int, b: Int) in return a + b } print("value = \(ref(1, 2))") // 结果: value = 3 // 上述闭包表达式中,返回值就是 (Int, Int)-> Int 类型 //2.缺省参数类型的闭包表达式 // swift不仅能够推导出闭包的返回值类型,还能推导出参数的类型,因此,闭包的形参也是可以省略的。 // 并且小括号也是可以省略的。如果闭包形参列表的圆括号省略了,那么每个形参的类型都必须缺省。 var ref2: (Int, Int) -> Int = { a, b in return a + b } print("1: \(ref2(2, 3))") ref2 = { a, b -> Int in return a + b } print("2: \(ref2(4, 6))") ref2 = { (a, b: Int) in return a + b } print("3: \(ref2(4, 5))") // 3. 缺省return关键字 // 如果闭包表达式中其执行语句只有一个单独的 return语句构成,那么关键字return也可以缺省 let ref3: (Int, Int) -> Int = { a, b in a + b } print("value = \(ref3(1, 1))") // 返回值是一个元组的第二个元素 print("\n") let ref4 = { (a: Int) -> Int in (print("a = \(a)"), a + 1).1 } print("value2 = \(ref4(3))") // 4. 省略 in 关键字 // 如果一个闭包确定其每个形参的类型以及返回类型,那么该表达式中连 in 关键字都能缺省。 // 当我们要引用其形参时使用 $ 符号加上形参索引:第一个形参的索引值为0,第二个索引值为1,后续参数 // 依次类推。 print("\n") var r: (Int, Int) -> Int = { $0 + $1 } print("value: \(r(3, 3))") let r2 = { print("hello") } r2() r = { print("第一个参数: \($0)") print("第二个参数: \($1)") return $0 + $1 } print("result: \(r(5, 8))") let r3: (Int) -> Void = { print("参数: \($0)") let a = $0 * $0 print("a = \(a)") } r3(5) } // 4. 尾随闭包 /* 如果一个闭包表达式作为函数调用的最后一个实参,那么我们可以采用“尾随闭包”语法糖。 */ do { print("\n ----------尾随闭包---------------") func foo(_ a: Int, callback: (Int) -> Void) { callback(a) } foo(10) { (aa) in print("参数是 \(aa)") } //或者简写 foo(12, callback: { print("参数: \($0)")}) //尾随闭包, 这个时候callback标签必须省略 foo(14){ print("参数是: \($0)") } func boo (_ a: Int, _ b: Int, callback: ((Int, Int) -> Int)?) { if let callback = callback { let value = callback(a, b) print("value = \(value)") } } boo(2, 3) { (a: Int, b: Int) -> Int in return a * a + b * b } } // 5. 捕获局部对象与闭包执行上下文 // 闭包所捕获的对象是按照引用进行捕获的,同时闭包本身是一个引用对象。 do { print("\n ----------捕获局部对象与闭包执行上下文---------------") var a = [1, 2, 3] var b = a a[0] += 10 print("a = \(a)") // 结果: a = [11, 2, 3] func foo() { var a = 10 let closure = { print("a = \(a)") } closure() a += 10 closure() } foo() /* 结果: a = 10 a = 20 */ func boo() -> () -> Void { var x = 10 return { x += 10 print("x = \(x)") } } var closure = boo() var ref = closure closure() ref() closure() /* 结果: x = 20 x = 30 x = 40 */ // 重新赋值后再次调用 ref = boo() closure() ref() /* 结果: x = 50 x = 20 */ /* 小结: 上述实例证明了闭包属于引用类型,闭包所捕获的外部局部对象也是以引用的方式 捕获的。 */ } // 6. 逃逸闭包 /* 如果我们定义了一个函数,它有一个形参为函数类型,如果在此函数中将通过异步的方式调用该函数引用对象, 那么我们需要将此函数类型声明为“逃逸的”,以表示该函数类型的形参对象将可能在函数调用操作结束后的某一 时刻才会被调用。 */ do { print("\n --------逃逸闭包----------") var ref: (() -> Void)! func foo(closure: @escaping () -> Void) { ref = closure } foo { print("你好") } ref() } // 7. 自动闭包 /* 自动闭包也是swift中的一个语法糖。如果一个函数的某个形参为函数类型,并且不含有任何形参,那么我们 就可以将此参数声明为“自动闭包”。 */ do { print("\n---------自动闭包----------") func foo(closure: () -> Void) { closure() } foo { print("简单的闭包") } func boo(auto closure: @autoclosure () -> Void) { closure() } boo(auto: print("这是个自动闭包")) func doo() { let a = 1, b = -1 func isLarger(compare: @autoclosure () -> Bool) -> Bool { return compare() } let result = isLarger(compare: a > b) print("result: \(result)") } doo() /* 小结: 不推荐各位在制作公共的API的时候使用自动闭包。 */ } 辅助文件: // // Test.h // swift11(闭包) // // Created by iOS on 2018/10/10. // Copyright © 2018年 weiman. All rights reserved. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface Test : NSObject extern void (^ _Nullable g_block)(void); // 指向函数的指针 extern void (* _Nullable g_func)(void); extern void CTest(void); @end NS_ASSUME_NONNULL_END // // Test.m // swift11(闭包) // // Created by iOS on 2018/10/10. // Copyright © 2018年 weiman. All rights reserved. // #import "Test.h" @implementation Test void (^ g_block)(void) = NULL; void (* g_func)(void) = NULL; void CTest(void) { if (g_block != NULL) { g_block(); } if (g_func != NULL) { g_func(); } } @end

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

Java并发编程的艺术(十一)——线程池(2)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/79612326 Executor两级调度模型 在HotSpot虚拟机中,Java中的线程将会被一一映射为操作系统的线程。在Java虚拟机层面,用户将多个任务提交给Executor框架,Executor负责分配线程执行它们;在操作系统层面,操作系统再将这些线程分配给处理器执行。 Executor结构 Executor框架中的所有类可以分成三类: 任务任务有两种类型:Runnable和Callable。 任务执行器Executor框架最核心的接口是Executor,它表示任务的执行器。Executor的子接口为ExecutorService。ExecutorService有两大实现类:ThreadPoolExecutor和ScheduledThreadPoolExecutor。 执行结果Future接口表示异步的执行结果,它的实现类为FutureTask。 线程池 Executors工厂类可以创建四种类型的线程池,通过Executors.newXXX即可创建。 1. FixedThreadPool public static ExecutorService newFixedThreadPool(int nThreads){ return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); } 1 2 3 它是一种固定大小的线程池; corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads; keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效; 阻塞队列采用了LinkedBlockingQueue,它是一个无界队列; 由于阻塞队列是一个无界队列,因此永远不可能拒绝任务; 由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。 2. CachedThreadPool public static ExecutorService newCachedThreadPool(){ return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>()); } 1 2 3 它是一个可以无限扩大的线程池; 它比较适合处理执行时间比较小的任务; corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大; keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死; 采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。 3. SingleThreadExecutor public static ExecutorService newSingleThreadExecutor(){ return new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); } 1 2 3 它只会创建一条工作线程处理任务; 采用的阻塞队列为LinkedBlockingQueue; 4. ScheduledThreadPool 它用来处理延时任务或定时任务。 它接收SchduledFutureTask类型的任务,有两种提交任务的方式: scheduledAtFixedRate scheduledWithFixedDelay SchduledFutureTask接收的参数: time:任务开始的时间 sequenceNumber:任务的序号 period:任务执行的时间间隔 它采用DelayQueue存储等待的任务 DelayQueue内部封装了一个PriorityQueue,它会根据time的先后时间排序,若time相同则根据sequenceNumber排序; DelayQueue也是一个无界队列; 工作线程的执行过程: 工作线程会从DelayQueue取已经到期的任务去执行; 执行结束后重新设置任务的到期时间,再次放回DelayQueue

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

java面试-Java并发编(十一)——线程池(2)

Executor两级调度模型 在HotSpot虚拟机中,Java中的线程将会被一一映射为操作系统的线程。在Java虚拟机层面,用户将多个任务提交给Executor框架,Executor负责分配线程执行它们;在操作系统层面,操作系统再将这些线程分配给处理器执行。 Executor结构 Executor框架中的所有类可以分成三类: 任务任务有两种类型:Runnable和Callable。 任务执行器Executor框架最核心的接口是Executor,它表示任务的执行器。Executor的子接口为ExecutorService。ExecutorService有两大实现类:ThreadPoolExecutor和ScheduledThreadPoolExecutor。 执行结果Future接口表示异步的执行结果,它的实现类为FutureTask。 线程池 Executors工厂类可以创建四种类型的线程池,通过Executors.newXXX即可创建。 1. FixedThreadPool public static ExecutorService newFixedThreadPool(int nThreads){ return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); } 1 2 3 它是一种固定大小的线程池; corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads; keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效; 阻塞队列采用了LinkedBlockingQueue,它是一个无界队列; 由于阻塞队列是一个无界队列,因此永远不可能拒绝任务; 由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。 2. CachedThreadPool public static ExecutorService newCachedThreadPool(){ return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>()); } 1 2 3 它是一个可以无限扩大的线程池; 它比较适合处理执行时间比较小的任务; corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大; keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死; 采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。 3. SingleThreadExecutor public static ExecutorService newSingleThreadExecutor(){ return new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); } 1 2 3 它只会创建一条工作线程处理任务; 采用的阻塞队列为LinkedBlockingQueue; 4. ScheduledThreadPool 它用来处理延时任务或定时任务。 它接收SchduledFutureTask类型的任务,有两种提交任务的方式: scheduledAtFixedRate scheduledWithFixedDelay SchduledFutureTask接收的参数: time:任务开始的时间 sequenceNumber:任务的序号 period:任务执行的时间间隔 它采用DelayQueue存储等待的任务 DelayQueue内部封装了一个PriorityQueue,它会根据time的先后时间排序,若time相同则根据sequenceNumber排序; DelayQueue也是一个无界队列; 工作线程的执行过程: 工作线程会从DelayQueue取已经到期的任务去执行; 执行结束后重新设置任务的到期时间,再次放回DelayQueue

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

[Android学习十一]Android开发单元测试

自从投入到Android Studio IDE之后基本上就赖着不走了。这里仅讨论AS(Android Studio)中Android单元测试。 开发一个Android应用单元测试这种程序员的自我修养和基本道德测试是必不可少的。其单元测试分为两块,一块是依赖Android API(平台)的单元测试,一块是不依赖Android API的单元测试。 1.不依赖AndroidAPI的单元测试 这一块就和通常开发JavaSE,EE应用的单元测试一样,测试框架更加需要自行选择即可。在通过AS创建Android应用模块时,默认在build.gradle文件中添加了测试库junit依赖。 如果在AS中使用不依赖AndroidAPI的单元测试,一图顶万言: 图一 图二 如图二所示,在Build Variants的Test Artifact设置为Unit tests之后,test源码目录呈现出IDEA风格的绿色目录。 这是就可以运行测试类或测试套件,比较容易就不多解释了。 2. 依赖Android API的单元测试 2.1 AS中配置Android单元测试 Android基于junit3框架提供了Android的单元测试框架,要在Android中使用单元测试就需要依赖android.test包下的具体类。下面是AS中配置Android单元测试的方法: 图三 2.2 Android单元测试示例 2.2.1 一个单元测试类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package secondriver.heathfood.test; import android.test.InstrumentationTestCase; import com.orhanobut.logger.Logger; import secondriver.heathfood.App; import secondriver.heathfood.logic.TianGou; import secondriver.heathfood.pojo.FoodClassResult; import secondriver.heathfood.pojo.FoodDetail; import secondriver.heathfood.pojo.FoodDetailResult; /** *Author:secondriver *Created:2016/1/20 */ public class TestTianGou extends InstrumentationTestCase{ public TianGoutianGou; public void setUp(){ tianGou= new TianGou(App.restTemplate()); } public void test_queryFoodClassByParentId1(){ FoodClassResultresult=tianGou.queryFoodClassByParentId( 0 ); assertTrue(result.isStatus()); } } 关于Android的单元测试基类参见: http://www.oschina.net/question/54100_27061?fromerr=NydwIvQR。 http://www.uml.org.cn/mobiledev/201306074.asp 注意:Android单元测试的测试类写法遵循的是Junit3. 2.2.2 执行单元测试 在执行单元测试之前,讲Build Variant的Test Artifact设置为图一所示值。 执行Android Tester之后,输出截图: 图四 从截图上得知未授网络访问权权限。 2.2.3 AS中Android单元测试控制台 图五 在网上找关于Android单元测试的案例时,比较杂乱,遂作此文予以整理,Android单元测试如何去做当是另外的主题,需要参考android.test包中提供的具体类。 文中的android测试类的包直接创建在了main代码目录下,比较好的方式如下Android测试代码目录结构图: 图 六 本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1737254,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

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

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

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

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册