首页 文章 精选 留言 我的

精选列表

搜索[c 17],共10016篇文章
优秀的个人博客,低调大师

JPDA 架构研究17 - JDI概览

引入: 前面用了很多篇幅来讨论JVMTI和JDWP部分,现在终于来看最靠近用户端部分了,JDI。 分析: a. JDI的基础知识 和JVMTI和JDWP不一样的是,JDI提供了一组接口,这些接口是纯JAVA编写的。他们主要是给开发环境IDE用的,虽然调试器的实现可以直接利用JDWP或者JVMTI,但是多了这一层则可以从用户的代码级别来定义要发送的请求和获取的信息。 本质上,Eclipse的调试器与目标VM之间的双向通信如下: 调试器将用户的操作转化为调试命令,命令通过链接被发送到前端运行目标程序的虚拟机上;然后,目标虚拟机根据接受的命令做出相应的操作,将调试的结果发回给后端的调试器;最后,调试器可视化数据信息反馈给用户。 JDI接口定义在$JAVA_HOME/lib/tools.jar中,从宏观上看,它分为5个大包。 包名 描述 com.sun.jdi 这是JDI的核心包,它提供了镜像机制将目标虚拟机上的所有数据、类型、域、方法、事件、状态和资源,以及调试器发向目标虚拟机的事件请求等都映射成 Mirror 对象 com.sun.jdi.connect 该包用于定义JDI到目标虚拟机的连接 com.sun.jdi.connect.spi 该包用于定义开发TransportService(也就是前面我在JDWP层讨论很深的传输器服务)所需要的必要的类和接口。 com.sun.jdi.event 该包定义了JDI事件和事件处理 com.sun.jdi.request 该包用于发送JDI事件然后在一定条件下发送。 b.JDI的具体实现 以Eclipse为例: org.eclipse.jdt.debug 是 JDI 的一个完整实现,而org.eclipse.jdt.debug.ui 是 Eclipse 调试工具界面的实现。从包名上看,我们大体上把JDI 分成三个部分: (1)数据模块。它负责调试器(Debugger)和目标虚拟机上(Target VM)的数据建模。 (2)链接模块。它建立调试器(Debugger)与目标虚拟机(Target VM)的沟通渠道。 (3)事件请求与处理模块。它提供调试器(Debugger)与目标虚拟机(VM)之间的交互方式。 我们会在接下来的几篇文章中从Eclipse的代码级别来分析这些模块。 本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1587958,如需转载请自行联系原作者

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

android 17 activity生命周期

手机指南针传感器处于手机头部。 Activity生命周期: 启动。 onCreat()方法:初始化布局对象,设置监听器。 onstart()方法:注册监听器。 onResume():activity已经是屏幕最前端了, running,已经是最前端了,可以触摸了,可以响应。 onPause():其他activity把之前的ancity完全遮住了,则调用onPause()方法暂停本acticity,然后调用onStop方法停止这个activity。如果只是部分遮住,则调用onPause()方法暂停本acticity,不调用onStop方法。停止住的acticity的数据和成员变量都是保存的,当挡住的acticity不遮住的时候会重新加载,里面的数据可以重新使用。处于暂停和停止的acticity的数据和成员变量都是保存的可以重新使用。处于暂停和停止的acticity有2种走向,当系统内存不足是会把停止的acticity杀掉,出了暂停的acticity优先级高于停止的acticity,当内存极度缺乏的时候也会杀掉处于暂停的acticity。但系统内存足够的时候,当挡住的activity不再挡住时,处于暂停的acticity调用onResume()方法启动,处于停止的activity调用onRestart()方法启动。 关掉activity时会依次调用onPause()onStop()ondestiry()方法,ondestiry()可以保存数据释放流资源和监听器和网络资源。流资源和数据库占用的是系统内存之外的资源,gc只能回收内存的对象,因此要释放外部资源。 如果系统资源匮乏,处于停止的activity被系统杀掉了则不会执行onDestory(),所以在onStop()方法里面就要释放资源。 第一个activity: package com.sxt.day04_03; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("main","onCreate()"); setListener(); } private void setListener() { findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(MainActivity.this, SecondActivity.class); startActivity(intent); } }); } @Override protected void onStart() { super.onStart(); Log.i("main","onStart()"); } @Override protected void onResume() { super.onResume(); Log.i("main","onResume()"); } @Override protected void onPause() { super.onPause(); Log.i("main", "onPause()"); } @Override protected void onStop() { super.onStop(); Log.i("main","onStop()"); } @Override protected void onDestroy() { super.onDestroy(); Log.i("main","onDestroy()"); } @Override protected void onRestart() { super.onRestart(); Log.i("main","onRestatr()"); } } 第二个activity: package com.sxt.day04_03; import android.app.Activity; import android.os.Bundle; public class SecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); } } 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/4886430.html,如需转载请自行联系原作者

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

UNIX 时间即将进入 17 亿纪元

UNIX 时间(或称 POSIX 时间)是 UNIX 或类 UNIX 系统使用的时间表示方式:从 UTC 1970 年 1 月 1 日 0 时 0 分 0 秒起至现在的总秒数,不考虑闰秒(由于 UTC 包括了闰秒,但在 POSIX 时间中闰秒会被忽略以提供一种简便且兼容的计算时差的方法。因此POSIX 时间转换后不一定是 UTC,尽管它也存在)。 再过两天,北京时间 2023/11/1506:13:20,UNIX 时间将进入 1700000000纪元。 上一次“亿级更新”:UNIX 时间 16 亿秒纪念

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

Spring Boot(17)——使用Spring Data JPA

使用Spring Data JPA 使用Spring Data JPA需要在pom.xml中添加spring-boot-starter-data-jpa依赖。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> 之后就可以在应用中定义Entity了,并使用javax.persistence相关注解了。比如下面就定义了一个简单的User实体。 @Entity @Table(name="tb_user") @Data public class User { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; private String name; private String username; } 之后可以定义自己的JpaRepository。 public interface UserJpaRepository extends JpaRepository<User, Long> { List<User> findByName(String name); } 如果你的目录结构是按照Spring Boot建议的目录结构,上面定义的Repository将自动被Spring Boot扫描到,并被注册为一个Spring bean。Spring Boot默认会扫描标注了@SpringBootApplication注解的Class所在的package下面的所有的package。如果需要扫描其它目录下的Repository,则可以通过@EnableJpaRepositories("com.xxx.package")来指定。 之后就可以在Service中注入定义好的Repository进行相应的增删改查了,比如下面这样: @Service public class UserService { @Autowired private UserJpaRepository userRepository; public void save(User user) { this.userRepository.save(user); } public void save(List<User> users) { this.userRepository.saveAll(users); } public List<User> findByName(String name) { return this.userRepository.findByName(name); } public Optional<User> findById(Long id) { return this.userRepository.findById(id); } } 添加了spring-boot-starter-data-jpa依赖后,默认会使用JPA的Hibernate实现。org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration将负责JPA的自动配置,其只有在bean容器中只定义了一个DataSource时才会进行自动配置。可以通过spring.jpa前缀的配置属性配置Hibernate JPA的相关信息,对应的配置属性将由org.springframework.boot.autoconfigure.orm.jpa.JpaProperties负责接收。可以通过spring.jpa.show-sql指定是否需要打印SQL语句,可以通过spring.jpa.hibernate.*指定Hibernate特定的配置信息。比如通过spring.jpa.hibernate.ddl-auto指定是否需要基于实体配置自动应用对应的DDL语句到数据库,它相当于使用Hibernate时的hibernate.hbm2ddl.auto。 spring.jpa.database=mysql spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update Spring Boot会自动注册org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor,以便可以在Web应用中使用懒加载。如果不需要自动注册OpenEntityManagerInViewInterceptor,则可以配置spring.jpa.open-in-view=false。关于JPA可以配置的更多信息请参考org.springframework.boot.autoconfigure.orm.jpa.JpaProperties的API文档。 Spring Boot默认会自动扫描Jpa Repository,如果不希望自动扫描Repository,可以配置spring.data.jpa.repositories.enabled=false。 本文主要介绍在Spring Boot应用中如何使用Spring Data Jpa,关于Spring Data Jpa的更多应用请参考相应的文档。 (注:本文是基于Spring Boot 2.0.3所写)

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

17.源码阅读(Touch事件分发)

有这样一个布局,Activity中有一个ViewGroup,ViewGroup中又放了一个View,我重写了Activity的dispatchTouchEvent和onTouchEvent,重写了ViewGroup的dispatchTouchEvent,onInterceptTouchEvent和onTouchEvent,重写了View的dispatchTouchEvent和onTouchEvent,然后触摸一下TestTouchView,看看控制台打印了什么结果 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".test.source.TestViewTouchActivity"> <com.app.rzm.test.view.TestTouchViewGroup android:layout_width="match_parent" android:background="#f00" android:layout_height="400dp"> <com.app.rzm.test.view.TestTouchView android:layout_width="200dp" android:background="#0f0" android:id="@+id/touch" android:layout_height="200dp" /> </com.app.rzm.test.view.TestTouchViewGroup> </LinearLayout> 1.默认没有任何拦截和事件处理的情况下打印结果 05-28 08:07:49.305 1590-1590/com.app.rzm D/Activity: dispatchTouchEvent:0 05-28 08:07:49.306 1590-1590/com.app.rzm D/ViewGroup: dispatchTouchEvent:0 onInterceptTouchEvent:0 05-28 08:07:49.306 1590-1590/com.app.rzm D/View: dispatchTouchEvent:0 05-28 08:07:49.307 1590-1590/com.app.rzm D/View: onTouchEvent:0 05-28 08:07:49.307 1590-1590/com.app.rzm D/ViewGroup: onTouchEvent:0 05-28 08:07:49.309 1590-1590/com.app.rzm D/Activity: onTouchEvent:0 05-28 08:07:49.327 1590-1590/com.app.rzm D/Activity: dispatchTouchEvent:2 onTouchEvent:2 05-28 08:07:49.344 1590-1590/com.app.rzm D/Activity: dispatchTouchEvent:2 onTouchEvent:2 05-28 08:07:49.361 1590-1590/com.app.rzm D/Activity: dispatchTouchEvent:2 onTouchEvent:2 05-28 08:07:49.377 1590-1590/com.app.rzm D/Activity: dispatchTouchEvent:2 05-28 08:07:49.378 1590-1590/com.app.rzm D/Activity: onTouchEvent:2 05-28 08:07:49.394 1590-1590/com.app.rzm D/Activity: dispatchTouchEvent:2 05-28 08:07:49.395 1590-1590/com.app.rzm D/Activity: onTouchEvent:2 可以看到在没有进行事件拦截的情况下,打印的顺序如上,我们可以简单分析以下事件传递流程: 有一点需要注意,事件的按下,滑动和抬起三种类型事件是一个一个进行传递的 1.当手指触摸屏幕时,按下事件收到响应,Activity的dispatchTouchEvent收到回调,将按下事件传递到了ViewGroup中的dispatchTouchEvent方法 2.ViewGroup收到按下事件时,调用onInterceptTouchEvent判断是否拦截按下事件,因为没有设置拦截,所以按下事件又被传递到View的dispatchTouchEvent方法中 3.View收到按下事件,传递到它的onTouchEvent方法去处理,由于这个View并没有设置处理这个事件,所以又将它传递到父布局ViewGroup的onTouchEvent中,看它是不是需要处理 4.ViewGroup的onTouchEvent收到这个事件,仍没有进行处理,所以又将事件传递到了Activity的onTouchEvent方法 5.Activity同样不处理,所以这个事件因为没人处理,所以就不了了之 6.ACTION_DOWN事件没有被处理,ACTION_MOVE事件就一直在Activity的dispatchTouchEvent和onTouchEvent方法间传递,直到ACTION_UP事件响应 Touch事件传递流程.jpg 源码中事件的传递,首先来到Activity的dispatchTouchEvent中 /** * Called to process touch screen events. You can override this to * intercept all touch screen events before they are dispatched to the * window. Be sure to call this implementation for touch screen events * that should be handled normally. * * @param ev The touch screen event. * * @return boolean Return true if this event was consumed. */ public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { //这个方法是提供出来进行重写的,不用管 onUserInteraction(); } //开始分发触摸事件 if (getWindow().superDispatchTouchEvent(ev)) { return true; } //如果事件没有被处理,则执行onTouchEvent方法 return onTouchEvent(ev); } 来到PhoneWindow中的superDispatchTouchEvent,可以看到它调用了DecorView中的方法,通过之前看setContentView的源码(https://www.jianshu.com/p/2f87ebe77f4e)我们已经认识了DecorView,接下来进入DecorView源码中 @Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); } 可以看到DecorView又调用了它父类的方法 public boolean superDispatchTouchEvent(MotionEvent event) { return super.dispatchTouchEvent(event); } 进入ViewGroup中的dispatchTouchEvent方法,这里是事件分发的源头。我们可以看到在这个方法中,做了许多的条件判断,而最终都会执行方法dispatchTransformedTouchEvent,区别在于方法中传递的参数会根据场景而有所不同 @Override public boolean dispatchTouchEvent(MotionEvent ev) { ...... boolean handled = false; //过滤掉一些不安全的劫持式的触摸事件 if (onFilterTouchEventForSecurity(ev)) { final int action = ev.getAction(); final int actionMasked = action & MotionEvent.ACTION_MASK; //新的按下事件产生时就初始化所有之前的触摸状态 //检测事件是否被拦截 if (!canceled && !intercepted) { //获取到当前得到焦点的view View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus() ? findChildWithAccessibilityFocus() : null; if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { if (newTouchTarget == null && childrenCount != 0) { final float x = ev.getX(actionIndex); final float y = ev.getY(actionIndex); //获取到所有可以接收这个触摸事件的view封装到集合中 final ArrayList<View> preorderedList = buildTouchDispatchChildList(); ...... for (int i = childrenCount - 1; i >= 0; i--) { final int childIndex = getAndVerifyPreorderedIndex( childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView( preorderedList, children, childIndex); if (childWithAccessibilityFocus != null) { if (childWithAccessibilityFocus != child) { continue; } childWithAccessibilityFocus = null; i = childrenCount - 1; } ...... if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { ...... break; } ....... } ....... } if (newTouchTarget == null && mFirstTouchTarget != null) { ...... } } } ...... return handled; } 我们来到方法dispatchTransformedTouchEvent中,这个方法的作用就是将触摸事件传递到当前的view中,如果当前view为null,就传递到它的上一层的ViewGroup,最终的是携带的MotionEvent参数,可以看到当存在按下滑动等事件时,这些事件会被封装到MotionEvent中传递到view /** * Transforms a motion event into the coordinate space of a particular child view, * filters out irrelevant pointer ids, and overrides its action if necessary. * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead. */ private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) { final boolean handled; // Canceling motions is a special case. We don't need to perform any transformations // or filtering. The important part is the action, not the contents. final int oldAction = event.getAction(); //如果当前事件是取消,则将取消参数设置给MotionEvent传递到view中 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) { event.setAction(MotionEvent.ACTION_CANCEL); if (child == null) { handled = super.dispatchTouchEvent(event); } else { handled = child.dispatchTouchEvent(event); } event.setAction(oldAction); return handled; } //获取到手指触摸移动的位置信息 // Calculate the number of pointers to deliver. final int oldPointerIdBits = event.getPointerIdBits(); final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits; // If for some reason we ended up in an inconsistent state where it looks like we // might produce a motion event with no pointers in it, then drop the event. if (newPointerIdBits == 0) { return false; } // If the number of pointers is the same and we don't need to perform any fancy // irreversible transformations, then we can reuse the motion event for this // dispatch as long as we are careful to revert any changes we make. // Otherwise we need to make a copy. final MotionEvent transformedEvent; //回调位置信息到下一级的view的dispatchTouchEvent方法 if (newPointerIdBits == oldPointerIdBits) { if (child == null || child.hasIdentityMatrix()) { if (child == null) { handled = super.dispatchTouchEvent(event); } else { final float offsetX = mScrollX - child.mLeft; final float offsetY = mScrollY - child.mTop; event.offsetLocation(offsetX, offsetY); handled = child.dispatchTouchEvent(event); event.offsetLocation(-offsetX, -offsetY); } return handled; } transformedEvent = MotionEvent.obtain(event); } else { transformedEvent = event.split(newPointerIdBits); } // Perform any necessary transformations and dispatch. if (child == null) { handled = super.dispatchTouchEvent(transformedEvent); } else { final float offsetX = mScrollX - child.mLeft; final float offsetY = mScrollY - child.mTop; transformedEvent.offsetLocation(offsetX, offsetY); if (! child.hasIdentityMatrix()) { transformedEvent.transform(child.getInverseMatrix()); } handled = child.dispatchTouchEvent(transformedEvent); } // Done. transformedEvent.recycle(); return handled; } 事件从ViewGroup分发到了View的dispatchTouchEvent方法,我们进入View的这个方法中,这里涉及到onTouch,onTouchEvent和onClick方法的回调顺序问题,可以在代码中看到,在onClickListener 和onTouchListener都设置了的情况下,最先执行的会是onTouch,并且如果onTouch方法返回值设置为true,那么将不会再往下回调onTouchEvent和onClick方法,事件就被onTouch拦截了;当其返回值为false,则会继续向下开始执行onTouchEvent,onClick方法是在onTouchEvent之后执行的,所以三者的执行顺序,在没有拦截的情况下,可见是onTouch > onTouchEvent > onClick /** * Pass the touch screen motion event down to the target view, or this * view if it is the target. * * @param event The motion event to be dispatched. * @return True if the event was handled by the view, false otherwise. */ public boolean dispatchTouchEvent(MotionEvent event) { ...... boolean result = false; ...... final int actionMasked = event.getActionMasked(); if (actionMasked == MotionEvent.ACTION_DOWN) { // Defensive cleanup for new gesture //按下后停止view的滑动 stopNestedScroll(); } //安全性过滤 if (onFilterTouchEventForSecurity(event)) { if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { result = true; } //ListenerInfo 对象封装了所有的view的监听相关的信息 //例如onTouchListener onClickListener等,只要给view设置 //了监听,这个对象就会被创建,可以在下一个代码块中 //看到ListenerInfo 的结构类型 ListenerInfo li = mListenerInfo; //这里会决定onTouch方法是否执行,如果给view设置了 //onTouchListener,那么ListenerInfo 对象存在,li != null满足 //li.mOnTouchListener != null也满足, //(mViewFlags & ENABLED_MASK) == ENABLED //用来判断这个view是否可用,如果被设置为enable false,那么 //是无法处理事件的,条件都满足了,就会回调onTouch方法了 if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } if (!result && onTouchEvent(event)) { result = true; } } if (!result && mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } // Clean up after nested scrolls if this is the end of a gesture; // also cancel it if we tried an ACTION_DOWN but we didn't want the rest // of the gesture. if (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL || (actionMasked == MotionEvent.ACTION_DOWN && !result)) { stopNestedScroll(); } return result; } ListenerInfo static class ListenerInfo { /** * Listener used to dispatch focus change events. * This field should be made private, so it is hidden from the SDK. * {@hide} */ protected OnFocusChangeListener mOnFocusChangeListener; /** * Listeners for layout change events. */ private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; protected OnScrollChangeListener mOnScrollChangeListener; /** * Listeners for attach events. */ private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; /** * Listener used to dispatch click events. * This field should be made private, so it is hidden from the SDK. * {@hide} */ public OnClickListener mOnClickListener; /** * Listener used to dispatch long click events. * This field should be made private, so it is hidden from the SDK. * {@hide} */ protected OnLongClickListener mOnLongClickListener; /** * Listener used to dispatch context click events. This field should be made private, so it * is hidden from the SDK. * {@hide} */ protected OnContextClickListener mOnContextClickListener; /** * Listener used to build the context menu. * This field should be made private, so it is hidden from the SDK. * {@hide} */ protected OnCreateContextMenuListener mOnCreateContextMenuListener; private OnKeyListener mOnKeyListener; private OnTouchListener mOnTouchListener; private OnHoverListener mOnHoverListener; private OnGenericMotionListener mOnGenericMotionListener; private OnDragListener mOnDragListener; private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; OnCapturedPointerListener mOnCapturedPointerListener; } 进入onTouchEvent方法,这个方法处理的比较复杂,我们删除一些非核心的代码来看.setOnClickListener的onClick方法最后是在抬起手指的时候执行的,所以这里有一个问题,如果你自定义的View重写了onTouchEvent,并且没有调用父类的super.onTouchEvent方法,那么你设置的onClickListener将会失效 /** * Implement this method to handle touch screen motion events. * <p> * If this method is used to detect click actions, it is recommended that * the actions be performed by implementing and calling * {@link #performClick()}. This will ensure consistent system behavior, * including: * <ul> * <li>obeying click sound preferences * <li>dispatching OnClickListener calls * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when * accessibility features are enabled * </ul> * * @param event The motion event. * @return True if the event was handled, false otherwise. */ public boolean onTouchEvent(MotionEvent event) { //检查是否可点击 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { switch (action) { //在手势抬起时执行onClick方法 case MotionEvent.ACTION_UP: ...... if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick(); ...... break; case MotionEvent.ACTION_DOWN: ...... break; case MotionEvent.ACTION_CANCEL: ...... break; case MotionEvent.ACTION_MOVE: ...... break; } return true; } return false; } public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); notifyEnterOrExitForAutoFillIfNeeded(true); return result; } 总结一下,到这里touch事件传递机制基本上简单的走了以下流程。事件开始的起点在所触摸的Activity的dispatchTouchEvent方法,通过这个方法将事件通过PhoneWindow传递到DecorView,然后又传递到ViewGroup中,在ViewGroup中进行事件的分发,首先获取到所有可以接收这个事件的View集合,然后将事件传递到当前获取焦点的View,一层一层的传递,经过ViewGroup的dispatchTouchEvent onInterceptTouchEvent方法进入View的dispatchTouchEvent方法,最后进入onTouchEvent方法进行事件的处理

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

阿里云前端周刊 - 第 17 期

推荐 1. Styled-Components 实战 http://www.ruanyifeng.com/blog/2017/07/neural-network.html Styled-Components 是由 Max Stoiber 与 Glen Maddern 创建的新的 CSS-in-JS 工具库,能够帮你组织 React 或者 React Native 项目中的样式声明。本文则着眼于介绍 Styled-Components 的设计理念与基本用法,首先介绍了 Styled-Components 的设计目标,然后介绍了如何使用 Styled-Components 来创建可复用的组件或者创建全局样式声明。 2. React Redux 概念与工作流清单 https://github.com/uanders/react-redux-che

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

开源大数据周刊-第17期

阿里云E-Mapreduce动态 E-Mapreduce团队 1.4版本(已经发布) 作业运行失败报警 作业并行提交 添加sqoop、shell类型的作业 1.4.1版本(已经发布) 完善失败报警 完善定时任务,增加小时、分钟定时任务 1.5.0版本 (正在研发) 集群整体运行情况的仪表盘 集群状态监控报警 1.6.0版本 交互式查询(支持hive、spark) 资讯 大数据投资人必读:中国大数据发展与投资分析报告随着大数据蕴涵价值的逐步释放,使其成为IT信息产业中最具潜力的蓝海。大数据正以一种革命风暴的姿态闯入人们视野,其技术和市场在快速发展,而驾驭大数据的呼声则一浪高过一浪。于是有人说中国大数据产业有炒作“过热”之嫌,也有人认为大数据投资正当时,那么企业家面对当下国内大数据产业到底该不该投资呢?本文或许可以给你点思路。 大数据技术催生高管新职位——首席数据官

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

屠龙刀法17——模式备份、清空、恢复

模式其实就是数据库中表格、视图、函数、存储过程等对象的集合逻辑体,在Mysql中模式是指的database,在Oracle中模式是指的user。一个具体的应用往往需要一个或者几个模式的支持,因此以模式为单位进行数据备份和恢复,无论在数据安全和开发测试环境中都非常有意义。使用DBCS可以把整个模式中的数据和对象全部备份到本地的一个目录中,也支持把备份好的目录中的所有数据和对象恢复到数据库中。

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

ShareX 17 发布,截图与屏幕录制工具

ShareX 是一个开源截图工具,可捕获或记录屏幕的任何区域,并一键共享。 它还允许将图像、文本或其他类型的文件上传到超过 80 个支持的存储服务上。 ShareX 17.0 正式发布,更新内容如下: 滚动捕获改进: 在滚动捕获期间自动忽略底部 50px,对于底部水平滚动条等情况很有用。 添加了“Auto ignore bottom edge”选项,除了默认的 50px 之外,该选项还会比较两张图像以识别底部的静态部分。 在滚动捕获窗口中添加了“Copy”按钮。 为某些操作添加了通知声音: 屏幕录制 stop/pause/abort 操作。 滚动捕获动作。 “Pin to screen”工具。 “Screen color picker”工具。 “Borderless window”工具。 浏览器扩展操作。 Silent OCR 操作。 “Disable/Enable hotkeys”操作。 添加了“Play sound after action is completed”选项。 添加了“Use custom action completed sound”选项。 从 silentOCR 操作中删除了 toast 通知。 删除了“Disable notifications”选项。 增加了阿拉伯语支持。 当设置“DisableUpload”registry 时,隐藏主窗口中的上传相关项。 无论上传失败或停止,均可将任务保存到历史记录中。 允许在“Borderless window”工具中恢复 borderless window。 添加了“Make active window borderless”热键。 添加了“Make active window top most”热键。 添加了“Pin to screen (Close all)”热键。 删除了 YouTube 图标,因为 Google 不允许使用 16x16 尺寸的 logo。 删除了 Google Photos image uploader。(原因:https://developers.googleblog.com/en/google-photos-picker-api-launch-and-library-api-updates/) 删除了 adf.ly URL shortener。 删除了 ShareX 12.4.0 之前生成的 .sxcu 文件的向后兼容性。 更多详情可查看:https://getsharex.com/changelog#v17.0.0

资源下载

更多资源
Mario

Mario

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

Spring

Spring

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

Sublime Text

Sublime Text

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册