一.前言
二.场景一:无操作符,无线程切换
代码如下(为了便于学习理解,使用了部分中文作为变量,选取的是Single)
//1.创建被观察者
var 被观察者 = Single.just("123") //分析1
//2.创建观察者
var 观察者 = object : SingleObserver {
override fun onSuccess(t: String) {
println("test ---> $t")
}
override fun onSubscribe(d: Disposable) {
}
override fun onError(e: Throwable) {
}
}
//3.被观察者订阅观察者
被观察者.subscribe(观察者) //分析2
上面这段代码,会将just方法中的参数传递到给SingleObserver匿名内部类的onSuccess方法中;我们逐步分析其是如何实现的;
看一下分析1的源码:被观察者的创建
//Single.java
public static Single just(final T item) {
ObjectHelper.requireNonNull(item, "item is null");//校验,忽略
return RxJavaPlugins.onAssembly(new SingleJust(item));//RxJavaPlugins.onAssembly,钩子函数,忽略
}
//SingleJust.java
public final class SingleJust extends Single {
final T value;
public SingleJust(T value) {
this.value = value;
}
@Override
protected void subscribeActual(SingleObserver observer) {
observer.onSubscribe(Disposables.disposed());
observer.onSuccess(value);
}
}
Single.just(“123”)实际上就是创建了一个SingleJust对象,也就是被观察者 。而观察者 的创建是通过一个SingleObserver的匿名内部类来构建,订阅 对应的是subscribe方法;
看一下分析2的源码:
//Single.java
public final void subscribe(SingleObserver observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
observer = RxJavaPlugins.onSubscribe(this, observer);
ObjectHelper.requireNonNull(observer, "The RxJavaPlugins.onSubscribe hook returned a null SingleObserver. Please check the handler provided to RxJavaPlugins.setOnSingleSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins");
try {
subscribeActual(observer);//分析3
} catch (NullPointerException ex) {
throw ex;
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
NullPointerException npe = new NullPointerException("subscribeActual failed");
npe.initCause(ex);
throw npe;
}
}
在分析2位置,变量“被观察者”是指向SingleJust对象的(多态),那么对应分析3可以知道会执行SingleJust的subscribeActual方法,看一下源码
//其中,方法中的参数为分析2位置中传递的观察者
protected void subscribeActual(SingleObserver observer) {
//调用观察者的onSubscribe和onSuccess方法
observer.onSubscribe(Disposables.disposed());
observer.onSuccess(value);
}
通过场景一,我们对被观察者 /观察者 /订阅 有个认识。
上面三步的源码分析,实际就是<被观察者>会“持有”(并非真正的持有,而是通过方法传递观察者)<观察者>的引用,当<被观察者>调用了订阅(subscribe)方法,就会通过<观察者>的引用去调用<观察者>自己的方法;如此,从<被观察者>那里产生的事件<我们统一先理解为数据吧,后续也这么理解,虽然有些不规范,但利于学习>会传递到给<观察者>的方法中;经过上面的分析,<数据>形成了流动。我们再来复杂一点的,加上操作符map。
三.场景二:在场景一的基础上增加map操作符
//1.创建被观察者
var 被观察者2 = Single.just("123")
//2.创建观察者
var 观察者2 = object : SingleObserver {
override fun onSuccess(t: String) {
println("test ---> $t")
}
override fun onSubscribe(d: Disposable) {
}
override fun onError(e: Throwable) {
}
}
//3.调用map操作符(创建新的被观察者)
var 被观察者3 = 被观察者2
.map { it -> "$it ---> 操作符原理" } //分析4
//4.<被观察者3>调用订阅方法
被观察者3.subscribe(观察者2) //位置5
public final Single map(Function mapper) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
return RxJavaPlugins.onAssembly(new SingleMap(this, mapper)); //分析5
}
分析5的位置实际上就是创建SingleMap对象(同样的前面的钩子函数忽略),通过场景一,我们可以分析到,“被观察者2”指向的是SingleJust,也就是分析5位置SingleMap的第一个参数是SingleJust,第二个参数是分析4位置传递过来的,那么,位置5的“被观察者3”实际上就是指向SingleMap,当调用位置5的代码时会执行SingleMap的subscribeActual方法(根据场景一可知);
分析SingleMap的subscribeActual方法的源码
public final class SingleMap extends Single {
final SingleSource source;
final Function mapper;
public SingleMap(SingleSource source, Function mapper) {
this.source = source;
this.mapper = mapper;
}
@Override
protected void subscribeActual(final SingleObserver t) {
//分析6
source.subscribe(new MapSingleObserver(t, mapper));
}
static final class MapSingleObserver implements SingleObserver {
final SingleObserver t;
final Function mapper;
MapSingleObserver(SingleObserver t, Function mapper) {
this.t = t;
this.mapper = mapper;
}
@Override
public void onSubscribe(Disposable d) {
t.onSubscribe(d);//位置7
}
@Override
public void onSuccess(T value) {
R v;
try {
v = ObjectHelper.requireNonNull(mapper.apply(value), "The mapper function returned a null value.");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
onError(e);
return;
}
t.onSuccess(v);//位置8
}
@Override
public void onError(Throwable e) {
t.onError(e);
}
}
}
看一下分析6的代码
通过分析5我们知道,分析6位置的source表示SingleJust,分析6的位置其逻辑是,通过SingleJust的引用执行订阅操作,订阅方法的参数是一个新的观察者(MapSingleObserver),新观察者持有“观察者2”的引用以及通过map操作符传递过来的mapper参数。
当SingleJust执行订阅方法时,会触发SingleJust的subscribeActual方法,结合前面的分析,会执行MapSingleObserver的onSubscribe和onSuccess方法。于是位置7和位置8就会执行“观察者2”的onSubscribe和onSuccess方法。
到此,“被观察者2”位置传递的参数就传递到了“观察者2”对应的回调方法中,也就是增加了map操作符的情况下,订阅逻辑以及<数据>传递逻辑就理顺了。
我们通过一张图来总结一下:
Api从上往下的调用所创建的被观察者我们分别成为上游被观察者和下游被观察者,我们自己主动创建的观察者我们称为下游观察者,该图解释了,在Api调用过程中对应的被观察者的创建以及上游观察者的创建。同时,被观察者与被观察者,被观察者与观察者之间的持有关系;
至此,前言中所提及的需要清楚的概念和需要验证的结论已经明确了。下面总结一下Rxjava的核心原理 :最下游的被观察者订阅最下游的观察者时(对应上图Api最下方的代码),会创建新的观察者作为下游观察者的上游并持有下游观察者,同时会触发其上游被观察者订阅刚创建的上游观察者。当最上游的被观察者执行了订阅方法,会去回调自身的subscribeActual方法,在该方法内部会调用最上游观察者的api,由于上游的观察者是持有下游观察者的,如此,会触发调用下游的观察者的方法,直到触发我们自己定义的最下游的观察者中的回调。即订阅是从下游逐步往上游触发,数据是从上游逐步往下游传递。
四.场景三:在场景二的基础上增加线程切换
4.1.subscribeOn切换线程的原理
Single.just("123").map { it -> "$it ---> 操作符原理" }
.subscribeOn(Schedulers.io())//分析9
.observeOn(AndroidSchedulers.mainThread())//分析10
.subscribe(object : SingleObserver {
override fun onSuccess(t: String) {
}
override fun onSubscribe(d: Disposable) {
}
override fun onError(e: Throwable) {
}
})
//Single.java
public final Single subscribeOn(final Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new SingleSubscribeOn(this, scheduler)); //分析11
}
//SingleSubscribeOn.java
public final class SingleSubscribeOn extends Single {
final SingleSource source;
final Scheduler scheduler;
public SingleSubscribeOn(SingleSource source, Scheduler scheduler) {
this.source = source;
this.scheduler = scheduler;
}
@Override
protected void subscribeActual(final SingleObserver observer) {
final SubscribeOnObserver parent = new SubscribeOnObserver(observer, source);
observer.onSubscribe(parent);
Disposable f = scheduler.scheduleDirect(parent);//分析12
parent.task.replace(f);
}
static final class SubscribeOnObserver
extends AtomicReference
implements SingleObserver, Disposable, Runnable {
//...
public void run() {
source.subscribe(this);
}
}
}
//抽象类 Scheduler.java
public Disposable scheduleDirect(@NonNull Runnable run) {
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);//分析13
}
//分析13的源码
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();//分析14
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);//钩子函数,忽略
DisposeTask task = new DisposeTask(decoratedRun, w);//位置15
w.schedule(task, delay, unit);//分析16
return task;
}
public abstract Worker createWorker();
//会执行其子类的createWorker,具体的是IoScheduler类的createWorker方法,因为在调用subscribeOn(Schedulers.io())时传入了Schedulers.io(),而通过分析Schedulers.io()就可以知道。
//Schedulers.java
public static Scheduler io() {
return RxJavaPlugins.onIoScheduler(IO);//忽略钩子函数,查看IO即可
}
static {
//...
IO = RxJavaPlugins.initIoScheduler(new IOTask());//忽略钩子函数,查看IOTask
//...
}
static final class IOTask implements Callable {
@Override
public Scheduler call() throws Exception {
return IoHolder.DEFAULT;
}
}
//查看IoHolder.DEFAULT
static final class IoHolder {
static final Scheduler DEFAULT = new IoScheduler();
}
现在我们知道分析14的位置,createWorker方法会调用IoScheduler类的createWorker方法,进入查看,可以知晓Worker指向的是EventLoopWorker。
//IoScheduler.java
public Worker createWorker() {
return new EventLoopWorker(pool.get());
}
static final class EventLoopWorker extends Scheduler.Worker {
//...
EventLoopWorker(CachedWorkerPool pool) {
this.pool = pool;
this.tasks = new CompositeDisposable();
this.threadWorker = pool.get();
}
//...
@NonNull
@Override
public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
if (tasks.isDisposed()) {
// don't schedule, we are unsubscribed
return EmptyDisposable.INSTANCE;
}
return threadWorker.scheduleActual(action, delayTime, unit, tasks);//分析17
}
}
位置15将Work和run(传递过来的新观察者)做了封装,分析16最终会执行EventLoopWorker的scheduleActual方法,最终会执行到分析17位置
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
Runnable decoratedRun = RxJavaPlugins.onSchedule(run);//钩子函数,忽略
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);//位置18
if (parent != null) {
if (!parent.add(sr)) {
return sr;
}
}
Future f;
try {
if (delayTime <= 0) {
f = executor.submit((Callable)sr);//分析19
} else {
f = executor.schedule((Callable)sr, delayTime, unit);
}
sr.setFuture(f);
} catch (RejectedExecutionException ex) {
if (parent != null) {
parent.remove(sr);
}
RxJavaPlugins.onError(ex);
}
return sr;
}
位置18的decoratedRun实际上还是scheduleActual方法的第一个参数run,也就是前面的DisposeTask,由于delayTime是等于0的,会执行到分析19,这里使用到了线程池,最终会执行sr(ScheduledRunnable)的call()方法,查看ScheduledRunnable的call()方法
public final class ScheduledRunnable extends AtomicReferenceArray
implements Runnable, Callable, Disposable {
//...
public ScheduledRunnable(Runnable actual, DisposableContainer parent) {
super(3);
this.actual = actual;
this.lazySet(0, parent);
}
//...
public Object call() {
// Being Callable saves an allocation in ThreadPoolExecutor
run();
return null;
}
@Override
public void run() {
lazySet(THREAD_INDEX, Thread.currentThread());
try {
try {
actual.run();//分析20
} catch (Throwable e) {
//...
}
} finally {
//...
}
}
//...
}
后面就执行到了分析20位置,而actual参数为DisposeTask,最终会执行DisposeTask的run方法
//Scheduler.java
public void run() {
runner = Thread.currentThread();
try {
decoratedRun.run();//分析21
} finally {
dispose();
runner = null;
}
}
分析21,通过前面的分析可以知道,decoratedRun是SubscribeOnObserver,也就是会执行SubscribeOnObserver的run方法,查看其方法
//SingleSubscribeOn.java的内部类SubscribeOnObserver
public void run() {
source.subscribe(this);//执行上游的订阅操作
}
到此,我们清楚了subscribeOn切换线程的原理 :先做切换线程然后上游的被观察者再做订阅。
当多次调用subscribeOn时,只有第一次调用的subscribeOn才生效(因为只有最上游的才会生效);
4.2.observeOn切换线程的原理
清楚了subscribeOn切换线程的原理,observeOn切换线程的原理实际上会容易一些,大家可以按照4.1中的分析进行源码梳理,这里就直接写出结论。
observeOn切换线程的原理 :先使上游的被观察者进行订阅,然后在上游的观察者通知下游的观察者时再进行线程切换。切换的是下游的线程,即:上游被观察者订阅的时候不做线程切换,收到上游传递过来数据时再做线程切换 。
五.(了解)disposable的工作原理
由于disposable很复杂,个人研究的不多,这里只是简单的做一下提及。
可以简单的将其分为两类:有后续与无后续。
有后续的取消会找上游,无后续的若取消就直接不做事。
六.手写Rxjava
6.1.Uml类图
6.2.运行效果
6.3.代码如下
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
SingleU
.just(111)
.map(object : FunctionU {
override fun apply(t: Int): String {
return "操作符$t"
}
})
.subscribeOn()
.observeOn()
.subscribe(object : ObserverU {
override fun onSubscribe() {
println("触发时机 onSubscribe")
}
override fun onError() {
println("触发时机 onError")
}
override fun onSuccess(t: String) {
println("触发时机 onSuccess $t")
}
})
}
}
//被观察者的顶层接口
interface ObservableU {
fun subscribe(observer: ObserverU)
}
//观察者的顶层接口
interface ObserverU {
fun onSubscribe()
fun onSuccess(t: T)
fun onError()
}
interface FunctionU {
fun apply(t: T): R
}
//该类继承自ObservableU,定义了具体被观察者的实现类的公共方法,该类是供外界使用的
abstract class SingleU : ObservableU {
override fun subscribe(observer: ObserverU) {
subscribeActual(observer)
}
protected abstract fun subscribeActual(observer: ObserverU)
fun map(mapper: FunctionU): SingleU {
return SingleMapU(this, mapper)
}
fun subscribeOn(): SingleU {
return SingleSubscribeOnU(this)
}
fun observeOn(): SingleU {
return SingleObserveOnU(this)
}
companion object {
fun just(value: T): SingleU {
return SingleJustU(value)
}
}
}
class SingleJustU(private val value: T) : SingleU() {
override fun subscribeActual(observer: ObserverU) {
observer.onSubscribe()
observer.onSuccess(value)
}
}
class SingleMapU(private val source: ObservableU, private val mapper: FunctionU) :
SingleU() {
override fun subscribeActual(observer: ObserverU) {
source.subscribe(MapSingleObserverU1(observer, mapper))
}
internal class MapSingleObserverU1(
private val t: ObserverU,
private val mapper: FunctionU
) : ObserverU {
override fun onSubscribe() {
t.onSubscribe()
}
override fun onSuccess(value: T) {
t.onSuccess(mapper.apply(value))
}
override fun onError() {
t.onError()
}
}
}
class SingleObserveOnU(private val sourceU: ObservableU) : SingleU() {
override fun subscribeActual(observer: ObserverU) {
sourceU.subscribe(ObserveOnSingleObserver1(observer))
}
internal class ObserveOnSingleObserver1(private val actual: ObserverU) : ObserverU {
private val handler = Handler(Looper.getMainLooper())
override fun onSubscribe() {
actual.onSubscribe()
}
override fun onSuccess(t: T) {
handler.post { actual.onSuccess(t) }
}
override fun onError() {
handler.post { actual.onError() }
}
}
}
class SingleSubscribeOnU(private val sourceU: ObservableU) : SingleU() {
override fun subscribeActual(observer: ObserverU) {
executorService.submit(SubscribeOnObserverU1(observer, sourceU))
}
internal class SubscribeOnObserverU1(
private val actual: ObserverU,
private val source: ObservableU
) : ObserverU, Runnable {
override fun onSubscribe() {
actual.onSubscribe()
}
override fun onSuccess(t: T) {
actual.onSuccess(t)
}
override fun onError() {
actual.onError()
}
override fun run() {
source.subscribe(this)
}
}
companion object {
private val executorService = Executors.newCachedThreadPool()
}
}
七.Rxjava结合Retrofit封装网络框架
项目地址
常用操作符
map:接收上游发送过来的数据,可以对数据进行一定的处理,然后交给下游。应用场景:可以用来做数据剥壳,根据状态值判断是否需要抛出异常;
compose:利用其特性减少重复代码,如线程切换。其函数参数传递的是一个具体的Transformer;
zip:合并数据源;
flatMap:嵌套网络请求;
flatMap跟compose的区别,两者都用户变换被观察者。compose操作的是整个被观察者流,可以将其看作接收一个被观察者并返回一个新的观察者的函数。flatMap用来对被观察者发送的数据做变换的,可以看作是接收一个数据项并返回一个被观察者的函数。compose适用于改变数据线程,添加错误处理。
八.总结
本文选取了Single的使用来分析了Rxjava的核心原理,同时在最后使用了Rxjava3和Retrofit2封装成网络模块,提供了简易的Api提供给外界使用(新项目中网络部分使用的是协程对Jetpack的支持库结合Retrofit以及Flow来进行封装的,这部分知识会逐步在上方项目中进行实现)。
你可能感兴趣的:(rxjava,android)
树莓派部署syncthing实现私有云 | 树莓派小无相系列
TuTuTu_
树莓派 树莓派
手机上存着不少照片,自己又时常折腾手机,总有数据丢失的问题,又对市面上的云盘不怎么放心,所以打算在家里利用树莓派搭建一个私有云。一番查找之后,发现了syncthing。Syncthing是一个跨平台,开源且免费的基于P2P的文件同步解决方案,支持Windows,Mac,Linux,Android,syncthing官方暂不支持iOS平台,但在AppStore有可用的第三方客户端。安装syncthi
android 框架组件,Android 架构组件介绍
臀总
android 框架组件
Android架构组件介绍Android,Architecture,Components,架构2018.08.08我们在Android开发的过程中,总是在和一些问题纠缠,比如在生命周期的管理,在屏幕旋转的时候重新布局,绘制,保存还原数据等。我们也一直在致力于减少内存的占用,减少内存泄漏的风险,优化我们的代码,特别在大项目中,要增加代码的可维护性。AndroidArchitectureCompone
Android系统架构与四大组件
Tyssen
Android开发系列教程 android开发 系统架构
本篇博文主要讲解Android的系统架构。对于Android开发者来说,有必要了解一下Android应用程序是如何运行的。Android是一个移动操作系统,它大致分为四层,即Linux内核层,库和运行时,Framework层和应用层。Android的体系架构鼓励系统组件重用,共享组件数据,并且定义组件的访问控制权限。可以说,这些层次结构即是相互独立,又是相互关联的。一Android系统架构1.Li
Android 开发必备知识点整理
阿里大厂_RMI
android java 算法
ArrayMap1.基于两个数组实现,一个存放hash;一个存放键值对。扩容的时候只需要数组拷贝,不需要重建哈希表2.内存利用率高3.不适合存大量数据,因为会对key进行二分法查找(1000以下)SparseArray1.基于两个数组实现,int做key2.内存利用率高3.不适合存大量数据,因为会对key进行二分法查找(1000以下)volatile关键字只能用来修饰变量,适用修饰可能被多线程同时
Android架构组件-App架构指南,Android面试基础技能罗列
2401_84149570
程序员 android 架构 面试
通用架构原则推荐的App架构搭建用户界面获取数据关联ViewModel和repository缓存数据持久化数据测试最终的架构指导原则附录暴露网络状态本指南适用于那些已经拥有开发Android应用基础知识的开发人员,现在想了解能够开发出更加健壮、优质的应用程序架构。注意:本指南假定读者熟悉Android框架。如果你不熟悉Android应用程序开发,请查看Android入门培训教程,其中包含本指南的必
Android架构组件-App架构指南(1)
2401_84537826
程序员 android 架构
指导原则附录暴露网络状态本指南适用于那些已经拥有开发Android应用基础知识的开发人员,现在想了解能够开发出更加健壮、优质的应用程序架构。注意:本指南假定读者熟悉Android框架。如果你不熟悉Android应用程序开发,请查看Android入门培训教程,其中包含本指南的必备内容。首先需要说明的是:AndroidArchitectureComponents翻译为Android架构组件并不是我自己
深入解析 Uniapp 的页面结构
烂蜻蜓
uni-app 前端 html css vue.js html5
一、引言Uniapp是一个使用Vue.js开发跨平台应用的前端框架,它能让开发者通过编写一套代码,发布到iOS、Android、H5、小程序等多个平台。在Uniapp开发中,清晰理解页面结构是高效开发的基础,本文将深入剖析Uniapp的页面结构。二、初始化项目后的目录结构当我们使用HBuilderX新建一个Uniapp项目后,会得到如下基本目录结构:components:存放自定义组件的目录。比如
V4L2框架 | MIPI Camera指令调试笔记
一歲抬頭
DVP MIPI CAMERA
前言:在本文中,我将介绍如何使用Rockchip平台和OV2640摄像头进行视频设备的调试和分析。我将使用一些常用的命令和工具来展示如何查看和设置视频设备的格式、分辨率、控制参数等,以及如何抓取和转换图像数据。还将介绍如何使用媒体控制器来查看设备的拓扑结构和连接情况。这些内容对于理解和优化视频设备的性能和质量。推荐:《Android系统开发中高级定制专栏导读》关于v4l2_subdevv4l2_s
Android中使用WebSocket
Huang兄
android websocket android
2017-12-25背景:后端逻辑框架调整,将原来的推送和轮询方式改成了使用WebSocket通信。原来的请求方式是由app发起请求,appServer对请求进行分发,中转中继服务器将具体请求下发到对应的物联网服务器,物联网服务器将指令下发到指定的设备。整个流程涉及到很多层http请求,并且每个服务的回调接口还不一致,只能在app发情请求之后,接着去轮询服务器,服务器端去查询设备状态、是否对指令有
什么是 SurfaceView?其使用场景及示例有哪些?
晚夜微雨问海棠呀
信息可视化
SurfaceView核心解析1.基本概念定义:SurfaceView是Android中一种特殊的视图组件,提供独立于主UI线程的绘图表面(Surface),允许在子线程中进行高性能图形渲染。关键特性:双缓冲机制:减少绘制时的屏幕闪烁。独立Surface:与主窗口分离的绘图层,支持更灵活的刷新控制。低延迟渲染:适用于高频刷新场景(如游戏、视频)。2.核心优势(对比普通View)特性SurfaceV
apk文件放到Linux服务器 nginx不支持apk ipa文件下载设置
云上上云
服务器 linux nginx
修改/usr/local/nginx/conf目录下的mime.types增加如下配置,重启nginx生效application/vnd.android.package-archiveapk;//安卓application/iphonepxlipa;//ios
uni-app: Android、iOS文件选择
Heyuan_Xie
Uni-App uni-app
场景uni-app移动端自带的文件选择,只支持图片和视频,想要选择本地其他格式的文件,只能通过其他方法实现。网上资料参差不齐,又杂乱,有说通过input标签实现,有说通过h5+实现,试了一下都不太合适。最终也是通过结合这诸多资料整理出目前的方案。基本实现方式是通过render.js是实现,自定义一个button,点击调用render.js里面的方法,往Dom里插入一个input标签,并监听数据的变
Audio Control HAL(一)
漫步的傻瓜
Android车载音频系统 android 音视频 车载系统
目录Audiofadeandbalance来自HAL的音频焦点请求将HIDL迁移到AIDL音频控制HAL音量组静音Android9中引入了音频控制HAL,可支持与汽车相关的音频用例。从Android14开始,音频控制HAL支持:淡变和平衡HAL音频焦点请求设备静音和闪避音频设备增益变化音频端口配置更改图1简要概述了车载音频服务架构,其中车载音频服务会与音频控制HAL进行通信。
Fino开源项目使用指南
凤尚柏Louis
Fino开源项目使用指南finoAndroidsmallfootprintinspectiontool项目地址:https://gitcode.com/gh_mirrors/fi/fino一、项目目录结构及介绍Fino是一个基于特定技术栈的开源项目,旨在提供高效且灵活的解决方案。以下是其基本目录结构概述:fino/├──README.md#项目介绍与快速入门文档├──LICENSE#许可证文件├─
Python爬虫实战项目案例——爬取微信朋友圈
冷漠无情姐姐
python 爬虫 微信
项目实战 Appium爬取微信朋友圈 自动化爬取App数据基于移动端的自动化测试工具Appium的自动化爬取程序。步骤1、JDK-DownloadJDK,Appium要求用户必须配置JAVA环境,否则启动Seesion报错。2、Appium-DownloadAppium,安装过程请自行搜索。3、AndroidSDK-DownloadSDK4、Selenium-建议使用低版本的PythonSelen
开源架构
林伟
相关开源网站
opensourcehttp://android.git.kernel.org/ftp://ftp.kernel.org/pub/linux/http://www.gnu.org/http://opensource.limofoundation.org/index.php/limo-open-source.htmlhttp://code.google.com/p/maxwit/blog:http:
WebView 细节,onShowCustomView与JS注入来实现视频全屏播放
Boo_Wang
Android基础 WebView 视频播放 硬件加速
概述WebView是开发中经常使用的组件,在使用中我们需要考虑文件下载,自定义scheme,重定向,硬件加速,Cookie,HTTPS/HTTP混合等多种问题。关于WebView之前的总结AndroidWebView使用,Http/Https,硬件加速等相关细节详解Androidhybrid之JS与Native的通信方式更多参考:AndroidWebview实现文件下载功能Android5.0We
用C++ Qt实现安卓电池充电动效 | 打造工业级电量控件
十年编程老舅
QT开发 c++ qt android qt项目实战 qt项目 qt开发 qt教程
一、为什么需要自定义电池控件?在工业控制、车机系统、智能硬件等领域的UI开发中,电池状态显示是高频出现的UI组件。通过实现一个支持颜色渐变、动态充电动画、警戒阈值提示的电池控件,开发者可以系统掌握以下核心能力:Qt绘图体系(QPainter/QPen/QBrush)自定义控件开发与提升技巧定时器驱动动画原理状态机与样式动态切换控件参数化配置思想本项目的技术复现度极高:实际效果可媲美Android原
Android Kotlin Jetpack Compose UI框架 完全解析(1)
2401_84132544
程序员 android kotlin ui
这一功能基于新版AndroidStudio对Compose的支持。新版的AndroidStudioArcticFox(现在还是Canary版本)中添加了许多新工具来支持JetpackCompose新特性,比如:实时文字、动画预览,布局检查等等。1.1.1强大的预览新的AndroidStudio增加了对文字更改实时预览的效果,可以在Preview、模拟器、或者真机上实时预览。1.1.2动画预览可以在
android浏览器资源嗅探,GitHub - icemanyandy/VBrowser-Android: 全网视频嗅探缓存APP
一朵小小玫
android浏览器资源嗅探
VBrowser-Android全网视频嗅探缓存APP简介一款用于全网视频嗅探、缓存及播放的APP,方便追剧党、出差党随时随地观看缓存好的视频。超强的视频嗅探能力,多线程急速下载。主要功能1.网页中包含的主流格式的流媒体视频的嗅探(M3U8,MP4等)2.主流格式的流媒体视频的缓存(M3U8及传统单文件视频(如MP4,avi))3.已缓存的视频播放(目前调用外部播放器,如MXPlayer)特色1.
Unity 接入SDK (Android)
乃敢与君决
java unity c#
前几篇帖子主要是写了一些安卓平台的基本操作,unity接入sdk是有多平台的,android,ios等,今天呢先写写如何接入安卓sdk;首先呢sdk是个啥呢,官方定义咱们总结出来就是一个工具包,他可以使应用连接到其他平台我们要了解unity接入安卓平台的话他这个交互方式是怎么样的,安卓的话是主体是java,然后unity这边呢主体看项目封装吧,这个不限制,接下来,咱们就说具体步骤。首先在你的Uni
数仓实战05:数仓搭建-DWS层
曾牛
数仓
1.业务术语1)用户用户以设备为判断标准,在移动统计中,每个独立设备认为是一个独立用户。Android系统根据IMEI号,IOS系统根据OpenUDID来标识一个独立用户,每部手机一个用户。2)新增用户首次联网使用应用的用户。如果一个用户首次打开某APP,那这个用户定义为新增用户;卸载再安装的设备,不会被算作一次新增。新增用户包括日新增用户、周新增用户、月新增用户。3)活跃用户打开应用的用户即为活
uniapp多端适配
林同学++
uni-app
UniApp是一个基于Vue.js开发多端应用的框架,它可以让开发者编写一次代码,同时适配iOS、Android、Web等多个平台。环境搭建:UniApp基于Vue.js开发,所以需要先安装VueCLInpminstall-g@vue/cli创建一个新的UniApp项目,名为"myapp"vuecreate-pdcloudio/uni-preset-vuemyapp进入项目目录,并运行以下命令启动
硬刚Android Jetpack:3万字全面指南与应用实践大揭秘
大模型大数据攻城狮
android面试 LiveData android jetpack room viewmodel android电量 workmanager
目录一、Jetpack概述(一)组件架构大剖析(二)优势特点大放送二、核心组件应用(一)ViewModel使用全攻略(二)LiveData实践秘籍(三)Room数据库深度解析(四)DataBinding技术详解三、UI开发指南(一)ConstraintLayout布局深度探索(二)Compose界面构建全解析(三)Navigation导航组件探秘四、后台任务处理(一)WorkManager应用实战
ARCore:ARCore的点云与深度API应用_2024-07-25_20-37-55.Tex
chenjj4003
游戏开发 1024程序员节 substance painter 贴图 android 数据库
ARCore:ARCore的点云与深度API应用ARCore简介ARCore的基本概念ARCore是Google开发的一个增强现实(AR)平台,旨在为移动设备提供高精度的AR体验。它通过使用设备的摄像头、传感器和机器学习技术,能够在没有外部标记的情况下,实现对现实世界的理解和交互。ARCore支持Android和iOS设备,允许开发者创建沉浸式的AR应用,无需额外硬件支持。ARCore的核心功能包
android wifi驱动流程,高通Android wifi驱动移植-SDIO
weixin_39727336
android wifi驱动流程
环境用的是android2.3系统,wifi是BCM4329,接口是SDIO,Android4.0在步骤上略有不同。1.首先了解SDIO的一些相关知识:SDIO有两端,其中一端是HOST端,另一端是device端.所有的通信都是由HOST端发送命令开始的,Device端只要能解析命令,就可以相互通信。CLK信号:HOST给DEVICE的时钟信号,每个时钟周期传输一个命令。CMD信号:双向的信号,用
Authentication Error errorcode: 230(APP scode校验失败)百度地图只显示网格线
梅子专栏
230错误 200错误 Android 百度地图 android 百度地图 230错误 200错误
在此就AndroidStudio下调用百度地图时的细节做个总结,某个细节没有注意到,可能就是程序报错的原因。最初这一问题是从“230验证失败”开始的。之后的调试中遇到了更多别的bug。执行AndroidStudio->build->GenerateSignedAPK,是用Studio自动打包签名,它会创建一个xxx.jks文件,通过命令keytool-v-list-keystore/Users/r
android开发--简易登录注册界面及逻辑设计
不会飞的fish。。
笔记
登录注册界面与逻辑设计1.第一步新建文件(相信各位码农一定会这一步)略。。。2.第二步登录注册界面设计登录界面主要包括几大控件,如登录、注册按钮,账号(Button)、密码输入框(Editext)、复选框等。可以利用shape参数对控件进行美化。界面设计可以线性布局嵌套使用,这样可以很好的对控件调整,美化界面。注册界面主要包括EdiText、Radiobutton、button、checkbox等
Java部署机器学习模型:方案二(基于DJL)
iiilloi
机器学习 spring spring boot
DJL(DeepJavaLibrary)是由亚马逊公司开发的一款开源的深度学习框架,它旨在为Java开发人员提供一个简单而强大的API,使得在Java中使用深度学习变得更加容易。DJL有以下几个方面优势:支持多个底层引擎DJL支持多个底层引擎,包括MXNet、TensorFlow和PyTorch等。这使得DJL可以在多个平台上使用,包括Java、Android、iOS和RaspberryPi等。易
Android Jenkins 测试,如何在android上为jenkins生成JUnit测试报告
Gullet
Android Jenkins 测试
我试图利用Jenkins中的“发布JUnit测试结果报告”,但无法让它适用于我的Android测试项目.我在jenkins的Android测试项目的设置基于本指南:https://wiki.jenkins-ci.org/display/JENKINS/Building+an+Android+app+and+test+project我希望有人可以发布一个简单的分步指南,介绍如何从测试运行中获取JUn
java短路运算符和逻辑运算符的区别
3213213333332132
java基础
/*
* 逻辑运算符——不论是什么条件都要执行左右两边代码
* 短路运算符——我认为在底层就是利用物理电路的“并联”和“串联”实现的
* 原理很简单,并联电路代表短路或(||),串联电路代表短路与(&&)。
*
* 并联电路两个开关只要有一个开关闭合,电路就会通。
* 类似于短路或(||),只要有其中一个为true(开关闭合)是
Java异常那些不得不说的事
白糖_
java exception
一、在finally块中做数据回收操作
比如数据库连接都是很宝贵的,所以最好在finally中关闭连接。
JDBCAgent jdbc = new JDBCAgent();
try{
jdbc.excute("select * from ctp_log");
}catch(SQLException e){
...
}finally{
jdbc.close();
utf-8与utf-8(无BOM)的区别
dcj3sjt126com
PHP
BOM——Byte Order Mark,就是字节序标记 在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输 字符"ZERO WIDTH NO-BREAK SPACE"。这样如
JAVA Annotation之定义篇
周凡杨
java 注解 annotation 入门 注释
Annotation: 译为注释或注解
An annotation, in the Java computer programming language, is a form of syntactic metadata that can be added to Java source code. Classes, methods, variables, pa
tomcat的多域名、虚拟主机配置
g21121
tomcat
众所周知apache可以配置多域名和虚拟主机,而且配置起来比较简单,但是项目用到的是tomcat,配来配去总是不成功。查了些资料才总算可以,下面就跟大家分享下经验。
很多朋友搜索的内容基本是告诉我们这么配置:
在Engine标签下增面积Host标签,如下:
<Host name="www.site1.com" appBase="webapps"
Linux SSH 错误解析(Capistrano 的cap 访问错误 Permission )
510888780
linux capistrano
1.ssh -v hdfs@192.168.18.133 出现
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
错误
运行状况如下:
OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuratio
log4j的用法
Harry642
java log4j
一、前言: log4j 是一个开放源码项目,是广泛使用的以Java编写的日志记录包。由于log4j出色的表现, 当时在log4j完成时,log4j开发组织曾建议sun在jdk1.4中用log4j取代jdk1.4 的日志工具类,但当时jdk1.4已接近完成,所以sun拒绝使用log4j,当在java开发中
mysql、sqlserver、oracle分页,java分页统一接口实现
aijuans
oracle jave
定义:pageStart 起始页,pageEnd 终止页,pageSize页面容量
oracle分页:
select * from ( select mytable.*,rownum num from (实际传的SQL) where rownum<=pageEnd) where num>=pageStart
sqlServer分页:
Hessian 简单例子
antlove
java Web service hessian
hello.hessian.MyCar.java
package hessian.pojo;
import java.io.Serializable;
public class MyCar implements Serializable {
private static final long serialVersionUID = 473690540190845543
数据库对象的同义词和序列
百合不是茶
sql 序列 同义词 ORACLE权限
回顾简单的数据库权限等命令;
解锁用户和锁定用户
alter user scott account lock/unlock;
//system下查看系统中的用户
select * dba_users;
//创建用户名和密码
create user wj identified by wj;
identified by
//授予连接权和建表权
grant connect to
使用Powermock和mockito测试静态方法
bijian1013
持续集成 单元测试 mockito Powermock
实例:
package com.bijian.study;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import or
精通Oracle10编程SQL(6)访问ORACLE
bijian1013
oracle 数据库 plsql
/*
*访问ORACLE
*/
--检索单行数据
--使用标量变量接收数据
DECLARE
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
BEGIN
select ename,sal into v_ename,v_sal
from emp where empno=&no;
dbms_output.pu
【Nginx四】Nginx作为HTTP负载均衡服务器
bit1129
nginx
Nginx的另一个常用的功能是作为负载均衡服务器。一个典型的web应用系统,通过负载均衡服务器,可以使得应用有多台后端服务器来响应客户端的请求。一个应用配置多台后端服务器,可以带来很多好处:
负载均衡的好处
增加可用资源
增加吞吐量
加快响应速度,降低延时
出错的重试验机制
Nginx主要支持三种均衡算法:
round-robin
l
jquery-validation备忘
白糖_
jquery css F# Firebug
留点学习jquery validation总结的代码:
function checkForm(){
validator = $("#commentForm").validate({// #formId为需要进行验证的表单ID
errorElement :"span",// 使用"div"标签标记错误, 默认:&
solr限制admin界面访问(端口限制和http授权限制)
ronin47
限定Ip访问
solr的管理界面可以帮助我们做很多事情,但是把solr程序放到公网之后就要限制对admin的访问了。
可以通过tomcat的http基本授权来做限制,也可以通过iptables防火墙来限制。
我们先看如何通过tomcat配置http授权限制。
第一步: 在tomcat的conf/tomcat-users.xml文件中添加管理用户,比如:
<userusername="ad
多线程-用JAVA写一个多线程程序,写四个线程,其中二个对一个变量加1,另外二个对一个变量减1
bylijinnan
java 多线程
public class IncDecThread {
private int j=10;
/*
* 题目:用JAVA写一个多线程程序,写四个线程,其中二个对一个变量加1,另外二个对一个变量减1
* 两个问题:
* 1、线程同步--synchronized
* 2、线程之间如何共享同一个j变量--内部类
*/
public static
买房历程
cfyme
2015-06-21: 万科未来城,看房子
2015-06-26: 办理贷款手续,贷款73万,贷款利率5.65=5.3675
2015-06-27: 房子首付,签完合同
2015-06-28,央行宣布降息 0.25,就2天的时间差啊,没赶上。
首付,老婆找他的小姐妹接了5万,另外几个朋友借了1-
[军事与科技]制造大型太空战舰的前奏
comsci
制造
天气热了........空调和电扇要准备好..........
最近,世界形势日趋复杂化,战争的阴影开始覆盖全世界..........
所以,我们不得不关
dateformat
dai_lm
DateFormat
"Symbol Meaning Presentation Ex."
"------ ------- ------------ ----"
"G era designator (Text) AD"
"y year
Hadoop如何实现关联计算
datamachine
mapreduce hadoop 关联计算
选择Hadoop,低成本和高扩展性是主要原因,但但它的开发效率实在无法让人满意。
以关联计算为例。
假设:HDFS上有2个文件,分别是客户信息和订单信息,customerID是它们之间的关联字段。如何进行关联计算,以便将客户名称添加到订单列表中?
&nbs
用户模型中修改用户信息时,密码是如何处理的
dcj3sjt126com
yii
当我添加或修改用户记录的时候对于处理确认密码我遇到了一些麻烦,所有我想分享一下我是怎么处理的。
场景是使用的基本的那些(系统自带),你需要有一个数据表(user)并且表中有一个密码字段(password),它使用 sha1、md5或其他加密方式加密用户密码。
面是它的工作流程: 当创建用户的时候密码需要加密并且保存,但当修改用户记录时如果使用同样的场景我们最终就会把用户加密过的密码再次加密,这
中文 iOS/Mac 开发博客列表
dcj3sjt126com
Blog
本博客列表会不断更新维护,如果有推荐的博客,请到此处提交博客信息。
本博客列表涉及的文章内容支持 定制化Google搜索,特别感谢 JeOam 提供并帮助更新。
本博客列表也提供同步更新的OPML文件(下载OPML文件),可供导入到例如feedly等第三方定阅工具中,特别感谢 lcepy 提供自动转换脚本。这里有导入教程。
js去除空格,去除左右两端的空格
蕃薯耀
去除左右两端的空格 js去掉所有空格 js去除空格
js去除空格,去除左右两端的空格
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&g
SpringMVC4零配置--web.xml
hanqunfeng
springmvc4
servlet3.0+规范后,允许servlet,filter,listener不必声明在web.xml中,而是以硬编码的方式存在,实现容器的零配置。
ServletContainerInitializer:启动容器时负责加载相关配置
package javax.servlet;
import java.util.Set;
public interface ServletContainer
《开源框架那些事儿21》:巧借力与借巧力
j2eetop
框架 UI
同样做前端UI,为什么有人花了一点力气,就可以做好?而有的人费尽全力,仍然错误百出?我们可以先看看几个故事。
故事1:巧借力,乌鸦也可以吃核桃
有一个盛产核桃的村子,每年秋末冬初,成群的乌鸦总会来到这里,到果园里捡拾那些被果农们遗落的核桃。
核桃仁虽然美味,但是外壳那么坚硬,乌鸦怎么才能吃到呢?原来乌鸦先把核桃叼起,然后飞到高高的树枝上,再将核桃摔下去,核桃落到坚硬的地面上,被撞破了,于是,
JQuery EasyUI 验证扩展
可怜的猫
jquery easyui 验证
最近项目中用到了前端框架-- EasyUI,在做校验的时候会涉及到很多需要自定义的内容,现把常用的验证方式总结出来,留待后用。
以下内容只需要在公用js中添加即可。
使用类似于如下:
<input class="easyui-textbox" name="mobile" id="mobile&
架构师之httpurlconnection----------读取和发送(流读取效率通用类)
nannan408
1.前言.
如题.
2.代码.
/*
* Copyright (c) 2015, S.F. Express Inc. All rights reserved.
*/
package com.test.test.test.send;
import java.io.IOException;
import java.io.InputStream
Jquery性能优化
r361251
JavaScript jquery
一、注意定义jQuery变量的时候添加var关键字
这个不仅仅是jQuery,所有javascript开发过程中,都需要注意,请一定不要定义成如下:
$loading = $('#loading'); //这个是全局定义,不知道哪里位置倒霉引用了相同的变量名,就会郁闷至死的
二、请使用一个var来定义变量
如果你使用多个变量的话,请如下方式定义:
. 代码如下:
var page
在eclipse项目中使用maven管理依赖
tjj006
eclipse maven
概览:
如何导入maven项目至eclipse中
建立自有Maven Java类库服务器
建立符合maven代码库标准的自定义类库
Maven在管理Java类库方面有巨大的优势,像白衣所说就是非常“环保”。
我们平时用IDE开发都是把所需要的类库一股脑的全丢到项目目录下,然后全部添加到ide的构建路径中,如果用了SVN/CVS,这样会很容易就 把
中国天气网省市级联页面
x125858805
级联
1、页面及级联js
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
&l