首页
About
友情链接
Search
1
RustDesk远程桌面工具自建服务器教程
2,206 阅读
2
V2ray配置文件翻译
1,579 阅读
3
draw.io(diagrams.net) - 免费开源全平台绘图软件
1,214 阅读
4
Android 11 中的软件包可见性
1,117 阅读
5
Windows常用软件
976 阅读
Uncategorized
Software
Android
Linux
Communist Party of China
Docker
Windows
Tools
登录
Search
Leon
累计撰写
36
篇文章
累计收到
48
条评论
首页
栏目
Uncategorized
Software
Android
Linux
Communist Party of China
Docker
Windows
Tools
页面
About
友情链接
搜索到
4
篇与
Android
的结果
2022-11-04
Kotlin协程
Kotlin协程就像 Java 中的 Executor 和 Android 中的 AsyncTask,Kotlin 中的协程也有对 Thread API 的封装,让我们可以在写代码时,不用关注多线程就能够很方便地写出并发操作。Kotlin协程是由官方提供的一套线程API,使用看起来同步方式写异步代码——非堵塞式挂起。消除回调launch({ val user = api.getUser() // 网络请求(IO 线程) nameTv.text = user.name // 更新 UI(主线程) }) api.getUser() .enqueue(object : Callback<User> { override fun onResponse(call : Call<User>, response:Response<User>){ runOnUiThread { nameTv.text = response.body()?.name } } })suspend 是 Kotlin 协程最核心的关键字,代码执行到 suspend 函数的时候会挂起,并且这个挂起是非阻塞式的,它不会阻塞你当前的线程。launch ,async 或者其他函数创建的协程,在执行到某一个 suspend 函数的时候,这个协程会被suspend,也就是被挂起。GlobalScope.launch(Dispatchers.Main) { val image = suspendingGetImage(imageId) // 获取图片 avatarIv.setImageBitmap(image) // 显示出来 } suspend fun suspendingGetImage(id: String) = withContext(Dispatchers.IO) { ... } suspend fun suspendUntilDone() { while (!done) { delay(5) } }但是suspend fun suspendingPrint() { println("Thread: ${Thread.currentThread().name}") }输出的结果还是在主线程。通过 withContext 源码可以知道,它本身就是一个挂起函数,它接收一个 Dispatcher 参数,依赖这个 Dispatcher 参数的指示,协程被挂起,然后切到别的线程。public suspend fun <T> withContext( context: CoroutineContext, block: suspend CoroutineScope.() -> T ): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return suspendCoroutineUninterceptedOrReturn sc@ { uCont -> // 计算新上下文 val oldContext = uCont.context val newContext = oldContext + context // 始终检查新上下文的取消 newContext.ensureActive() // FAST PATH #1 -- 新上下文与旧上下文相同 if (newContext === oldContext) { val coroutine = ScopeCoroutine(newContext, uCont) return@sc coroutine.startUndispatchedOrReturn(coroutine, block) } // FAST PATH #2 -- 新dispatcher与旧dispatcher相同(发生了变化) // `equals` 被设计使用 if (newContext[ContinuationInterceptor] == oldContext[ContinuationInterceptor]) { val coroutine = UndispatchedCoroutine(newContext, uCont) // There are changes in the context, so this thread needs to be updated withCoroutineContext(newContext, null) { return@sc coroutine.startUndispatchedOrReturn(coroutine, block) } } // SLOW PATH -- 使用新的dispatcher val coroutine = DispatchedCoroutine(newContext, uCont) block.startCoroutineCancellable(coroutine, coroutine) coroutine.getResult() } }所以这个 suspend,其实并不是起到把任何协程挂起,或者说切换线程的作用。真正挂起协程这件事,是 Kotlin 的协程框架帮我们做的。所以我们想要自己写一个挂起函数,仅仅只加上 suspend 关键字是不行的,还需要函数内部直接或间接地调用到 Kotlin 协程框架自带的 suspend 函数才行。在 Kotlin 里,协程就是基于线程来实现的一种更上层的工具 API,类似于 Java 自带的 Executor 系列 API 或者 Android 的 Handler 系列 API。协程它不仅提供了方便的 API,在设计思想上是一个基于线程的上层框架协程就是切线程。挂起就是可以自动切回来的切线程。挂起的非阻塞式指的是它能用看起来阻塞的代码写出非阻塞的操作。
2022年11月04日
26 阅读
0 评论
0 点赞
2021-12-10
Android启动流程
init进程 –-> Zygote进程 –> SystemServer进程 –>应用进程1、启动电源以及系统启动:当电源按下时引导芯片从预定义的程序(固化在ROM)开始执行,加载引导程序BootLoader到RAM,然后执行。2、引导程序BootLoader:BootLoader是在Android系统开始运行前的一个小程序,主要用于把系统OS拉起来并运行。3、Linux内核启动:当内核启动时,设置缓存、被保护存储器、计划列表、加载驱动。当其完成系统设置时,会先在系统文件中寻找init.rc文件,并启动init进行。4、init进程启动:初始化和启动属性服务,并且启动Zygote进程。5、Zygote进程启动:创建JVM并为其注册JNI方法,创建服务器端Socket,启动SystemServer进程。6、SystemServer进程启动:启动Binder线程池和SystemServiceManager,并且启动各种系统服务。7、Launcher启动:被SystemServer进程启动的AMS会启动Launcher,Launcher启动后会将已安装应用的快捷图标显示到系统桌面上。启动电源以及系统启动当电源按下时引导芯片代码会从预定义的地方(固化在ROM)开始执行,加载引导程序BootLoader到RAM,然后执行。引导程序BootLoader它是Android操作系统开始运行前的一个小程序,主要将操作系统OS拉起来并进行。Linux内核启动当内核启动时,设置缓存、被保护存储器、计划列表、加载驱动。此外,还启动了Kernel的swapper进程(pid = 0)和kthreadd进程(pid = 2)。swapper进程:又称为idle进程,系统初始化过程Kernel由无到有开创的第一个进程, 用于初始化进程管理、内存管理,加载Binder Driver、Display、Camera Driver等相关工作。kthreadd进程:Linux系统的内核进程,是所有内核进程的鼻祖,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等内核守护进程。当内核完成系统设置时,它首先在系统文件中寻找init.rc文件,并启动init进程。init进程init进程主要用来初始化和启动属性服务,并且启动Zygote进程。init进程是Linux系统的用户进程,是所有用户进程的鼻祖,进程号为1,它有许多重要的职责,比如创建Zygote孵化器和属性服务等。并且它是由多个源文件组成的,对应源码目录system/core/init中。1、创建和挂载启动所需的文件目录。2、初始化和启动属性服务。3、解析init.rc配置文件并启动Zygote进程。ZygoteZygote是在init进程启动时创建的,它又称为孵化器,它可以通过fork(复制进程)的形式来创建应用程序进程和SystemServer进程。并且,Zygote进程在启动的时候回创建DVM或者ART,因此通过fork而创建的应用程序进程和SystemServer进程可以在内部获取一个DVM或者ART的实例副本。1、创建AppRuntime,执行其start方法,启动Zygote进程。。2、创建JVM并为JVM注册JNI方法。3、使用JNI调用ZygoteInit的main函数进入Zygote的Java FrameWork层。4、使用registerZygoteSocket方法创建服务器端Socket,并通过runSelectLoop方法等等AMS的请求去创建新的应用进程。5、启动SystemServer进程。SystemServer进程SystemService进程被创建后,主要的处理如下:1、启动Binder线程池,这样就可以与其他进程进行Binder跨进程通信。2、创建SystemServiceManager,它用来对系统服务进行创建、启动和生命周期管理。3、启动各种系统服务:引导服务、核心服务、其他服务,共100多种。应用开发主要关注引导服务ActivityManagerService、PackageManagerService和其他服务WindowManagerService、InputManagerService即可。SystemServer进程主要是用于创建系统服务的,例如AMS、WMS、PMS。这篇文章将从以下两个部分来对SystemServer进行分析:Zygote处理SystemServer进程SystemServer进程解析Launcher进程Android系统启动的最后一步就是启动了一个Launcher应用程序来显示系统中已经安装的应用程序。Launcher在启动的过程中会请求请求PMS返回系统中已安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,从而使得用户可以点击这些快捷图片来启动相应的应用程序。Launcher作为Android系统的桌面,它的作用有两点:1、作为Android系统的启动器,用于启动应用程序。2、作为Android系统的桌面,用于显示和管理应用程序的快捷图标或者其它桌面组件。
2021年12月10日
41 阅读
0 评论
0 点赞
2021-09-01
Android 11 中的软件包可见性
官方文档:Android 11 中的软件包可见性 这个特性直接导致了如下错误:如果不在content provider的client的AndroidManifest.xml声明标签: <queries> <package android:name="com.fxkxb.mycontentprovider" /> <provider android:authorities="com.fxkxb.mycontentprovider.provider"/> </queries> <uses-permission android:name="com.fxkxb.mycontentprovider"/>就会导致Failed to find provider info for错误。
2021年09月01日
1,117 阅读
7 评论
1 点赞
2021-08-13
Android Studio单元测试的编码过程
Android Studio单元测试的编码过程前言本次单元测试过程中遇到了很多很多很多很多问题,技术更新迭代速度实在是太快了,网上搜到的很多东西都过时了,这里找到了一个五年前印度小哥的教学录屏[1]......本来英语不好的我听着蹩脚的印度英语,实在是折磨QAQ....不过总体上按照他的步骤是可行的,期间遇到的各种问题也用过搜索解决了,最终磕磕绊绊完成了简单的单元测试编写。于是有了这篇技术总结。设置测试环境在测试开始前,首先添加 AndroidX Test API[2],以及为项目配置 Android 测试依赖项。最终的在应用的顶级 build.gradle 文件中,依赖项如下:dependencies { androidTestImplementation "org.mockito:mockito-core:2.18.0" androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test:rules:1.4.0' androidTestImplementation 'org.hamcrest:hamcrest-library:1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' }同时确保 defaultConfig { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" }使用Android Studio生成测试类鼠标标记要生成的类,按Alt+Enter,选择第一个。在创建测试类窗口中,测试库我们选择JUnit4。类名可以自定义,建议不要改。父类不选,目标包就是项目包名,勾选setUp和tearDown。最后在要测试的方法前打勾。点击OK。随即弹出窗口提示我们选择测试类类型,我们选Android的测试类。由此我们得到了一个测试类,按Shift+Ctrl+T可在测试类与Activity间切换,这里创建rule并实例化。 @Rule public ActivityTestRule<FirstActivity> mainActivityActivityTestRule = new ActivityTestRule<FirstActivity>(FirstActivity.class); private FirstActivity firstActivity = null; @Before public void setUp() throws Exception { firstActivity = mainActivityActivityTestRule.getActivity(); }这样我们就可以通过实例化的rule来获取页面元素。a Simple Example: 测试文本是否为空。UT代码:TextView t = firstActivity.findViewById(R.id.textView10); assertNull(t.getText()); 2. 点击测试方法左边的绿三角即可开始测试。 ![image-20210813060836192.png][4] 以我的程序为例,来测试LED小灯的点亮功能。@Test public void light() { firstActivity.power = true; TextView[] leds = {firstActivity.findViewById(R.id.textView4), firstActivity.findViewById(R.id.textView6), firstActivity.findViewById(R.id.textView5), firstActivity.findViewById(R.id.textView7)}; int[] ledStatus = {1, 1, 0, 0}; final Drawable.ConstantState drawable = leds[0].getBackground().getConstantState(); final Drawable.ConstantState drawable2 = leds[1].getBackground().getConstantState(); firstActivity.light(ledStatus,leds); final Drawable.ConstantState drawable1 = leds[0].getBackground().getConstantState(); final Drawable.ConstantState drawable3 = leds[1].getBackground().getConstantState(); assertEquals(drawable,drawable1); assertNotEquals(drawable2,drawable3); } 我的Activity部分。 public void light(int[] b, TextView[] t) { for (int i = 0; i < 4; i++) { switch (i) { case 0: if (b[i]==1) { if (power) { t[i].setBackgroundResource(R.drawable.lightred); } } else if (b[i]==-1){ break; }else { t[i].setBackgroundResource(R.drawable.light); } ; break; case 1: if (b[i]==1) { if (power) { t[i].setBackgroundResource(R.drawable.lightgreen); } } else if (b[i]==-1){ break; } else { t[i].setBackgroundResource(R.drawable.light); } ; break; case 2: if (b[i]==1) { if (power) { t[i].setBackgroundResource(R.drawable.lightblue); } } else if (b[i]==-1){ break; } else { t[i].setBackgroundResource(R.drawable.light); } ; break; case 3: if (b[i]==1) { if (power) { t[i].setBackgroundResource(R.drawable.lightup); } } else if (b[i]==-1){ break; } else { t[i].setBackgroundResource(R.drawable.light); } ; break; default: break; } } }点击测试类左边的双绿三角可开始测试类中全部测试方法的测试。 我的测试结果:参考文献Android app development for beginners - 26 - Android - Unit test for Activity - Activity Test Rule: https://www.youtube.com/watch?v=_TR6QcRozAgSet up project for AndroidX Test: https://developer.android.com/training/testing/set-up-projectBuild instrumented unit tests: https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests#javaAndroid单元测试(二):Mockito框架的使用: https://blog.csdn.net/qq_17766199/article/details/78450007Q&A on stackoverflow: https://stackoverflow.com/questions/13621407/getting-the-current-background-id-of-a-viewAndroid单元测试-对Activity的测试: https://blog.csdn.net/Double2hao/article/details/77160950
2021年08月13日
744 阅读
1 评论
0 点赞