前言
EventBus 是一个处理事件的第三方框架,以发布和订阅 的方式让使用者能够避免一些复杂的逻辑,轻松地在组件之间传递消息。
EventBus is a publish/subscribe event bus for Android and Java.
我是17年底才接触到它的,所以这里就分析一下最新EventBus3.0 的源码。至于如何使用EventBus,请进入github查看示例。
获取EventBus对象
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault () {
if (defaultInstance == null ) {
synchronized (EventBus.class) {
if (defaultInstance == null ) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
注释已经写的很明白了,方便你在单一进程中获取一个全局范围的唯一实例 。
然而它的构造方法并没有私有化,我们也可以构造多个EventBus,当然一般情况下我们使用默认的即可。
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus () {
this (DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
……
}
注册订阅者
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
*
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register (Object subscriber) {
Class subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this ) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
注释中提示我们:
不需要接收消息的时候及时取消订阅
订阅的方法必须加上@Subscribe 的注解
可以在@Subscribe 中配置线程和订阅的优先级
查找订阅方法
我们进入findSubscriberMethods() :
List findSubscriberMethods(Class subscriberClass ) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null ) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation" );
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
这里先看findUsingInfo() ,如果忽略注解器生成的MyEventBusIndex,会进入这个方法:
private List findUsingInfo(Class subscriberClass ) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null ) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null ) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array ) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
进入findUsingReflectionInSingleClass() ,通过反射的方式来查找订阅方法:
private List findUsingReflection(Class subscriberClass ) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null ) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
进入findUsingReflectionInSingleClass() :
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz .getDeclaredMethods ()
} catch (Throwable th) {
// Workaround for java.lang .NoClassDefFoundError , see https://github.com /greenrobot/EventBus/issues/149
methods = findState.clazz .getMethods ()
findState.skipSuperClasses = true
}
// 遍历方法,进行过滤
for (Method method : methods) {
int modifiers = method.getModifiers ()
if ((modifiers & Modifier.PUBLIC ) != 0 && (modifiers & MODIFIERS_IGNORE) == 0 ) {
Class[] parameterTypes = method.getParameterTypes ()
// 方法参数为一个
if (parameterTypes.length == 1 ) {
Subscribe subscribeAnnotation = method.getAnnotation (Subscribe.class )
// 包含Subscribe的注解
if (subscribeAnnotation != null) {
Class eventType = parameterTypes[0 ]
// 保存到findState对象当中
if (findState.checkAdd (method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode ()
findState.subscriberMethods .add (new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority (), subscribeAnnotation.sticky ()))
}
}
} else if (strictMethodVerification && method.isAnnotationPresent (Subscribe.class )) {
String methodName = method.getDeclaringClass ().getName () + "." + method.getName ()
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length )
}
} else if (strictMethodVerification && method.isAnnotationPresent (Subscribe.class )) {
String methodName = method.getDeclaringClass ().getName () + "." + method.getName ()
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract" )
}
}
}
订阅者订阅
回到register() :
public void register (Object subscriber) {
Class subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this ) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
进入subscribe() :
private void subscribe (Object subscriber, SubscriberMethod subscriberMethod) {
Class eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get (eventType);
if (subscriptions == null ) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
for (int i = 0 ; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get (i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break ;
}
}
List> subscribedEvents = typesBySubscriber.get (subscriber);
if (subscribedEvents == null ) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
if (eventInheritance) {
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, Object> entry : entries) {
Class candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get (eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
粘性事件
为什么在订阅阶段就处理事件了呢?从代码的逻辑思考反推,就是订阅者订阅的时候事件已经发送出来了 。
那么就很好理解粘性事件 了,就是发布者发送一个粘性事件,这个事件会被存储起来,当对应的订阅者订阅这个事件时,立马就会接收到这个事件。
更简单的说,只要发送者发送过事件,订阅者在事件发送后才注册也能收到该事件。类似于,关机的手机突然开机了,能够收到之前关机阶段没收到的短信。
发布事件
进入post() :
/** Posts the given event to the event bus. */
public void post (Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true ;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset" );
}
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0 ), postingState);
}
} finally {
postingState.isPosting = false ;
postingState.isMainThread = false ;
}
}
}
接着进入postSingleEvent() :
private void postSingleEvent (Object event , PostingThreadState postingState) throws Error {
Class eventClass = event .getClass();
boolean subscriptionFound = false ;
if (eventInheritance) {
List> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0 ; h < countTypes; h++) {
Class clazz = eventTypes.get (h);
subscriptionFound |= postSingleEventForEventType(event , postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event , postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this , event ));
}
}
}
进入postSingleEventForEventType() :
private boolean postSingleEventForEventType (Object event , PostingThreadState postingState, Class eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this ) {
subscriptions = subscriptionsByEventType.get (eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event ;
postingState.subscription = subscription;
boolean aborted = false ;
try {
postToSubscription(subscription, event , postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null ;
postingState.subscription = null ;
postingState.canceled = false ;
}
if (aborted) {
break ;
}
}
return true ;
}
return false ;
}
进入postToSubscription() :
private void postToSubscription (Subscription subscription, Object event , boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event );
break ;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event );
} else {
mainThreadPoster.enqueue(subscription, event );
}
break ;
case MAIN_ORDERED:
if (mainThreadPoster != null ) {
mainThreadPoster.enqueue(subscription, event );
} else {
invokeSubscriber(subscription, event );
}
break ;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event );
} else {
invokeSubscriber(subscription, event );
}
break ;
case ASYNC:
asyncPoster.enqueue(subscription, event );
break ;
default :
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
以上是根据订阅者订阅方法的线程来做不同的处理,默认的ThreadMode是POSTING ,来看下ThreadMode :
public enum ThreadMode {
/**
* Subscriber will be called directly in the same thread, which is posting the event. This is the default. Event delivery
* implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for
* simple tasks that are known to complete in a very short time without requiring the main thread. Event handlers
* using this mode must return quickly to avoid blocking the posting thread, which may be the main thread.
*/
POSTING,
/**
* On Android, subscriber will be called in Android's main thread (UI thread). If the posting thread is
* the main thread, subscriber methods will be called directly, blocking the posting thread. Otherwise the event
* is queued for delivery (non-blocking). Subscribers using this mode must return quickly to avoid blocking the main thread.
* If not on Android, behaves the same as {@link
*/
MAIN,
/**
* On Android, subscriber will be called in Android's main thread (UI thread). Different from {@link
* the event will always be queued for delivery. This ensures that the post call is non-blocking.
*/
MAIN_ORDERED,
/**
* On Android, subscriber will be called in a background thread. If posting thread is not the main thread, subscriber methods
* will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single
* background thread, that will deliver all its events sequentially. Subscribers using this mode should try to
* return quickly to avoid blocking the background thread. If not on Android, always uses a background thread.
*/
BACKGROUND,
/**
* Subscriber will be called in a separate thread. This is always independent from the posting thread and the
* main thread. Posting events never wait for subscriber methods using this mode. Subscriber methods should
* use this mode if their execution might take some time , e.g. for network access. Avoid triggering a large number
* of long running asynchronous subscriber methods at the same time to limit the number of concurrent threads. EventBus
* uses a thread pool to efficiently reuse threads from completed asynchronous subscriber notifications.
*/
ASYNC
}
应该还是比较好理解的。
最终都会进入invokeSubscriber() :
void invokeSubscriber(Subscription subscription, Object event ) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event );
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event , e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception" , e);
}
}
当然也有可能调用不同的Poster ,先把事件加入队列然后再去处理,Poster是个接口,有三个实现类HandlerPoster,BackgroundPoster,AsyncPoster ,这里简单看一下他们的定义:
public class HandlerPoster extends Handler implements Poster
class AsyncPoster implements Runnable , Poster
final class BackgroundPoster implements Runnable , Poster
HandlerPoster 所做的就是切换到主线程,然后再进一步处理事件。
取消注册
进入unregister() :
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister (Object subscriber) {
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null ) {
for (Class eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
新特性Subscriber Index
利用apt避免了运行时寻找订阅者信息的反射操作,提高了性能,可以参考EventBus3.0新特性之Subscriber Index。
你可能感兴趣的:(Android)
Android studio:如何在同一个页面显示多个fragment
剑客狼心
android studio android ide
家母罹患肝癌,可在水滴筹页面查看详情实现一个简单的效果:创建TestOneFragmentpublicclassTestOneFragmentextendsFragment{@OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){//使用一个简单的布局文件
[Android Studio]SQLScout插件安装破解
weixin_33755847
移动开发 数据库 开发工具
以下内容为原创,欢迎转载,转载请注明来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5972138.html[AndroidStudio]SQLScout插件安装破解0.写在前面想当初很长一段时间内不想用AndroidStudio而喜欢用IntellijIDEA(旗舰版)其中一个原因就是因为IntellijIDEA(旗舰版)自带DatabaseExp
【原创】Android Studio Ladybug 中Gradle配置
赵庆明老师
Android android studio android ide
使用AndroidStudio创建项目后,由于需要下载的一下文件在国外,加上网速的问题,以及防火墙的问题,不少文件难以下载。常常导致项目创建后,要等很长时间,各种折腾,结果一个demo都跑不起来。经过几天的探索,没在AS中发现比较好的配置方法。本打算逆向修改AS中的程序文件,发现太费事。接下来找到了AS的源码,打算编译一个来替换,一看80多G,头都大了。于是退而求其次,选择在项目配置文件中解决。具
Android studio 打包 uni App
前端小小小学生
uni-app 前端 android uni-app android studio
Androidstudio打包uniAppHBuilderX本身有原生App云打包功能,本身没什么需求可以直接使用,如果需要多次打包,云打包每次链接只能提供5次下载机会,而且要时间排队打包,所以学习了一下Androidstudio工具打包,下面是使用方法,仅供参考:1.安装Androidstudio下载Androidstudio下载地址:http://www.android-studio.org/
Android Studio系列讲解之UI开发的布局
彬sir哥
Android kotlin入门到进阶系列讲解 android studio kotlin UI 布局
<<返回总目录文章目录一、常用控件的使用方法1、TextView2、Button3、EditText4、ImageView二、详细2种基本布局1、LinearLayout2、RelativeLayout三、系统控件不够用?创建自定义控件1、引入布局2、创建自定义控件一、常用控件的使用方法Android给我们提供了大量的UI控件,合理地使用这些控件就可以非常轻松地编写出相当不错的界面首先新建一个UI
Android Studio增量包升级方法
慈眉善目张先森
Android小记 Android studio增量更新
AndroidStudio增量包升级方法由于外网的限制,as的自动升级基本是可以抛弃了,这里可以使用增量包升级,你要知道你的Androidstudio版本,还有下载增量包的资源查看你的版本Build为你的版本号,我这里是最新的,已经更新过的,这里的版本号后面有用;获取增量包获取增量版本号下载该文件,然后里面内容如下如图,你知道你的版本和需要升级到的版本的话,你就可以拼出你需要下载的增量包的地址,h
android studio优化编译速度
chenhuakang
安卓优化 android studio android gradle
优化步骤1.优化gradle配置:在项目根目录创建一个gradle.properties文件#开启gradle并行编译,开启daemon,调整jvm内存大小org.gradle.daemon=trueorg.gradle.configureondemand=trueorg.gradle.parallel=trueorg.gradle.jvmargs=-Xmx4096m-XX:MaxPermSize
2024.1.2版本Android Studio gradle下载超时问题处理
粤M温同学
Android android studio android
一、问题背景在项目的根build.gradle里面配置了以下地址后,依旧下载gradle包失败,平常如果出现第三方库或者gradle下载失败,配置以下地址,一般可以下载成功maven{url'https://maven.aliyun.com/repository/public'}maven{url'https://maven.aliyun.com/nexus/content/groups/publ
【原创】Android Studio 中好用的翻译插件
赵庆明老师
Android android studio android ide
在使用AndroidStudio的时候,且不说英文界面,在编写代码的时候遇到的文档也是英文的,如果英语基础不过关,这个软件就太好了。名称很简单:Translation,由Yii.Guxing开发,目前800多次安装。https://plugins.jetbrains.com/plugin/8579-translation在AndroidStudio中打开设置\插件,搜索Translation即可,
销售易、极兔、珍客CRM:产品功能特色与企业适用性分析
程序员机器学习人工智能
销售易CRM产品功能移动化与社交化:销售易CRM支持iOS、Android等主流操作系统,销售人员可以随时随地访问客户信息、更新销售进度、创建任务等。同时,它还具备社交化功能,能够整合企业内部的社交网络,促进员工之间的协作与沟通。AI与大数据驱动:销售易CRM融合了人工智能和大数据技术,通过智能数据分析,帮助企业洞察客户行为和需求,预测销售趋势。例如,AI可以对客户数据进行深度挖掘,识别出高价值客
【android:位置传感器——使用近程传感器】
萌虎不虎
android
android:位置传感器——使用近程传感器近程传感器可让您确定物体与设备的距离。以下代码展示如何获取默认近程传感器的实例:privateSensorManagersensorManager;privateSensorsensor;...//获取传感器sensorManager=(SensorManager)getSystemService(Context.SENSOR_SERVICE);sens
Kivy 模块使用python语言编译android可用的apk——开篇
静候光阴
Kivy编译apk技术全面解析 android python kivy ubntu linux buildozer
本专栏目标,是将使用kivy库编辑的python语言文件,通过编译可以直接在android环境下执行的apk(亲测鸿蒙可用)。学习本专栏前,请学习kivy的基本操作,可以参考我之前的免费专栏内容:《Python+Kivy(App开发)从入门到实践》自学笔记:Python文件+.kv文件实现“Helloworld”_kivykv文件_静候光阴的博客-CSDN博客由于编译过程中依赖安装和配置问题会造成
Kivy 模块使用python语言编译android可用的apk——Android-for-Python
静候光阴
Kivy编译apk技术全面解析 android python kivy buildozer
将为Android构建的Kivy示例。例子,名词一种可以被模仿或不被模仿的模式平行或非常相似的案例,尤其是作为先例或模型时每个存储库(用户指南除外)都包含一个独立的可运行示例。所有示例都在Android上运行,大多数在桌面上运行,还有一些在iOS上运行。包含buildozer.spec或记录对buildozer.spec所需的修改。一、CloudStorageExamples(云存储示例)概述Fi
Kivy教程大全之 使用 NumPy 和 Kivy 对 Android 设备进行图像分类
知识大胖
Python源码大全 python kivy numpy
文章简介ANN架构。使用KV语言创建小部件树。创建Kivy应用程序。使用正确的NumPy版本。构建Android应用程序。了解更多信息本教程的重点是构建一个调用预训练的ANN来对图像进行分类的Android应用程序。这里不深入讨论准备数据集、构建、训练和优化ANN的步骤。在本教程中将仅对它们进行简要讨论。但不要担心——在不了解这些细节的情况下遵循本教程中的想法是可以的。如果您想了解它们,请查看我之
Kivy转apk——使用打包虚拟机(亲测~)
刘骏宗
Kivy转apk——使用打包虚拟机(亲测~)Kivy转apk使用打包虚拟机亲测项目地址:https://gitcode.com/Resource-Bundle-Collection/e8cd4文档简介本资源提供了详细的指导,帮助开发者使用Kivy框架将Python项目转换为Androidapk文件。该流程基于虚拟机环境,特别适合那些希望避免手动配置复杂开发环境的用户。通过这篇亲测分享,你可以了解到
Android网络技术——HttpUrlConnection和OkHttp
penghc_xhs
Android 第一行代码 android
Android网络技术——HttpUrlConnection和OkHttpHttpURLConnection是一个abstract类,可用于发起网络请求OkHttp不仅在接口封装上做得简单易用,就连在底层实现上也是自成一派,比起原生的HttpURLConnection,可以说是有过之而无不及,现在已经成了广大Android开发者首选的网络通信库一、布局设置注:ScrollView容器用于滚动内部的
Android 访问网络框架之——OkHttp框架的解析
mr丶yang
原创 Okhttp 框架 网络
越来越发现一些第三方的框架比Android原生大的API好用多了,而且android废弃掉了HttpClient,有必要学习一些访问网络的框架,于是踏上了一条框架学习之路,先前学习了Volley框架。今天来解析一下OkHttp框架。一,OkHttp的简单使用,主要包括:一般的get请求一般的post请求基于Http的文件上传文件下载加载图片支持请求回调,直接返回对象、对象集合支持session的保
Android网络框架——OKHttp
闲暇部落
Java android okhttp java
目录一、介绍二、优势三、功能四、应用1.HttpGet的使用步骤2.HttpPost携带参数的使用步骤:3.使用post进行表单(键值对)上传一、介绍OKHttp是一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso)用于替代HttpUrlConnection和ApacheHttpClient(androidAPI236.0里已移除H
app自动化测试appium教程之一——环境搭建(appium+python+mumu模拟器)
zhizhi0920
app自动化测试教程 python java android android studio
app自动化测试教程之一——环境搭建(appium+python+mumu模拟器)安装JDK1.官网下载地址2.下载最新版JDK3.安装4.配置环境变量5.验证安装安装AndroidSDK1.下载地址2.下载Androidstudio并安装3.配置环境变量4.验证安装安装NODE.JS安装python环境安装appium1.下载地址2.下载并安装3.打开appiun进行操作Appium-Pytho
Android使用广播时出现异常:java.lang.InstantiationException: class has no zero argument constructor
zhongjianblackberry
Android android 异常 解决方案
Android开发中使用广播时遇到如下问题:java.lang.InstantiationException:classhasnozeroargumentconstructor解决方案:1,如果是静态广播注册方式、广播作为内部类来使用:广播内部类声明为static类型。2,如果是非静态广播注册方式:广播必须在类中注册(调用registerReceiver()方法)、注销(调用unregisterR
软件盘将dialog顶上去_Android实现输入法弹出时把布局顶上去和登录按钮顶上去的解决方法...
weixin_39859128
软件盘将dialog顶上去
背景:在写登录界面时,老板就觉得在输入密码的时候谈出来的输入法软键盘把登录按钮遮挡住了(入下图所示,不爽),连输入框都被挡了一半,于是不满意了,要叫我改,于是我看QQ的登录效果,我就去研究了一下,弹出输入法整个布局上来了,终于让老板满意了。(如上图这样,老板不满意的,呵呵)1,咱们就解决问题吧。我看了很多博客和问答,很多人都说直接在在AndroidManifest.xml中给这个Activity设
android输入框强制隐藏,Android输入框引起的软键盘显示与隐藏,以及窗口调整的问题研究...
霜霜很乖哦
android输入框强制隐藏
Android是一个针对触摸屏专门设计的操作系统,当点击编辑框,系统自动为用户弹出软键盘,以便用户进行输入。那么,弹出软键盘后必然会造成原有布局高度的减少,那么系统应该如何来处理布局的减少?我们能否在应用程序中进行自定义的控制?这些是本文要讨论的重点。一、软键盘显示的原理软件盘的本质是什么?软键盘其实是一个Dialog!InputMethodService为我们的输入法创建了一个Dialog,并且
【Flutter】webview_flutter使用详解
m0_74824091
vip1024p flutter
文章目录前言一、如何使用前言webview_flutter是Flutter官方推出的一款用于Flutter上的webview插件,该插件在iOS用的是WKWebView支持;在Android上用的是系统WebView。插件地址:https://pub.dev/packages/webview_flutter一、如何使用第一步:在项目根目录下运行如下命令配置依赖flutterpubaddwebvie
org.xmlpull.v1.XmlPullParserException: Unexpected token
JQ_AK47
android错误 Android初体验 android xml 服务器
org.xmlpull.v1.XmlPullParserException:Unexpectedtoken(position:unknown@5:1injava.io.InputStreamReader@3fe1c1a2)问题的原委是这样的,从服务器获取一个xml流,然后android客户端解析,但是总是包这个错误。pull解析器解析xml输入流privateBooleanparseXml(Inp
【Android 音视频开发打怪升级:音视频硬解码篇】二、音视频硬解码流程:封装基础解码框架(1)
2401_84132544
程序员 android 音视频
首先,这一系列文章均基于自己的理解和实践,可能有不对的地方,欢迎大家指正。其次,这是一个入门系列,涉及的知识也仅限于够用,深入的知识网上也有许许多多的博文供大家学习了。最后,写文章过程中,会借鉴参考其他人分享的文章,会在文章最后列出,感谢这些作者的分享。码字不易,转载请注明出处!教程代码:【Github传送门】目录一、Android音视频硬解码篇:1,音视频基础知识2,音视频硬解码流程:封装基础解
Linux 上利用 getifaddrs 函数枚举,获取理论上可用物理网卡设备
liulilittle
C/C++ linux 运维 服务器
本文所示代码可以在__ANDROID_API__>=24上编译或者在Linux上面。boolNetwork::GetLocalExitInterface(std::string&interface_,UInt32&address,UInt32&gw,UInt32&mask){boolb=false;#if(!defined(ANDROID)||__ANDROID_API__>=24)structi
解决虚幻Unreal Engine手动配置安卓打包环境后无法识别SDK问题
qq_39889893
虚幻 android 游戏引擎
情况说明首先确保sdk、jdk、ndk版本和地址全部正确,ANDROID_HOME、JAVA_HOME、ANDROID_NDK_HOME环境变量配置正确(这一步网上教程很多)UE能够正常打包apk出来,只是打包平台那里没有识别到安卓的logo,而是三角形内一个感叹号,且在点击“打包项目”按钮后,出现烦人的弹窗提示sdk未配置,关闭弹窗后又能成功打包apk出来(事实上已经成功配置了的,只是ue没有默
【项目实战】接入极光推送SDK,实现从Java服务端后台推送自定义消息到Android车机端
本本本添哥
001 - 基础开发能力 android java 开发语言
一、需求描述项目中需要接入极光推送SDK,实现从Java服务端推送消息到Android车机端,以下实现的功能主要是安卓端的,IOS端的虽然代码也兼容了,但是不在本次讨论范围内。以下是具体的实现过程。二、极光推送介绍极光推送是一款提供高效、安全、可靠的移动推送服务的云端平台,帮助用户快速实现安全的移动消息推送,它能够支持Android、iOS和Web等多个平台,为客户端App提供推送服务。它可以帮助
abp过滤规则android,ABP的数据过滤器(Data Filters)
月宫一号
abp过滤规则android
我们在数据库开发中,一般会运用软删除(softdelete)模式,即不直接从数据库删除数据,而是标记这笔数据为已删除。因此,如果实体被软删除了,那么它就应该不会在应用程序中被检索到。要达到这种效果,我们需要在每次检索实体的查询语句上添加SQL的Where条件IsDeleted=false。这是个乏味的工作。但它是个容易被忘掉的事情。因此,我们应该要有个自动的机制来处理这些问题。ABP提供数据过滤器
kotlin recycler_view must not be null
yechaoa
Kotlin 疑难杂症 Kotlin recycler_viewm kotlin
报错recycler_viewmustnotbenull解析找不到recycler_view?overridefuninitView(){recycler_view.layoutManager=LinearLayoutManager(mContext)}就上面这一行很简单的代码,居然提示找不到recycler_view,难道是kotlin-android-extensions插件的问题?不可能啊,
eclipse maven
IXHONG
eclipse
eclipse中使用maven插件的时候,运行run as maven build的时候报错
-Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match.
可以设一个环境变量M2_HOME指
timer cancel方法的一个小实例
alleni123
多线程 timer
package com.lj.timer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class MyTimer extends TimerTask
{
private int a;
private Timer timer;
pub
MySQL数据库在Linux下的安装
ducklsl
mysql
1.建好一个专门放置MySQL的目录
/mysql/db数据库目录
/mysql/data数据库数据文件目录
2.配置用户,添加专门的MySQL管理用户
>groupadd mysql ----添加用户组
>useradd -g mysql mysql ----在mysql用户组中添加一个mysql用户
3.配置,生成并安装MySQL
>cmake -D
spring------>>cvc-elt.1: Cannot find the declaration of element
Array_06
spring bean
将--------
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3
maven发布第三方jar的一些问题
cugfy
maven
maven中发布 第三方jar到nexus仓库使用的是 deploy:deploy-file命令
有许多参数,具体可查看
http://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html
以下是一个例子:
mvn deploy:deploy-file -DgroupId=xpp3
MYSQL下载及安装
357029540
mysql
好久没有去安装过MYSQL,今天自己在安装完MYSQL过后用navicat for mysql去厕测试链接的时候出现了10061的问题,因为的的MYSQL是最新版本为5.6.24,所以下载的文件夹里没有my.ini文件,所以在网上找了很多方法还是没有找到怎么解决问题,最后看到了一篇百度经验里有这个的介绍,按照其步骤也完成了安装,在这里给大家分享下这个链接的地址
ios TableView cell的布局
张亚雄
tableview
cell.imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:[indexPath row]]];
CGSize itemSize = CGSizeMake(60, 50);
&nbs
Java编码转义
adminjun
java 编码转义
import java.io.UnsupportedEncodingException;
/**
* 转换字符串的编码
*/
public class ChangeCharset {
/** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 */
public static final Strin
Tomcat 配置和spring
aijuans
spring
简介
Tomcat启动时,先找系统变量CATALINA_BASE,如果没有,则找CATALINA_HOME。然后找这个变量所指的目录下的conf文件夹,从中读取配置文件。最重要的配置文件:server.xml 。要配置tomcat,基本上了解server.xml,context.xml和web.xml。
Server.xml -- tomcat主
Java打印当前目录下的所有子目录和文件
ayaoxinchao
递归 File
其实这个没啥技术含量,大湿们不要操笑哦,只是做一个简单的记录,简单用了一下递归算法。
import java.io.File;
/**
* @author Perlin
* @date 2014-6-30
*/
public class PrintDirectory {
public static void printDirectory(File f
linux安装mysql出现libs报冲突解决
BigBird2012
linux
linux安装mysql出现libs报冲突解决
安装mysql出现
file /usr/share/mysql/ukrainian/errmsg.sys from install of MySQL-server-5.5.33-1.linux2.6.i386 conflicts with file from package mysql-libs-5.1.61-4.el6.i686
jedis连接池使用实例
bijian1013
redis jedis连接池 jedis
实例代码:
package com.bijian.study;
import java.util.ArrayList;
import java.util.List;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoo
关于朋友
bingyingao
朋友 兴趣爱好 维持
成为朋友的必要条件:
志相同,道不合,可以成为朋友。譬如马云、周星驰一个是商人,一个是影星,可谓道不同,但都很有梦想,都要在各自领域里做到最好,当他们遇到一起,互相欣赏,可以畅谈两个小时。
志不同,道相合,也可以成为朋友。譬如有时候看到两个一个成绩很好每次考试争做第一,一个成绩很差的同学是好朋友。他们志向不相同,但他
【Spark七十九】Spark RDD API一
bit1129
spark
aggregate
package spark.examples.rddapi
import org.apache.spark.{SparkConf, SparkContext}
//测试RDD的aggregate方法
object AggregateTest {
def main(args: Array[String]) {
val conf = new Spar
ktap 0.1 released
bookjovi
kernel tracing
Dear,
I'm pleased to announce that ktap release v0.1, this is the first official
release of ktap project, it is expected that this release is not fully
functional or very stable and we welcome bu
能保存Properties文件注释的Properties工具类
BrokenDreams
properties
今天遇到一个小需求:由于java.util.Properties读取属性文件时会忽略注释,当写回去的时候,注释都没了。恰好一个项目中的配置文件会在部署后被某个Java程序修改一下,但修改了之后注释全没了,可能会给以后的参数调整带来困难。所以要解决这个问题。
&nb
读《研磨设计模式》-代码笔记-外观模式-Facade
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
/*
* 百度百科的定义:
* Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,
* 隐藏子系统的复杂性,使子系统更加容易使用。他是为子系统中的一组接口所提供的一个一致的界面
*
* 可简单地
After Effects教程收集
cherishLC
After Effects
1、中文入门
http://study.163.com/course/courseMain.htm?courseId=730009
2、videocopilot英文入门教程(中文字幕)
http://www.youku.com/playlist_show/id_17893193.html
英文原址:
http://www.videocopilot.net/basic/
素
Linux Apache 安装过程
crabdave
apache
Linux Apache 安装过程
下载新版本:
apr-1.4.2.tar.gz(下载网站:http://apr.apache.org/download.cgi)
apr-util-1.3.9.tar.gz(下载网站:http://apr.apache.org/download.cgi)
httpd-2.2.15.tar.gz(下载网站:http://httpd.apac
Shell学习 之 变量赋值和引用
daizj
shell 变量引用 赋值
本文转自:http://www.cnblogs.com/papam/articles/1548679.html
Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则:
首个字符必须为字母(a-z,A-Z)
中间不能有空格,可以使用下划线(_)
不能使用标点符号
不能使用bash里的关键字(可用help命令查看保留关键字)
需要给变量赋值时,可以这么写:
Java SE 第一讲(Java SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行)
dcj3sjt126com
java jdk
Java SE 第一讲:
Java SE:Java Standard Edition
Java ME: Java Mobile Edition
Java EE:Java Enterprise Edition
Java是由Sun公司推出的(今年初被Oracle公司收购)。
收购价格:74亿美金
J2SE、J2ME、J2EE
JDK:Java Development
YII给用户登录加上验证码
dcj3sjt126com
yii
1、在SiteController中添加如下代码:
/**
* Declares class-based actions.
*/
public function actions() {
return array(
// captcha action renders the CAPTCHA image displ
Lucene使用说明
dyy_gusi
Lucene search 分词器
Lucene使用说明
1、lucene简介
1.1、什么是lucene
Lucene是一个全文搜索框架,而不是应用产品。因此它并不像baidu或者googleDesktop那种拿来就能用,它只是提供了一种工具让你能实现这些产品和功能。
1.2、lucene能做什么
要回答这个问题,先要了解lucene的本质。实际
学习编程并不难,做到以下几点即可!
gcq511120594
数据结构 编程 算法
不论你是想自己设计游戏,还是开发iPhone或安卓手机上的应用,还是仅仅为了娱乐,学习编程语言都是一条必经之路。编程语言种类繁多,用途各 异,然而一旦掌握其中之一,其他的也就迎刃而解。作为初学者,你可能要先从Java或HTML开始学,一旦掌握了一门编程语言,你就发挥无穷的想象,开发 各种神奇的软件啦。
1、确定目标
学习编程语言既充满乐趣,又充满挑战。有些花费多年时间学习一门编程语言的大学生到
Java面试十问之三:Java与C++内存回收机制的差别
HNUlanwei
java C++ finalize() 堆栈 内存回收
大家知道, Java 除了那 8 种基本类型以外,其他都是对象类型(又称为引用类型)的数据。 JVM 会把程序创建的对象存放在堆空间中,那什么又是堆空间呢?其实,堆( Heap)是一个运行时的数据存储区,从它可以分配大小各异的空间。一般,运行时的数据存储区有堆( Heap)和堆栈( Stack),所以要先看它们里面可以分配哪些类型的对象实体,然后才知道如何均衡使用这两种存储区。一般来说,栈中存放的
第二章 Nginx+Lua开发入门
jinnianshilongnian
nginx lua
Nginx入门
本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章:
nginx启动、关闭、重启
http://www.cnblogs.com/derekchen/archive/2011/02/17/1957209.html
agentzh 的 Nginx 教程
http://openresty.org/download/agentzh-nginx-tutor
MongoDB windows安装 基本命令
liyonghui160com
windows安装
安装目录:
D:\MongoDB\
新建目录
D:\MongoDB\data\db
4.启动进城:
cd D:\MongoDB\bin
mongod -dbpath D:\MongoDB\data\db
&n
Linux下通过源码编译安装程序
pda158
linux
一、程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的lib目录下的文件 配置文件:这个不必多说,都知道 帮助文档:通常是我们在linux下用man命令查看的命令的文档
二、linux下程序的存放目录 linux程序的存放目录大致有三个地方: /etc, /b
WEB开发编程的职业生涯4个阶段
shw3588
编程 Web 工作 生活
觉得自己什么都会
2007年从学校毕业,凭借自己原创的ASP毕业设计,以为自己很厉害似的,信心满满去东莞找工作,找面试成功率确实很高,只是工资不高,但依旧无法磨灭那过分的自信,那时候什么考勤系统、什么OA系统、什么ERP,什么都觉得有信心,这样的生涯大概持续了约一年。
根本不是自己想的那样
2008年开始接触很多工作相关的东西,发现太多东西自己根本不会,都需要去学,不管是asp还是js,
遭遇jsonp同域下变作post请求的坑
vb2005xu
jsonp 同域post
今天迁移一个站点时遇到一个坑爹问题,同一个jsonp接口在跨域时都能调用成功,但是在同域下调用虽然成功,但是数据却有问题. 此处贴出我的后端代码片段
$mi_id = htmlspecialchars(trim($_GET['mi_id ']));
$mi_cv = htmlspecialchars(trim($_GET['mi_cv ']));
贴出我前端代码片段:
$.aj