抢红包插件实现原理浅析

抢红包,先看效果图~

实现自动抢红包,解决问题有两点:

一:如何实时监听发红包的事件

二:如何在红包到来的时候自动进入页面并自动点击红包

一、如何获取红包到来的事件

为了获取红包到来状态栏的变化,我们要用到一个类:Accessibility

许多Android使用者因为各种情况导致他们要以不同的方式与手机交互。

这包括了有些用户由于视力上,身体上,年龄上的问题致使他们不能看完整的屏幕或者使用触屏,也包括了无法很好接收到语音信息和提示的听力能力比较弱的用户。

Android提供了Accessibility功能和服务帮助这些用户更加简单地操作设备,包括文字转语音(这个不支持中文),触觉反馈,手势操作,轨迹球和手柄操作

OK,了解到这一点,那么接下来就顺利点了,首先来看看Accessibility以及AccessibilityService的使用

  1. 新建一个类继承AccessibilityService,并在AndroidManifest文件里注册它:
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
<application>
<service   android:name="com.zkhb.weixinqinghongbao.service.QiangHongBaoService"
android:label="@string/app_name"     android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
 <intent-filter>
     <action android:name="android.accessibilityservice.AccessibilityService" />
     </intent-filter>
    <meta-data
      android:name="android.accessibilityservice"          android:resource="@xml/qianghongbao_service_config" />
     </service>
</application>  

在子类QiangHongBaoService里实现几个重要的重载方法:

onServiceConnected() - 可选。系统会在成功连接上你的服务的时候调用这个方法,在这个方法里你可以做一下初始化工作,例如设备的声音震动管理,也可以调用setServiceInfo()进行配置工作。

onAccessibilityEvent() - 必须。通过这个函数可以接收系统发送来的AccessibilityEvent,接收来的AccessibilityEvent是经过过滤的,过滤是在配置工作时设置的。

onInterrupt() - 必须。这个在系统想要中断AccessibilityService返给的响应时会调用。在整个生命周期里会被调用多次。

onUnbind() - 可选。在系统将要关闭这个AccessibilityService会被调用。在这个方法中进行一些释放资源的工作。

然后在/res/xml/accessibility_service_config.xml:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"  android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags=""
    android:canRetrieveWindowContent="true"
    android:description="@string/accessibility_description"
    android:notificationTimeout="100"
    android:packageNames="com.tencent.mm" />

二、主要关注点以及如何在红包到来的时候自动进入页面并自动点击红包

onAccessibilityEvent方法中监听状态栏的变化,主要有:AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED、AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED、AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED

在响应窗体以及窗体内容变化时处理相关逻辑,获取带微信消息时以下代码打开消息:

  //将微信的通知栏消息打开
        Notification notification = (Notification) event.getParcelableData();
        PendingIntent pendingIntent = notification.contentIntent;
        try {
            pendingIntent.send();
        } catch (PendingIntent.CanceledException e) {
            e.printStackTrace();
        }

具体代码网上有很多,一般都是通过:findAccessibilityNodeInfosByTextfindAccessibilityNodeInfosByViewId查找文本或者资源节点进行点击操作,但新版微信开红包页面进行了处理,没有文本信息,而如果采用:

图中resouces-id这种形式就可能出现这种情况:

在了解整个核心后,获取事件不外乎就是通过文本与id判断,那么就可以将文本改为图标方式,将id改为动态id(每次显示都是随机生成),这样一来就可以提高外挂的门槛。

如何进行规避呢,目前我想的是既然开红包的页面文本和ID都有可能会变,那我们能不能找个不变的进行判断呢,考虑过后,我觉得最可能不变的地方就是开红包这个按钮的位置,也就是图中的bounds,于是在思考过后有了下面的处理:

  for (int i = 0; i < nodeInfo.getChildCount(); i++) {
            //Log.e("TAG", "getViewIdResourceName :"+nodeInfo.getChild(i).getViewIdResourceName());
            Rect outBounds = new Rect();
            nodeInfo.getChild(i).getBoundsInScreen(outBounds);
            int left_dp = px2dip(this, 400);
            int top_dp = px2dip(this, 1035);
            int right_dp = px2dip(this, 682);
            int bottom_dp = px2dip(this, 1320);

            int left_px = dip2px(this, left_dp);
            int top_px = dip2px(this, top_dp);
            int right_px = dip2px(this, right_dp);
            int bottom_px = dip2px(this, bottom_dp);

            Rect mStandar = new Rect(left_px,top_px,right_px,bottom_px);
            if(mStandar.contains(outBounds)){
                Log.e("TAG", "outBounds.left :"+outBounds.left+";outBounds.top :"+outBounds.top+";outBounds.right :"+outBounds.right+";outBounds.bottom :"+outBounds.bottom);
                nodeInfo.getChild(i).performAction(AccessibilityNodeInfo.ACTION_CLICK);
                break;
            }
        }

这里取的矩形区域要比按钮区域稍大点,然后判断到开红包页面按钮是否在我们预先设置的区域内,如果在,我们直接进行点击开红包操作:AccessibilityNodeInfo.ACTION_CLICK

其他比如如何防止重复抢等细节问题,也是要处理的问题。

好了,直接放下关键代码,仅供参考:

package com.zkhb.weixinqinghongbao.service;

import java.util.Date;
import java.util.List;

import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.app.KeyguardManager.KeyguardLock;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;

import com.zkhb.weixinqinghongbao.MainActivity;
import com.zkhb.weixinqinghongbao.R;
import com.zkhb.weixinqinghongbao.entity.HongBaoInfo;
import com.zkhb.weixinqinghongbao.util.DateFormatUtils;
import com.zkhb.weixinqinghongbao.util.LogUtil;

/**
 *
 * 抢红包服务
 */
@SuppressLint("NewApi")
public class QiangHongBaoService extends AccessibilityService {

//    static final String TAG = "QiangHongBao";

    /** 微信的包名*/
    static final String WECHAT_PACKAGENAME = "com.tencent.mm";
    /** 红包消息的关键字*/
    static final String HONGBAO_TEXT_KEY = "[微信红包]";
    /** 红包消息的关键字*/
    static final String HONGBAO_TEXT_KEY1 = "微信红包";

    private static final int ENVELOPE_RETURN = 0;

    private static final String LOCK_TAG = "屏幕";

    Handler handler = new Handler();
    /** 是否在抢红包界面里*/
//    public boolean isInMM=false;
    /** 是否可以点击*/
//    public boolean ISCLICKED=false;
    /** 是否进入过拆红包界面*/
    public static boolean ISCOMINQIANGCHB=false;
    //真正的
    public static boolean ISCOMINQIANGCHB2=false;
    //真正的判断
    public static boolean ISCOMINQIANGCHB3=false;
     /** 是否来自通知栏*/
    private static boolean ISCOMNOTIFY=false;

    private PowerManager pm;
    //点亮屏幕
    private WakeLock mWakeLock;
     //解锁锁定屏幕
    private KeyguardLock keyguardLock;
    /**判断之前用户是否锁屏  */
    private static boolean islock=false;
    /**通知服务 */
    private NotificationManager n_manager;
    public void unlock(){
        if(pm==null){
            pm = (PowerManager) getApplication().getSystemService(Context.POWER_SERVICE);
        }
        boolean isScreenOn = pm.isScreenOn();//如果为true,则表示屏幕“亮”了,否则屏幕“暗”了。
        if(!isScreenOn){
            islock=true;
            KeyguardManager keyguardManager = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);
            keyguardLock = keyguardManager.newKeyguardLock(LOCK_TAG);
            keyguardLock.disableKeyguard();

            mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, LOCK_TAG);
            mWakeLock.acquire();
        }
    }

    public void lock(){
        if(islock){
            //释放屏幕常亮锁
            if(null != mWakeLock) {
                mWakeLock.release();
            }
            //屏幕锁定
            if(keyguardLock!=null){
                keyguardLock.reenableKeyguard();
            }
        }
    }
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        final int eventType = event.getEventType();

        LogUtil.info("事件---->" + event);

        //通知栏事件
        if(eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
            unlock();
            List<CharSequence> texts = event.getText();
            if(!texts.isEmpty()) {
                for(CharSequence t : texts) {
                    String text = String.valueOf(t);
                    if(text.contains(HONGBAO_TEXT_KEY)) {
                        ISCOMNOTIFY=true;
                        ISCOMINQIANGCHB=false;
                        openNotify(event);
                        break;
                    }
                }
            }
        } else if(eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            unlock();
            openHongBao(event);
//            AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
//            List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText = nodeInfo.findAccessibilityNodeInfosByText("领取红包");
//            if(findAccessibilityNodeInfosByText.isEmpty()){
//              isInMM=false;
//            }else{
//              isInMM=true;
//            }
//            List<CharSequence> text = event.getText();
//            if(text.size()>=0){
//              CharSequence charSequence = text.get(0);
////                if(charSequence.equals("微信")){
////                    isInMM=true;
////                }else{
////                    isInMM=false;
////                }
//            }
        }else if(eventType==AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && ISCOMNOTIFY){
            unlock();
            openHongBao(event);
            List<AccessibilityNodeInfo> InfoText = getRootInActiveWindow().findAccessibilityNodeInfosByText("领取红包");
            if(!InfoText.isEmpty()){
                checkKey2();
                ISCOMNOTIFY=false;
            }
        }
    }
    /*@Override
    protected boolean onKeyEvent(KeyEvent event) {
        //return super.onKeyEvent(event);
        return true;
    }*/
    @Override
    public boolean onUnbind(Intent intent) {
        Toast.makeText(this, "断开抢红包服务", Toast.LENGTH_SHORT).show();
        ISCOMINQIANGCHB=false;
        islock=false;
        ISCOMINQIANGCHB2=false;
        ISCOMINQIANGCHB3=false;
        ISCOMNOTIFY=false;
        setNotification("已关闭抢红包小助手服务~~",Notification.FLAG_AUTO_CANCEL,"已关闭抢红包小助手服务~~~");
        return super.onUnbind(intent);
    }
    @Override
    public void onInterrupt() {
        Toast.makeText(this, "中断抢红包服务", Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        ISCOMINQIANGCHB=false;
        ISCOMINQIANGCHB2=false;
        ISCOMINQIANGCHB3=false;
        islock=false;
        ISCOMNOTIFY=false;

        setNotification("已开启抢红包小助手服务~~",Notification.FLAG_NO_CLEAR,"已开启抢红包小助手服务~~~");

        Toast.makeText(this, "连接抢红包服务", Toast.LENGTH_SHORT).show();
    }

    private void setNotification(String content,int flags,String title) {
        if(n_manager==null){
            n_manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
        }
        n_manager.cancelAll();
        Notification notification=new Notification(R.drawable.ic_launcher, content, System.currentTimeMillis());
//        notification.defaults |= Notification.DEFAULT_VIBRATE;
//        long[] vibrate = {0,100,200,300}; //0毫秒后开始振动,振动100毫秒后停止,再过200毫秒后再次振动300毫秒
//        notification.vibrate=vibrate;
        notification.flags |= flags; //表明在点击了通知栏中的"清除通知"后,此通知不清除,

        Intent notificationIntent = new Intent(this,MainActivity.class); //点击该通知后要跳转的Activity
        PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),0,notificationIntent,0);
        notification.setLatestEventInfo(getApplicationContext(), title, "进入微信抢红包~~", contentIntent);

        n_manager.notify(0, notification);
    }

    private void sendNotifyEvent(){
        AccessibilityManager manager= (AccessibilityManager)getSystemService(ACCESSIBILITY_SERVICE);
        if (!manager.isEnabled()) {
            return;
        }
        AccessibilityEvent event=AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
        event.setPackageName(WECHAT_PACKAGENAME);
        event.setClassName(Notification.class.getName());
        CharSequence tickerText = HONGBAO_TEXT_KEY;
        event.getText().add(tickerText);
        manager.sendAccessibilityEvent(event);
    }

    /** 打开通知栏消息*/
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void openNotify(AccessibilityEvent event) {
        if(event.getParcelableData() == null || !(event.getParcelableData() instanceof Notification)) {
            return;
        }
        //将微信的通知栏消息打开
        Notification notification = (Notification) event.getParcelableData();
        PendingIntent pendingIntent = notification.contentIntent;
        try {
            pendingIntent.send();
        } catch (PendingIntent.CanceledException e) {
            e.printStackTrace();
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void openHongBao(AccessibilityEvent event) {
        if("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI".equals(event.getClassName())) {
            //点中了红包,下一步就是去拆红包
            ISCOMINQIANGCHB=true;
            ISCOMINQIANGCHB2=true;
            checkKey1();
        } else if("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI".equals(event.getClassName())) {
            //拆完红包后看详细的纪录界面
             LogUtil.info("事件---->com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI");
             //nonething
//          if(ISCOMINQIANGCHB){
//              ISCOMINQIANGCHB=false;
//          }
             if(ISCOMINQIANGCHB2){
                 ISCOMINQIANGCHB3=true;
             }else{
                 ISCOMINQIANGCHB3=false;
             }
            checkKey3();
            ISCOMINQIANGCHB=true;
            ISCOMINQIANGCHB2=false;
            performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
            if(getSharedPreferences("config", Context.MODE_PRIVATE).getBoolean("auto", false)){
                performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);
            }
            lock();
        } else if("com.tencent.mm.ui.LauncherUI".equals(event.getClassName())) {
//          isInMM=true;
            //在聊天界面,去点中红包
            LogUtil.info("事件---->com.tencent.mm.ui.LauncherUI");
            checkKey2();
        }
    }
    @SuppressLint("NewApi") @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void checkKey3() {
        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
         if(nodeInfo == null) {
             LogUtil.info("rootWindow为空333");
             return;
         }
         //TODO
         List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText = nodeInfo.findAccessibilityNodeInfosByText("元");
         if(findAccessibilityNodeInfosByText.size()>=0){
             AccessibilityNodeInfo accessibilityNodeInfo2 = findAccessibilityNodeInfosByText.get(0).getParent();
             CharSequence money = accessibilityNodeInfo2.getChild(2).getText();
             CharSequence name = accessibilityNodeInfo2.getChild(0).getText();
             if(ISCOMINQIANGCHB3){
                 HongBaoInfo info=new HongBaoInfo();
                 info.setStrDateTime(DateFormatUtils.format("yyyy-MM-dd HH:mm:ss", new Date()));
                 info.setStrMoney(money+"");
                 info.setStrName(name+"");
                 info.save();
             }
             Toast.makeText(getApplicationContext(), money+":::"+name, 0).show();
         }
//       List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/aw8");
//       AccessibilityNodeInfo accessibilityNodeInfo = findAccessibilityNodeInfosByViewId.get(0);
//       CharSequence text = accessibilityNodeInfo.getText();
    }

    private void checkKey1() {
        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if(nodeInfo == null) {
            LogUtil.info("rootWindow为空11111");
            return;
        }

        for (int i = 0; i < nodeInfo.getChildCount(); i++) {
            Log.e("TAG", "getViewIdResourceName :"+nodeInfo.getChild(i).getViewIdResourceName());
            Rect outBounds = new Rect();
            nodeInfo.getChild(i).getBoundsInScreen(outBounds);
            int left_dp = px2dip(this, 400);
            int top_dp = px2dip(this, 1035);
            int right_dp = px2dip(this, 682);
            int bottom_dp = px2dip(this, 1320);

            int left_px = dip2px(this, left_dp);
            int top_px = dip2px(this, top_dp);
            int right_px = dip2px(this, right_dp);
            int bottom_px = dip2px(this, bottom_dp);

            Rect mStandar = new Rect(left_px,top_px,right_px,bottom_px);
            if(mStandar.contains(outBounds)){
                Log.e("TAG", "outBounds.left :"+outBounds.left+";outBounds.top :"+outBounds.top+";outBounds.right :"+outBounds.right+";outBounds.bottom :"+outBounds.bottom);
                nodeInfo.getChild(i).performAction(AccessibilityNodeInfo.ACTION_CLICK);
                break;
            }
//          nodeInfo.performAction(action)//[405,1042][675,1312]
        }
        //List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("拆红包");

//  List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/b5d");
//        for(AccessibilityNodeInfo n : list) {
//            n.performAction(AccessibilityNodeInfo.ACTION_CLICK);
//        }
    }

    private void checkKey2() {
        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if(nodeInfo == null) {
            LogUtil.info("rootWindow为空222222");
            return;
        }
        List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("领取红包");
        if(list.isEmpty()) {
            list = nodeInfo.findAccessibilityNodeInfosByText(HONGBAO_TEXT_KEY);
            for(AccessibilityNodeInfo n : list) {
                LogUtil.info("-->微信红包:" + n);
                n.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                break;
            }
        } else {
            //最新的红包领起
            AccessibilityNodeInfo parent = list.get(list.size() - 1).getParent();
//          Log.w(TAG, "ISCLICKED::"+ISCLICKED)!ISCLICKED;
            if(parent != null && !ISCOMINQIANGCHB) {
                parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
//            for(int i = list.size() - 1; i >= 0; i --) {
//                AccessibilityNodeInfo parent = list.get(i).getParent();
//                Log.i(TAG, "-->领取红包:" + parent);
//                if(parent != null && parent.isClickable()) {
//                    parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
//                    break;
//                }
//            }
//            performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
        }
    }
    /**
     * @param info 当前节点
     * @param matchFlag 需要匹配的文字
     * @param type  操作的类型
     */
    @SuppressLint("NewApi")
    public void recycle(AccessibilityNodeInfo info, String matchFlag, int type) {
        if (info != null) {
            if (info.getChildCount() == 0) {
                CharSequence desrc = info.getContentDescription();
                switch (type) {
                    case ENVELOPE_RETURN://返回
                        if (desrc != null && matchFlag.equals(info.getContentDescription().toString().trim())) {
                            if (info.isCheckable()) {
                                info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                            } else {
                                performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
                            }
                        }
                        break;
                }
            } else {
                int size = info.getChildCount();
                for (int i = 0; i < size; i++) {
                    AccessibilityNodeInfo childInfo = info.getChild(i);
                    if (childInfo != null) {
                        LogUtil.info("index: " + i + " info" + childInfo.getClassName() + " : " + childInfo.getContentDescription()+" : "+info.getText());
                        recycle(childInfo, matchFlag, type);
                    }
                }
            }
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        lock();
    }
    /**
     * 根据手机的分辨率从 dip 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }  

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
//        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / 3 + 0.5f);  //3是本人手机的设备密度
    }
}

AccessibilityService还可以用在智能安装、虚拟按键上都有很多应用,这样的实践只是给我们一种解决问题另外的一种思路,问题嘛,总还是要解决的。

时间: 2024-08-04 03:45:55

抢红包插件实现原理浅析的相关文章

OpenVAS漏洞扫描插件工作原理浅析

开始阅读此文之前请安装好OSSIM v4.15OpenVAS釆用***测试原理,利用Scanner模块中的脚本引擎对目标进行安全检测.Openvas的Scanner的扫描性能依赖于同时进行扫描的并发进程数,不同的硬件环境上可设置的最有效并发扫描数各不相同,Openvas的扫描引擎设备可在保证系统稳定的前提下达到最佳的扫描性能,对于大型网络使用标准设备进行部署可大大降低安装和维护成本.脚本引擎根据用户提交的配置与要求,首先对脚本进行加载与调度,按照顺序依次调用脚本并解析执行,实现扫描功能. 0.什

Android中微信抢红包插件原理解析和开发实现

一.前言 自从去年中微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导致了.或许是网络的原因,而且这个也是最大的原因.但是其他的不可忽略的因素也是要考虑到进去的,比如在手机充电锁屏的时候,我们并不知道有人已经开始发红包了,那么这时候也是让我们丧失了一大批红包的原因.那么关于网络的问题,我们开发者可能用相关技术无法解决(当然在Google和Facebook看来的话,他们

【Spark Core】TaskScheduler源码与任务提交原理浅析2

引言 上一节<TaskScheduler源码与任务提交原理浅析1>介绍了TaskScheduler的创建过程,在这一节中,我将承接<Stage生成和Stage源码浅析>中的submitMissingTasks函数继续介绍task的创建和分发工作. DAGScheduler中的submitMissingTasks函数 如果一个Stage的所有的parent stage都已经计算完成或者存在于cache中,那么他会调用submitMissingTasks来提交该Stage所包含的Tas

Handler原理浅析

    理解Handler的原理首先要搞清楚什么是Looper,在我的上一篇博文中对此有专门的介绍.Looper的作用是开启一个消息循环,从MessageQueue(Message队列,是Looper的成员变量)中循环取出消息处理.一个线程要使用Handler来处理来自其它线程的消息,这个线程必须有且仅有一个Looper对象与之绑定,也可以说一个Looper对象是是与一个线程一一对应的. Hander有一个Looper类型的成员,在Handler的构造函数(new Handler()或者new

微信QQ的二维码登录原理浅析

在很多地方就是都出现了使用二维码登录,二维码付款,二维码账户等应用(这里的二维码种马,诈骗就不说了),二维码验证,多终端辅助授权应用开始多起来,这里先说下啥是二维码,其实二维码就是存了二进制数据的黑白图片,当出现要求二维码登录的时候,服务器会生成一条临时的唯一的二维码信息,发送到客户端以二维码(图片)的形式写入到网页,然后你就会看到统一的四个方形的二维码,如果做的好这个二维码信息应该是有时效的,这里暂且不考虑这些,就简单的微信登录作为例子看看吧: 首先说下整个授权流程: 在客户端网页中会不断向服

Atitit&#160;插件机制原理与设计微内核&#160;c#&#160;java&#160;的实现attilax总结

Atitit 插件机制原理与设计微内核 c# java 的实现attilax总结 1. 微内核与插件的优点1 2. 插件的注册与使用2 2.1. Ioc容器中注册插件2 2.2. 启动器微内核启动3 3. 插件的俩种执行策略3 3.1. 必须手动接续,否则自动终止(推荐)3 3.2. 必须手动throw  stop ex终止,负责自动接续..4 4. 插件链的生成原理4 5. -------code4 6. 参考7 1. 微内核与插件的优点 但凡有生命力的产品,都是在扩展性方面设计的比较好的,因

php中的插件机制原理和实例

PHP中的插件机制原理和实例 投稿:junjie 字体:[增加 减小] 类型:转载 这篇文章主要介绍了PHP中的插件机制原理和实例,文中例子主要借鉴了网上一些网友的方式做了稍微的改造,需要的朋友可以参考下 PHP项目中很多用到插件的地方,更尤其是基础程序写成之后很多功能由第三方完善开发的时候,更能用到插件机制,现在说一下插件的实现.特点是无论你是否激活,都不影响主程序的运行,即使是删除也不会影响. 从一个插件安装到运行过程的角度来说,主要是三个步骤: 1.插件安装(把插件信息收集进行采集和记忆的

深入解读PHP插件机制原理

深入解读PHP插件机制原理 PHP插件机制是指一类特定的功能模块,主要特点有:可以随时激活删除使用,灵活性较强.大家可以在文章中获得这一机制的相关知识. AD:51CTO移动APP安全沙龙!马上要爆满,手慢没座位! 我们在这篇文章中主要向大家讲了一些PHP插件机制的实现方法.希望大家可以通过本问介绍的内容初步了解对PHP插件机制的认识. PHP函数restore()重置PHP配置环境 PHP数据缓存类必要性分析 PHP创建PPT文档范例解析 总结各种不同PHP控制语句 PHP INCLUDE语句

LINQ内部执行原理浅析

C#3.0 增加LINQ的特性 一.基本概念 LINQ,语言级集成查询(Language INtegrated Query) 经过了最近 20 年,面向对象编程技术( object-oriented (OO) programming technologies )在工业领域的应用已经进入了一个稳定的发展阶段.程序员现在都已经认同像类(classes).对象(objects).方法(methods)这样的语言特性.考察现在和下一代的技术,一个新的编程技术的重大挑战开始呈现出来,即面向对象技术诞生以来