精华内容
下载资源
问答
  • 1、为什么我使用嵌入式node启动节点,启动后的节点不会加入到集群中? 2、使用 TransportClient 方式建立 Client,启动程序后,程序的控制台,和服务器端的es一直报错,获取节点信息失败,是什么原因?即上面的错误...
  • 不断添加数据数据是之前输入过的,返回上一个页面回来也一样 输入数据 <p><img alt="" height="118" src="https://img-ask.csdnimg.cn/upload/1613226499043.png" width="372" /></p> 添加成功 ...
  • 为什么我不能在手机上播放QQ音乐?1,Android系统;可以设置为受软件(例如360等)的限制来解锁,并且软件本身缺少数据.2,APP系统;那些未在App Store中下载的软件在其他一些软件市场中下载,因为有时这些软件市场...

    0cdb02d836ac79e89c5e2ee9f78526b9.png

    为什么我不能在手机上播放QQ音乐?

    1,Android系统;可以设置为受软件(例如360等)的限制来解锁,并且软件本身缺少数据.

    2,APP系统;那些未在App Store中下载的软件会在其他一些软件市场中下载,因为有时这些软件市场中的软件数据会丢失,并且下载只是一个空壳.

    3,APP系统的越狱版本,经常遇到软件无法使用的问题,找到可以购买此手机的地方,让他们代您处理(有时越狱不成功,导致大多数软件限制)

    4. 手机内存不足,缓存过多,导致手机死机,无法上传. 您可以关闭“ QQ音乐”进程并再次清除缓存. 可以在QQ,微信和微博上清除,也可以清除Mobile Manager等类似软件.

    5,网络状态不好,请重新连接WIFI.

    6. QQ音乐系统出现错误,请先关闭QQ音乐进程,然后再将其重新打开. 如果没有,请删除QQ音乐并重新下载.

    为什么不能连续播放QQ音乐?

    将播放顺序设置为列表循环,以便自动播放列表歌曲

    f3f5c681dd5d8bbc16a0abd79f363abd.png

    为什么我的QQ音乐无法观看视频?

    此问题与您的计算机设置以及QQ音乐软件是否正常运行密切相关. 如果您遇到这种情况,建议您尝试以下解决方案:

    1. 如果您使用“瑞星”,“金山王达”和“天网”之类的防火墙,请检查是否已设置“禁止使用QQ音乐和插件”,并将“禁止”状态更改为“允许”状态,或退出防火墙,然后重试. 请与您的防火墙提供商联系以获取详细信息;

    二,清除浏览器缓存;

    操作方法:

    1. 选择浏览器顶部的“工具”;

    2,然后选择“ Internet选项”;

    3. 点击“常规”下的“删除Cookie”;

    4. 确认完成操作.

    953b1b8a2a47c83d2dcca17ec26a524c.png

    3. 请检查计算机的Windows Media Player是否损坏,请在Windows Media Player 9上方下载并安装播放器;

    Wmp10下载地址: 单击此处输入.

    4. 更换QQ音乐软件. 请卸载以前的QQ音乐软件,然后重新下载QQ音乐软件,建议您将其安装到与尝试之前不同的路径

    QQ音乐显示无法播放,请检查声卡是否正确安装

    原因: 计算机的声卡驱动程序已损坏或未正确安装.

    1. 首先打开Driver Master应用程序,进入Driver Master主页,然后单击以打开“ Drive Management”选项.

    c995d143ad4bd113f387d355afa40f4bfb057c.jpg

    为什么我的计算机不能播放QQ音乐?

    建议您重新安装声卡驱动程序,然后再卸载QQ音乐. 重新安装可以解决问题或清除垃圾.

    455cb44ea43ab7e1c5d0b1b97cd04c7d.png

    尝试以下操作:

    1. 清理计算机上无用的文件和垃圾;它还可以提高计算机性能.

    请去官方下载并安装兔子:

    清除文件垃圾;注册表等. 使用Rabbit清理不需要重新启动.

    9d82d158ccbf6c8118c11e33b73eb13532fa4072.jpg

    为什么不能播放QQ音乐中的MV?

    QQ音乐中的MV无法播放的原因有很多:

    1. 演绎音乐库中没有相关的MV资源,导致无法播放;

    2. 由于网络原因,无法加载mv;

    1d0cd1737af6052a94b43eec8a76680f.png

    3. 带扣音乐软件本身存在故障,导致无法播放MV;

    对于第三种情况,您可以切换到其他MV以确认是否无法播放. 如果无法播放所有MV,则应考虑第三种情况. 您需要卸载该软件,然后重新安装该软件的最新版本.

    为什么“ QQ音乐”总是提示歌曲无效或网络连接失败?

    QQ音乐始终无法连接到Internet. 无法登录的原因:

    QQ被禁止访问网络,并且无法连接到网络.

    解决方案:

    1. 打开手机的安全软件,然后找到权限管理;

    2. 进入权限管理后,单击应用程序权限管理;

    3. 找到QQ音乐,然后单击进入,设置网络功能以允许使用.

    本文来自电脑杂谈,转载请注明本文网址:

    http://www.pc-fly.com/a/shumachanpin/article-295093-1.html

    展开全文
  • 初学Tensorflow,望见谅,最近在学习数据増广,发现在进行图像大小随机缩放时出错,代码如下: ``` img = tf.placeholder(tf.uint8,shape=...所以问问各位大神,这是为什么啊,为什么不能随机resize一张图啊。
  • ![图片说明](https://img-ask.csdn.net/upload/201710/25/1508915399_421295.png) 为什么会出现这种情况啊,我明明设置了白名单,返回也正常但是还是会出现这种情况
  • 这里cates为什么会是一个数组而不是对象?因为这要根据后台数据文档来定,给的是什么类型,就定义什么类型 定义fetchCatesData函数进行获取数据, wx.request后面有url和成功、失败回调函数,如果数据请求有参数则.....

    有的小程序有分类这一项,但位置和方法不相同,这里就将如何获取后台数据并初步渲染说一下

    data: {
        // 分类数据
        cates: []
        }
    

    这里cates为什么会是一个数组而不是对象?因为这要根据后台数据文档来定,给的是什么类型,就定义什么类型

    定义fetchCatesData函数进行获取数据, wx.request后面有url和成功、失败回调函数,如果数据请求有参数则在data中进行添加

     fetchCatesData() {
        wx.request({
          url: '后台提供的地址链接',
          data:'请求的参数',
          success: res => {
            this.setData({
            //将获取到的数据赋值给cates数组中,随后用于渲染
              cates: res.data.message
            })
          },
          fail: err => {
            console.log('err:', err)
          }
        })
      }
    

    并把fetchCatesData函数定义到onLoad钩子函数中

    onLoad(){
    	//获取分类的数据
    	this.fetchCatesData()
    }
    

    到这里就可以在AppData中获取到所返回的数据了
    由于小程序页面布局各不相同,这只要进行渲染并获取样式即可完成,在这里附上该分类的结构图

    <view class="cates">
      <block wx:for="{{cates}}" wx:key='index'>
        <navigator url="/pages/cates/cates" open-type="switchTab" wx:if='{{item.navigator_url}}'>
          <image src="{{item.image_src}}" />
        </navigator>
        <image wx:else src="{{item.image_src}}" />
      </block>
    </view>
    

    block不是一个组件,仅是一个包装元素,不会在页面中渲染,只接受控制属性,可以把if 或则 for 语句写在block标签 ,来控制了这一块的逻辑
    navigator的open-type="switchTab"跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
    navigator的open-type的四种属性:
    navigate 保留当前页面,跳转到应用内的某个页面
    redirect 关闭当前页面,跳转到应用内的某个页面
    reLaunch 关闭所有页面,打开到应用内的某个页面
    switchTab 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面

    展开全文
  • 一般需求中出现在Activity启动中需要获取Ui控件相关大小或者在界面绘制完成之后刷新数据,我们都知道在UI绘制完成之后,时机最好,不会阻塞主线程导致卡顿或者UI控件参数获取失败。 也许大家使用过或 知道Handler...

    一般需求中会出现在Activity启动中需要获取Ui控件相关大小或者在界面绘制完成之后刷新数据,我们都知道在UI绘制完成之后,时机最好,不会阻塞主线程导致卡顿或者UI控件参数获取失败。

    也许大家使用过或 知道Handler(MainLooper).Post(Runnable)和View.Post(Runnable)都是把Runnable封装成Message再 push到主线程中looper中MessageQueue中,会发现在Activity的生命周期中执行这两种方式效果不同,前者不满足我们的需求,而后者却能做到,但这是为啥,有没有深入分析,本文就从Activity启动流程以及UI刷新和绘制流程原理以及消息循环机制、同步障碍机制来剖析。

    先看demo运行效果,以获取Ui控件大小为例子,如下:

    class MyActivity extends Activity{
    .....
      @Override
     protected void onCreate(Bundle savedInstanceState) 
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
      myCustomView = findViewById(R.id.custom);
       Log.i("chuan", "onCreate init myCustomView  width=" + myCustomView.getWidth());
    }
     @Override
        protected void onResume() {
            super.onResume();
       Log.i("chuan", "Main onResume");
            new Handler().post(new Runnable() {
                @Override
                public void run() {
                    Log.i("chuan", "onResume Handler post runnable button width=" + myCustomView.getWidth());
                }
            });
            myCustomView.post(new Runnable() {
                @Override
                public void run() {
                    Log.i("chuan", "onResume myCustomView post runnable button width=" + myCustomView.getWidth());
                }
            });
        }
    public class MyView extends View {
      @Override
        public void layout(int l, int t, int r, int b) {
            super.layout(l, t, r, b);
            Log.i("chuan", "myView layout");
        }
        @Override
        protected void onAttachedToWindow() {
            Log.i("chuan", "myView onAttachedToWindow with"+getWidth());
            try {
                Object mAttachInfo = ReflectUtils.getDeclaredField(this, View.class, "mAttachInfo");
                Log.i("chuan", "myView onAttachedToWindow mAttachInfo=null?" + (mAttachInfo == null));
                Object mRunQueue = ReflectUtils.getDeclaredField(this, View.class, "mRunQueue");
                Log.i("chuan", "myView onAttachedToWindow mRunQueue=null?" + (mRunQueue == null));
            } catch (Exception e) {
            }
            super.onAttachedToWindow();
        }
        @Override
        public boolean post(Runnable action) {
            try {
                Object mAttachInfo = ReflectUtils.getDeclaredField(this, View.class, "mAttachInfo");
                Log.i("chuan", "myView post mAttachInfo=null?" + (mAttachInfo == null));
            } catch (Exception e) {
            }
            return super.post(action);
        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Log.i("chuan", "myView onDraw");
            }
    }

    日志显示结果:

    /chuan: myView init
    /chuan: Main onCreate   
    /chuan: onCreate init myCustomView  width=0
    /chuan: Main onResume
    /chuan:
        myView post mAttachInfo=null?true
    /chuan: onResume Handler post runnable button width=0
    /chuan: myView onAttachedToWindow width=0
        myView onAttachedToWindow mAttachInfo=null?false
    /chuan: myView layout
    /chuan: myView onDraw
    /chuan: onResume myCustomView post runnable button width=854 

    从日志中可以看出几点

    1. 在Activity可交互之前的生命周期中UI直接操作是失效的,即使通过handler把Ui操纵任务post到onResume生命周期之后,也依然获取失效,日志可以看到此时ui界面都没有绘制。

    2. 发现View.post(Runnable)会让runnable在该View完成了measure、layout、draw之后再执行,这个时候当然就可以获取到Ui相关参数了。

    先看下两者的源码实现:

    1、handler.post(Runnable)

    Handler.class
    public final boolean post(Runnable r){
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

    代码简单可以看到就是把runnable封装成Message然后加入当前Looper的MessageQueue队列中。

    2、再看下View.post(Runnable)

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        //先是通过attachInfo.mHandler.post来实现,实际上就是用Handler.post和上述一样
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
        //若attachInfo =null时,维护一个mRunQueue 队列,
        // 然后在dispatchAttachedToWindow通过mRunQueue.executeActions(info.mHandler);跟上述方法一样
        getRunQueue().post(action);
        return true;
    }
      void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
        if (mOverlay != null) {
            mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
        }
    ..........省略....
        // Transfer all pending runnables.
        if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
        performCollectViewAttributes(mAttachInfo, visibility);
        onAttachedToWindow();
    .......省略......
    }
    private HandlerActionQueue getRunQueue() {
        if (mRunQueue == null) {
            mRunQueue = new HandlerActionQueue();
        }
        return mRunQueue;
    }
    
    //实际也是通过handler来post到主线程
    public void executeActions(Handler handler) {
        synchronized (this) {
            final HandlerAction[] actions = mActions;
            for (int i = 0, count = mCount; i < count; i++) {
                final HandlerAction handlerAction = actions[i];
                handler.postDelayed(handlerAction.action, handlerAction.delay);
            }
            mActions = null;
            mCount = 0;
        }
    }
    
    

    通过源码调用发现最终都是通过handler.post()方式来加入到主线程队列中,api调用一样为何效果不一样,下面就从如下几个知识点来分析:

    1. Activity生命周期启动流程

    2. Message消息发送和执行原理机制

    3. UI绘制刷新触发原理机制

    4. MessageQueue同步障碍机制

    Activity启动流程 :ApplicationThread收到AMS的scheduleLaunchActivity的Binder消息之后,原因是binder线程,会通过ActivityThread中的mH(Handler)来sendMessage;

    mH(Handler)会把这个异步消息加入到MainLooper中MessageQueue,等到执行时候回调handleLaunchActivity,handleLaunchActivity方法会执行很多方法,这个是入口,简单来说会创建Activity对象,调用其启动生命周期,attach、onCreate、onStart、onResume,以及添加到WindowManager中,重点看下本文中onResume生命周期是如何回调的。

    在Activity可见之后,紧接着就是要触发绘制界面了,会走到handleResumeActivity方法,会performResumeActivity调用activity的onResume方法

    public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null && !r.activity.mFinished) {
           .....................
            try {
                r.activity.onStateNotSaved();
                r.activity.mFragments.noteStateNotSaved();
                //调用activity的onResume方法
                r.activity.performResume();
    ...............................
            } catch (Exception e) {
           ........   
            }
        }
        return r;
    }
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        //1、调用activity的onResume方法
        ActivityClientRecord r = performResumeActivity(token, clearHide);
           ......
        if (r != null) {
            final Activity a = r.activity;
            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
          .......................
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                //2、decorView先暂时隐藏
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    //3、关键函数 添加到window触发ui测量、布局、绘制
                    wm.addView(decor, l);
                }
            ..............       
                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
                if (r.activity.mVisibleFromClient) {
                //4、添加decorView之后,设置可见,从而显示了activity的界面
                    r.activity.makeVisible();
                }
            }
    }  

    由此可见:从handleResumeActivity执行流程来看onResume调用时候,Activity中的UI界面并没有经过measure、layout、draw等流程,所以直接在onResume或者之前的onCreate中执行ui操纵都是无用的,因为这个时候Ui界面不可见,没有绘制。那为何通过hander.post(Runnable)让执行发生在handleLaunchActivity这个Message之后,这个时候流程已经走完了,也是在Ui界面触发绘制之后,怎么还是不行呢。

    Message消息发送和执行原理机制这里就不阐述了,hander.post(Runnable)让执行发生在handleLaunchActivity这个Message之后就是因为这个Message循环机制原理,可以让任务通常让加入的先后顺序依次执行,所以handleLaunchActivity这个Message执行之后,就是onResume中的push的Message。

    但是为何onResume中hander.post(Runnable)还不能ui操作呢,就猜测handleLaunchActivity之后还没有同步完成UI绘制,那UI绘制刷新触发原理机制是怎么样的了,直接分析触发条件,上文中的wm.addVIew开始:windowManager会通过子类WindowManagerImpl来实现,其内部又通过WindowManagerGlobal的单实例来实现addVIew,源码如下 

    WindowManagerGlobal.class

    public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
          ...............
            ViewRootImpl root;
            View panelParentView = null;
            ......
            //ViewRootImpl整个UI操作实际控制着
                root = new ViewRootImpl(view.getContext(), display);
                view.setLayoutParams(wparams);
                mViews.add(view);
                mRoots.add(root);
                mParams.add(wparams);
            }
    .................
            // do this last because it fires off messages to start doing things
            try {
            //绑定decorView,并触发开发绘制
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
            }
        }

    addView动作又转给ViewRootImpl.setView来实现,具体源码如下: 
    ViewRootImpl.class

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ..........
                //触发刷新绘制的关键
                requestLayout();
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                ..........
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    //通过binder call添加到Display
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
           ...............
            //decorView添加父类ViewParent 就是ViewRootImpl
                view.assignParent(this);
            }
        }
    }

    setView完成了上述几个重要步骤,其中requestLayout的实现是如何触发刷新绘制的:

    从上述代码可以发现在addView之后同步执行到requestLayout,再到scheduleTraversals中设置了同步障碍消息,这个简单阐述,看下源码实现: 

    MessageQueue.class

    private int postSyncBarrier(long when) {
       synchronized (this) {
            final int token = mNextBarrierToken++;
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            msg.arg1 = token;
            Message prev = null;
            Message p = mMessages;
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            if (prev != null) { // invariant: p == prev.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }
    //根据token移动这个Message
    public void removeSyncBarrier(int token) {
        // Remove a sync barrier token from the queue.
        // If the queue is no longer stalled by a barrier then wake it.
        synchronized (this) {
            Message prev = null;
            Message p = mMessages;
            while (p != null && (p.target != null || p.arg1 != token)) {
                prev = p;
                p = p.next;
            }
            if (p == null) {
                throw new IllegalStateException("The specified message queue synchronization "
                        + " barrier token has not been posted or has already been removed.");
            }
            final boolean needWake;
            if (prev != null) {
                prev.next = p.next;
                needWake = false;
            } else {
                mMessages = p.next;
                needWake = mMessages == null || mMessages.target != null;
            }
            p.recycleUnchecked();
            // If the loop is quitting then it is already awake.
            // We can assume mPtr != 0 when mQuitting is false.
            if (needWake && !mQuitting) {
                nativeWake(mPtr);
            }
        }
    }

    MessageQueue同步障碍机制: 可以发现就是把一条Message,注意这个Message是没有设置target的,整个消息循环唯一一处不设置回调的target(hander),因为这个即使标志了同步障碍消息,也是不需要handler来pushMessage到队列中,直接手动循环移动链表插入到合适time的Message之后的即可。

    然后是如何识别这个障碍消息的呢,在Looper的loop循环获取MessageQueue.next()函数获取下一个的message,是如何实现的,

    MessageQueue.class

    Message next() {
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            //查询是否有下一个消息,没有就阻塞
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                //关键地方,首先识别 msg.target == null情况就是同步障碍消息,如果该消息是同步障碍消息的话,就会循环查询下一个消息是否是isAsynchronous状态,异步Message,专门给刷新UI消息使用的
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                //如果查到异步消息或者没有设置同步障碍的消息,直接返回执行
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
             ........省略.................
          nextPollTimeoutMillis = 0;
        }
    }

    可以看到scheduleTraversals中设置了同步障碍消息,就是相当于在MessageQueue中插入了一个Message,并且是在onResume之后插入的,所以在onResume中handler.post(Runnable)之后,这个消息会在同步障碍Message之前,会先被执行,这个时候依然没有刷新绘制界面,待查询到同步障碍Message时候,会等待下个异步Message(刷新Message)出现。

    所以在onResume中handler.post(Runnable)是Ui操作失效的。

    那么为何View.post(Runnable)就可以了,再回过头来看下其源码: 
    View.class

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }

    由于在onResume中执行,这个时候ViewRootImpl还没有初始化(addView时),而mAttachInfo是在ViewRootImpl构造函数中初始化的,过此时mAttachInfo=null,从上文知道 getRunQueue()维护了一个mRunQueue 队列,然后在dispatchAttachedToWindow通过mRunQueue.executeActions(info.mHandler);那这个方法dispatchAttachedToWindow什么会被调用,回顾上文中ViewRootImpl第一次收到Vsync同步刷新信号之后会执行performTraversals,这个函数内部做了个判断当时第一次mFirst时候会调用host.dispatchAttachedToWindow(mAttachInfo, 0);把全局mAttachInfo下发给所有子View,其源码如下: 

    View.class

    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
        if (mOverlay != null) {
        //向下分发info,其实现在ViewGroup中
            mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
        }
        mWindowAttachCount++;
        // We will need to evaluate the drawable state at least once
     .........
        // Transfer all pending runnables.
        if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
        performCollectViewAttributes(mAttachInfo, visibility);
        onAttachedToWindow();
        ........
    }

    由此可以知道在performTraversals(Message)中push Message到主线中,肯定会这个performTraversals(Message)之后再执行,并且在doTraversals中移除了同步障碍消息(Message),故会依次执行。所以onResume中View.post的Message就会在performTraversals之后执行,而performTraversals就是完成了View整个测量、布局和绘制。当View的mAttachInfo !=null时也说明肯定完成过UI绘制。

    感谢看完,看似简单的东西,其实内部原理没有分析清楚容易糊涂,同时研究源码会学到很多相关的知识点,例如要看懂本文就需要了解上文中提到的4个知识点。 
    1. Activity生命周期启动流程 
    2. Message消息发送和执行原理机制 
    3. UI绘制刷新触发原理机制 
    4. MessageQueue同步障碍机制

     

     

     

     

     

     

     

     

    展开全文
  • 为什么要用 Message Queue? 1.解耦 在项目启动之初来预测将来项目碰到什么需求,是极其困难的。消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展...

    为什么要用 Message Queue?

    1.解耦
    在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束

    2.冗余
    有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。在被许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理过程明确的指出该消息已经被处理完毕,确保你的数据被安全的保存直到你使用完毕。

    3.扩展性
    因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的;只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。

    4.灵活性 & 峰值处理能力
    在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。

    5.可恢复性
    当体系的一部分组件失效,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。而这种允许重试或者延后处理请求的能力通常是造就一个略感不便的用户和一个沮丧透顶的用户之间的区别。

    6.送达保证
    消息队列提供的冗余机制保证了消息能被实际的处理,只要一个进程读取了该队列即可。在此基础上, IronMQ 提供了一个”只送达一次”保证。无论有多少进程在从队列中领取数据,每一个消息只能被处理一次。这之所以成为可能,是因为获取一个消息只是”预定”了这个消息,暂时把它移出了队列。除非客户端明确的表示已经处理完了这个消息,否则这个消息会被放回队列中去,在一段可配置的时间之后可再次被处理。

    7.顺序保证
    在大多使用场景下,数据处理的顺序都很重要。消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。 IronMO 保证消息通过 FIFO(先进先出)的顺序来处理,因此消息在队列中的位置就是从队列中检索他们的位置。

    8.缓冲
    在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行—写入队列的处理会尽可能的快速,而不受从队列读的预备处理的约束。该缓冲有助于控制和优化数据流经过系统的速度。

    9.理解数据流
    在一个分布式系统里,要得到一个关于用户操作会用多长时间及其原因的总体印象,是个巨大的挑战。消息系列通过消息被处理的频率,来方便的辅助确定那些表现不佳的处理过程或领域,这些地方的数据流都不够优化。

    10.异步通信
    很多时候,你不想也不需要立即处理消息。消息队列提供了异步处理机制,允许你把一个消息放入队列,但并不立即处理它。你想向队列中放入多少消息就放多少,然后在你乐意的时候再去处理它们。

    Messagequeue 的数据结构是什么?

    基础数据结构中“先进先出”的一种数据结构
     


     

    展开全文
  • 刚开始怀疑所JSON的格式错了,但为什么有时候成功呢? 于是怀疑所有些数据里面可能保护\n,\r等字符,影响了解析。可是加入了转义甚至替换之后,该问题还是没解决,陷入了困境。 难道所因为数据被截断了? 没...
  • //授权获取经纬度信息 getIndexData() { var _this = this; wx.getLocation({ type: 'gcj02', success(res) { _this.getData(res....目前不知道官方为什么会优先这个 在调试过程中数据直接为空、也就是在 .
  • 为什么会出现在mounted钩子函数中获取元素失败呢 原因:我们的dom中的数据是通过异步获取到的 而mounted钩子函数只会执行一次并且在他执行的时候数据还没有请求过来 所以获取不到dom 解决方法:我们可以watch与...
  • 糟糕的工作秩序如何造成严重破坏 几句话可以使或打破一个维护团队。工单就是证明。 "过去,做出错误的决定是因为我们没有准确的工单信息,"米勒库尔斯的资产护理规划师蒂姆·戴维森...这就是为什么本文要回到基础
  • 请问 为什么本地爬虫爬取获取json数据 获取成功,放到服务器上运行就会获取失败?这问题到底出在哪里? 用的requests 设置和不设置headers都试过了 结果一样。 html = requests.get(url) print html.text 本地的...
  • 打开URL后的数据:!...写的测试类: ``` ... import java.io.ByteArrayOutputStream;...import java.io.IOException;... System.out.println("----------------------------listchangdu--------------...为什么这里报错呢?
  • 获取数据失败,请重试'); }); }, showMsg(str){ this.$toast({ message: str, duration: 2000, }); }, /** * 刷新 * */ refresh(done) { const that = this; console.log("当前是...
  • UDP报文头部(源端口,目的端口,报头长度和数据长度和,校验和),有16位的校验...若数据一致表示这条数据可以交付给上层处理(当用户调用recvfrom能够获取数据);因为协议中有长度所以就根据头部中的长度进行交...
  • //获取exe数据在被创建进程时的状态(内存映射状态) //Step6:创建一个挂起的进程 int a = CreateProcess(StrName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &Shell_pi); if (!a) { ...
  • 为什么要用Message Queue  解耦 在项目启动之初来预测将来项目碰到什么需求,是极其困难的。消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或...
  • 我开了3个浏览器测试正常后,关闭其中一个就这个异常以下是我的代码麻烦各位大神给看看 ``` package test; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java....
  • System.out.println("获取数据库连接失败!!"); } return conn; } /*获取Statement对象*/ public void getStmt(){ createConn(); try{ //调用Connection类实例的createStatement()方法...
  • //这也是说明为什么stSize既是一个输入量也是一个输出量 //释放原来的内存空间 delete pIpAdapterInfo; //重新申请内存空间用来存储所有网卡信息 pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize...
  • 心力交瘁啊,这个错误一般都是数据库和模型不对一产生的问题,但是还是有特殊情况的嘛。 我遇到特殊情况就是...解决方法:重新拉取模型,我不知道为什么会出现这种问题,因为平常很少看警告这里东西,所以下次...
  • 为什么获取不了数据?等等等等 1、这是因为我代码里全国的cookies需要你自己打开浏览器更新好后替换,而且这个cookies大概只能持续20秒左右! 2、另外全国卫健委的数据格式一直在变,也有可能导致爬取失败! 代码 ...
  • 然后检查一下代码,发现传递的Key和获取的Key都没错,但是为什么在目标Activity会获取不到传递过来的数据? 然后查资料,发现是Activity的启动模式导致的,MainActivity 设置的启动模式是singleTask , 也就是说,...
  • 因此打算换成抓包分析接口获取,此贴仅记录学习过程,项目基于springboot,提供关键代码,其他配置就不提供了,都是比较简单的,如果有知道为什么失败率那么高也请告诉我(页面都是能访问的,但是跑的时候有很多...
  • 找到一个公开的诗词API,尝试写了个一个js去请求,但因为网络或者接口的原因,导致请求超时或者失败,于是想写一个判断返回然后超时或者失败重新请求的js,苦于新手,一直不知道怎么拿到返回的数据,代码如下** ...
  • 为什么会出现这样的情况呢?这期我们就来看看这个"诡异"的事件。坐好了,准备发车!查看内存使用情况首先想要知道 Redis 内存的使用情况,我们就需要获取相关的信息。Redis 中查看内存相关信息是很简单的,只需要在...
  • //必须等待一段时间,rs485才数据发送出去 control_rs485('1'); ret = read_uart_data(xrdata,5); if(ret ) { LOGD("Open: fail to get uart data\n"); } if((xrdata[0]==0x00) && (xrdata[1]==...
  • 更新说明:0.7版(2018.12.13)1) 添加 自定义数据值 直接取指针的用法例子.2) 修改 添加() 方法返回值 变更 整数型(0=添加失败 1=成功添加 2=覆盖)3) 修复 类全局变量时异常问题(将HeapAlloc、HeapFree、...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 165
精华内容 66
关键字:

为什么会获取数据失败