GVKun编程网logo

路径运动与anime.js(路径运动和定位运动)

21

以上就是给各位分享路径运动与anime.js,其中也会对路径运动和定位运动进行解释,同时本文还将给你拓展AndroidScaleAnimation和TranslateAnimation,如何避免Sca

以上就是给各位分享路径运动与anime.js,其中也会对路径运动和定位运动进行解释,同时本文还将给你拓展Android ScaleAnimation和TranslateAnimation,如何避免ScaleAnimation运动、android.animation.TimeAnimator.TimeListener的实例源码、android.animation.TimeAnimator的实例源码、Android进程启动与Activity显示等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

路径运动与anime.js(路径运动和定位运动)

路径运动与anime.js(路径运动和定位运动)

如何解决路径运动与anime.js?

我正在尝试使用anime.js制作一个非常简单的动画,其中两个点应该沿着一条路径不断移动。有谁知道为什么动画在某个点停止并返回?我想让它无限旋转。是路径有问题还是功能有问题?

代码笔:[https://codepen.io/Martschioo/pen/eYBNOZv]

谢谢各位! 马斯奇奥

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

Android ScaleAnimation和TranslateAnimation,如何避免ScaleAnimation运动

Android ScaleAnimation和TranslateAnimation,如何避免ScaleAnimation运动

我有一个ScaleSet,里面有一个ScaleAnimation和一个TranslateAnimation,如下所示:

TranslateAnimation:

TranslateAnimation goTopFromright =
        new TranslateAnimation(0,-(right.getLeft()-top.getLeft()),-(right.getTop()-top.getTop()));

ScaleAnimation:

ScaleAnimation =  setSizeforTop = new ScaleAnimation(1,2,1,2);

和AnimationSet:

bringToLeftFromTopAnimationSet  = new AnimationSet(true);
bringToTopFromrightAnimationSet.addAnimation(goTopFromright);
bringToTopFromrightAnimationSet.addAnimation(setSizeforTop);

问题是,当我尝试仅使用ScaleAnimation时,我的项目会转到我想要的位置,但是当我在AnimationSet中使用ScaleAnimation和TranslateAnimation时,我的项目翻译的次数超出了我的需要,就像ScaleAnimation引入了一些补充一样动作abd我不知道如何删除它们.

谢谢您的帮助.

解决方法

正确的解决方案是改变动画的顺序.规模必须先行:
bringToTopFromrightAnimationSet.addAnimation(setSizeforTop);
bringToTopFromrightAnimationSet.addAnimation(goTopFromright);

android.animation.TimeAnimator.TimeListener的实例源码

android.animation.TimeAnimator.TimeListener的实例源码

项目:NoticeDog    文件:PanelView.java   
void init() {
    this.handler = new Handler(Looper.getMainLooper());
    this.mAnimationCallback = new TimeListener() {
        public void onTimeUpdate(TimeAnimator animation,long totalTime,long deltaTime) {
            PanelView.this.animationTick(deltaTime);
        }
    };
    this.mStopAnimator = new Runnable() {
        public void run() {
            if (PanelView.this.mTimeAnimator != null && PanelView.this.mTimeAnimator.isstarted()) {
                PanelView.this.LOG("Stop Animator : stopping",new Object[0]);
                PanelView.this.mTimeAnimator.end();
                PanelView.this.mRubberbanding = false;
                PanelView.this.mClosing = false;
            }
        }
    };
    this.mTimeAnimator = new TimeAnimator();
    this.mTimeAnimator.setTimeListener(this.mAnimationCallback);
}
项目:android-chromium-view    文件:GenericTouchGesture.java   
private Runnable createJBRunnable() {
    // On JB,we rely on TimeAnimator to send events tied with vsync.
    return new Runnable() {
        @Override
        public void run() {
            mTimeAnimator = new TimeAnimator();
            mTimeAnimator.setTimeListener(new TimeListener() {
                @Override
                public void onTimeUpdate(TimeAnimator animation,long deltaTime) {
                    if (!sendEvent(mDownTime + totalTime)) {
                        mTimeAnimator.end();
                    }
                }
            });
            mTimeAnimator.start();
        }
    };
}
项目:android-chromium    文件:GenericTouchGesture.java   
private Runnable createJBRunnable() {
    // On JB,long deltaTime) {
                    if (!sendEvent(mStartTime + totalTime)) {
                        mTimeAnimator.end();
                    }
                }
            });
            mTimeAnimator.start();
        }
    };
}
项目:chromium_webview    文件:GenericTouchGesture.java   
private Runnable createJBRunnable() {
    // On JB,long deltaTime) {
                    if (!sendEvent(mDownTime + totalTime)) {
                        mTimeAnimator.end();
                    }
                }
            });
            mTimeAnimator.start();
        }
    };
}
项目:cordova-android-chromium    文件:GenericTouchGesture.java   
private Runnable createJBRunnable() {
    // On JB,long deltaTime) {
                    if (!sendEvent(mStartTime + totalTime)) {
                        mTimeAnimator.end();
                    }
                }
            });
            mTimeAnimator.start();
        }
    };
}

android.animation.TimeAnimator的实例源码

android.animation.TimeAnimator的实例源码

项目:NoticeDog    文件:SpringTranslateTimeListener.java   
public void onTimeUpdate(TimeAnimator timeAnimator,long totalTime,long deltaTime) {
    if (!this.mStarted.booleanValue()) {
        this.mStarted = Boolean.valueOf(true);
        if (this.mAnimationListener != null) {
            this.mAnimationListener.onAnimationStart(null);
        }
    }
    if (timeAnimator.isRunning()) {
        if (isReallyClose().booleanValue()) {
            stepFast();
        } else {
            step();
        }
        if (isFinished().booleanValue() && this.mAnimationListener != null) {
            this.mAnimationListener.onAnimationEnd(null);
        }
    }
}
项目:NoticeDog    文件:PanelView.java   
void init() {
    this.handler = new Handler(Looper.getMainLooper());
    this.mAnimationCallback = new TimeListener() {
        public void onTimeUpdate(TimeAnimator animation,long deltaTime) {
            PanelView.this.animationTick(deltaTime);
        }
    };
    this.mStopAnimator = new Runnable() {
        public void run() {
            if (PanelView.this.mTimeAnimator != null && PanelView.this.mTimeAnimator.isstarted()) {
                PanelView.this.LOG("Stop Animator : stopping",new Object[0]);
                PanelView.this.mTimeAnimator.end();
                PanelView.this.mRubberbanding = false;
                PanelView.this.mClosing = false;
            }
        }
    };
    this.mTimeAnimator = new TimeAnimator();
    this.mTimeAnimator.setTimeListener(this.mAnimationCallback);
}
项目:chromium-for-android-56-debug-video    文件:ToolbarProgressBar.java   
@Override
public void onTimeUpdate(TimeAnimator animation,long totalTimeMs,long deltaTimeMs) {
    // Cap progress bar animation frame time so that it doesn't jump too much even when
    // the animation is janky.
    float progress = mAnimationLogic.updateProgress(mTargetProgress,Math.min(deltaTimeMs,PROGRESS_FRAME_TIME_CAP_MS) * 0.001f,getWidth());
    progress = Math.max(progress,0);
    ToolbarProgressBar.super.setProgress(progress);

    if (mAnimatingView != null) {
        int width = Math.abs(
                getDrawable().getBounds().right - getDrawable().getBounds().left);
        mAnimatingView.update(progress * width);
    }

    if (getProgress() == mTargetProgress) {
        if (!mIsstarted) postOnAnimationDelayed(mHideRunnable,mHidingDelayMs);
        mProgressAnimator.end();
        return;
    }
}
项目:AndroidChromium    文件:ToolbarProgressBar.java   
@Override
public void onTimeUpdate(TimeAnimator animation,mHidingDelayMs);
        mProgressAnimator.end();
        return;
    }
}
项目:Vafrinn    文件:ToolbarProgressBar.java   
@Override
public void onTimeUpdate(TimeAnimator animation,long deltaTimeMs) {
    // Cap progress bar animation frame time so that it doesn't jump too much even when
    // the animation is janky.
    ToolbarProgressBar.super.setProgress(mAnimationLogic.updateProgress(
            mTargetProgress,Math.max(deltaTimeMs,getWidth()));

    if (getProgress() == mTargetProgress) {
        if (mTargetProgress == 1.0f && !mIsstarted) {
            postOnAnimationDelayed(mHideRunnable,mHidingDelayMs);
        }
        mProgressAnimator.end();
        return;
    }
}
项目:365browser    文件:ToolbarProgressBar.java   
@Override
public void onTimeUpdate(TimeAnimator animation,mHidingDelayMs);
        mProgressAnimator.end();
        return;
    }
}
项目:android-chromium-view    文件:GenericTouchGesture.java   
private Runnable createJBRunnable() {
    // On JB,we rely on TimeAnimator to send events tied with vsync.
    return new Runnable() {
        @Override
        public void run() {
            mTimeAnimator = new TimeAnimator();
            mTimeAnimator.setTimeListener(new TimeListener() {
                @Override
                public void onTimeUpdate(TimeAnimator animation,long deltaTime) {
                    if (!sendEvent(mDownTime + totalTime)) {
                        mTimeAnimator.end();
                    }
                }
            });
            mTimeAnimator.start();
        }
    };
}
项目:android-chromium    文件:GenericTouchGesture.java   
private Runnable createJBRunnable() {
    // On JB,long deltaTime) {
                    if (!sendEvent(mStartTime + totalTime)) {
                        mTimeAnimator.end();
                    }
                }
            });
            mTimeAnimator.start();
        }
    };
}
项目:chromium_webview    文件:GenericTouchGesture.java   
private Runnable createJBRunnable() {
    // On JB,long deltaTime) {
                    if (!sendEvent(mDownTime + totalTime)) {
                        mTimeAnimator.end();
                    }
                }
            });
            mTimeAnimator.start();
        }
    };
}
项目:cordova-android-chromium    文件:GenericTouchGesture.java   
private Runnable createJBRunnable() {
    // On JB,long deltaTime) {
                    if (!sendEvent(mStartTime + totalTime)) {
                        mTimeAnimator.end();
                    }
                }
            });
            mTimeAnimator.start();
        }
    };
}
项目:chromium-net-for-android    文件:AnimationFrameTimeHistogram.java   
@Override
public void onTimeUpdate(TimeAnimator animation,long deltaTime) {
    if (mFrameTimesCount == mFrameTimesMs.length) {
        mAnimator.end();
        cleanUp();
        Log.w(TAG,"Animation frame time recording reached the maximum number. It's either"
                + "the animation took too long or recording end is not called.");
        return;
    }

    // deltaTime is 0 for the first frame.
    if (deltaTime > 0) {
        mFrameTimesMs[mFrameTimesCount++] = deltaTime;
    }
}
项目:NoticeDog    文件:LinearTranslateTimeListener.java   
public void onTimeUpdate(TimeAnimator timeAnimator,long deltaTime) {
    if (!timeAnimator.isRunning()) {
        return;
    }
    if (((float) totalTime) > this.mDuration) {
        timeAnimator.cancel();
        if (this.mAnimationListener != null) {
            this.mAnimationListener.onAnimationEnd(null);
            return;
        }
        return;
    }
    step((float) totalTime);
}
项目:chromium-for-android-56-debug-video    文件:AppMenuDragHelper.java   
AppMenuDragHelper(Activity activity,AppMenu appMenu,int itemRowHeight) {
    mActivity = activity;
    mAppMenu = appMenu;
    mItemRowHeight = itemRowHeight;
    Resources res = mActivity.getResources();
    mAutoScrollFullVeLocity = res.getDimensionPixelSize(R.dimen.auto_scroll_full_veLocity);
    // If user is dragging and the popup ListView is too big to display at once,// mDragScrolling animator scrolls mPopup.getListView() automatically depending on
    // the user's touch position.
    mDragScrolling.setTimeListener(new TimeAnimator.TimeListener() {
        @Override
        public void onTimeUpdate(TimeAnimator animation,long deltaTime) {
            ListPopupWindow popup = mAppMenu.getPopup();
            if (popup == null || popup.getListView() == null) return;

            // We keep both mDragScrollOffset and mDragScrollOffsetRounded because
            // the actual scrolling is by the rounded value but at the same time we also
            // want to keep the precise scroll value in float.
            mDragScrollOffset += (deltaTime * 0.001f) * mDragScrollingVeLocity;
            int diff = Math.round(mDragScrollOffset - mDragScrollOffsetRounded);
            mDragScrollOffsetRounded += diff;
            popup.getListView().smoothScrollBy(diff,0);

            // Force touch move event to highlight items correctly for the scrolled position.
            if (!Float.isNaN(mLastTouchX) && !Float.isNaN(mLastTouchY)) {
                menuItemAction(Math.round(mLastTouchX),Math.round(mLastTouchY),ITEM_ACTION_HIGHLIGHT);
            }
        }
    });

    // We use medium timeout,the average of tap and long press timeouts. This is consistent
    // with ListPopupWindow#ForwardingListener implementation.
    mTapTimeout =
            (ViewConfiguration.getTapTimeout() + ViewConfiguration.getLongPresstimeout()) / 2;
    mScaledTouchSlop = ViewConfiguration.get(activity).getScaledTouchSlop();
}
项目:xDrip    文件:XDripDreamService.java   
/**
 * Every TimeAnimator frame,nudge each bouncing view along.
 */
public void onTimeUpdate(TimeAnimator animation,long elapsed,long dt_ms) {
    final float dt = dt_ms / 1000f; // seconds
    for (int i = 0; i < getChildCount(); i++) {
        final View view = getChildAt(i);
        final PointF v = (PointF) view.getTag();

        // step view for veLocity * time
        view.setX(view.getX() + v.x * dt);
        view.setY(view.getY() + v.y * dt);

        // handle reflections
        final float l = view.getX();
        final float t = view.getY();
        final float r = l + view.getWidth();
        final float b = t + view.getHeight();
        boolean flipX = false,flipY = false;
        if (r > mWidth) {
            view.setX(view.getX() - 2 * (r - mWidth));
            flipX = true;
        } else if (l < 0) {
            view.setX(-l);
            flipX = true;
        }
        if (b > mHeight) {
            view.setY(view.getY() - 2 * (b - mHeight));
            flipY = true;
        } else if (t < 0) {
            view.setY(-t);
            flipY = true;
        }
        if (flipX) v.x *= -1;
        if (flipY) v.y *= -1;
    }
}
项目:xDrip-plus    文件:XDripDreamService.java   
/**
 * Every TimeAnimator frame,flipY = false;
        if (r > mWidth) {
            view.setX(view.getX() - 2 * (r - mWidth));
            flipX = true;
        } else if (l < 0) {
            view.setX(-l);
            flipX = true;
        }
        if (b > mHeight) {
            view.setY(view.getY() - 2 * (b - mHeight));
            flipY = true;
        } else if (t < 0) {
            view.setY(-t);
            flipY = true;
        }
        if (flipX) v.x *= -1;
        if (flipY) v.y *= -1;
    }
}
项目:AndroidChromium    文件:AppMenuDragHelper.java   
AppMenuDragHelper(Activity activity,the average of tap and long press timeouts. This is consistent
    // with ListPopupWindow#ForwardingListener implementation.
    mTapTimeout =
            (ViewConfiguration.getTapTimeout() + ViewConfiguration.getLongPresstimeout()) / 2;
    mScaledTouchSlop = ViewConfiguration.get(activity).getScaledTouchSlop();
}
项目:Vafrinn    文件:AppMenuDragHelper.java   
AppMenuDragHelper(Activity activity,the average of tap and long press timeouts. This is consistent
    // with ListPopupWindow#ForwardingListener implementation.
    mTapTimeout =
            (ViewConfiguration.getTapTimeout() + ViewConfiguration.getLongPresstimeout()) / 2;
    mScaledTouchSlop = ViewConfiguration.get(activity).getScaledTouchSlop();
}
项目:androidtv-daydream    文件:Bouncer.java   
public void onTimeUpdate(TimeAnimator animation,long dt_ms) {
    final float dt = dt_ms / 1000f; // seconds
    for (int i=0; i<getChildCount(); i++) {
        final View view = getChildAt(i);
        final PointF v = (PointF) view.getTag();

        // step view for veLocity * time
        view.setX(view.getX() + v.x * dt);
        view.setY(view.getY() + v.y * dt);

        // handle reflections
        final float l = view.getX();
        final float t = view.getY();
        final float r = l + view.getWidth();
        final float b = t + view.getHeight();
        boolean flipX = false,flipY = false;
        if (r > mWidth) {
            view.setX(view.getX() - 2 * (r - mWidth));
            flipX = true;
        } else if (l < 0) {
            view.setX(-l);
            flipX = true;
        }
        if (b > mHeight) {
            view.setY(view.getY() - 2 * (b - mHeight));
            flipY = true;
        } else if (t < 0) {
            view.setY(-t);
            flipY = true;
        }
        if (flipX) v.x *= -1;
        if (flipY) v.y *= -1;
    }
}
项目:365browser    文件:AnimationFrameTimeHistogram.java   
@Override
public void onTimeUpdate(TimeAnimator animation,"Animation frame time recording reached the maximum number. It's either"
                + "the animation took too long or recording end is not called.");
        return;
    }

    // deltaTime is 0 for the first frame.
    if (deltaTime > 0) {
        mFrameTimesMs[mFrameTimesCount++] = deltaTime;
    }
}
项目:365browser    文件:AppMenuDragHelper.java   
AppMenuDragHelper(Activity activity,the average of tap and long press timeouts. This is consistent
    // with ListPopupWindow#ForwardingListener implementation.
    mTapTimeout =
            (ViewConfiguration.getTapTimeout() + ViewConfiguration.getLongPresstimeout()) / 2;
    mScaledTouchSlop = ViewConfiguration.get(activity).getScaledTouchSlop();
}
项目:Bugstick    文件:BugView.java   
private void init(Context context) {
    animator = new TimeAnimator();
    animator.setTimeListener(this);

    paint = new Paint();
    paint.setColor(Color.WHITE);

    density = getResources().getdisplayMetrics().density;

    path = new Path();
    pathMeasure = new PathMeasure();
    position = new PointF();
    veLocity = new PointF();
}
项目:adt-leanback-support    文件:FocusHighlightHelper.java   
@Override
public void onTimeUpdate(TimeAnimator animation,long deltaTime) {
    float fraction;
    if (totalTime >= mDuration) {
        fraction = 1;
        mAnimator.end();
    } else {
        fraction = (float) (totalTime / (double) mDuration);
    }
    if (mInterpolator != null) {
        fraction = mInterpolator.getInterpolation(fraction);
    }
    setFocusLevel(mFocusLevelStart + fraction * mFocusLevelDelta);
}
项目:android-MorphClock    文件:SystemClockManager.java   
public SystemClockManager(SystemClockListener listener,long resolution) {
    mListener = listener;
    mResolution = resolution;

    mAnimator = new TimeAnimator();
    mAnimator.setTimeListener(this);
}
项目:android-MorphClock    文件:SystemClockManager.java   
@Override
public void onTimeUpdate(TimeAnimator timeAnimator,long l,long l2) {
    long Now = l / mResolution;
    if (Now != mLast) {
        mLast = Now;
        mListener.onTimeChanged(System.currentTimeMillis());
    }
}
项目:cogitolearning-examples    文件:FpsTimeListener.java   
public void onTimeUpdate(TimeAnimator animation,long deltaTime)
{

  double currentFps;
  if (deltaTime != 0)
    currentFps = 1000.0 / (double) deltaTime;
  else
    currentFps = 0.9 * fps;
  if (fps < 0.0)
    fps = currentFps;
  else
    fps = 0.9 * fps + 0.1 * currentFps;
  textView.setText(String.format("fps: %.2f",fps));
}
项目:cogitolearning-examples    文件:PropertyAnimation09.java   
@Override
@SuppressLint("NewApi")
protected void onCreate(Bundle savedInstanceState)
{
  super.onCreate(savedInstanceState);
  setContentView(R.layout.property_animations09);

  if (android.os.Build.VERSION.SDK_INT >= 19)
  {
    ImageView someImage = (ImageView) findViewById(R.id.some_image);

    ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(someImage,"rotation",360);
    rotateAnim.setDuration(1000);
    rotateAnim.setRepeatCount(5);
    rotateAnim.setRepeatMode(ObjectAnimator.RESTART);

    fpsText = (TextView) findViewById(R.id.fps_text);
    FpsTimeListener listener = new FpsTimeListener(fpsText);

    final TimeAnimator timeAnim = new TimeAnimator();
    timeAnim.setTimeListener(listener);

    anim = new AnimatorSet();
    anim.play(rotateAnim).with(timeAnim);
    rotateAnim.addListener(new AnimatorListenerAdapter()
    {
      @Override
      public void onAnimationEnd(Animator animation)
      {
        timeAnim.end(); 
      }
    });
  }
}
项目:NoticeDog    文件:PanelView.java   
private void animationTick(long dtms) {
    boolean z = true;
    if (!this.mTimeAnimator.isstarted()) {
        this.mTimeAnimator = new TimeAnimator();
        this.mTimeAnimator.setTimeListener(this.mAnimationCallback);
        if (this.mPeekAnimator != null) {
            this.mPeekAnimator.cancel();
        }
        this.mTimeAnimator.start();
        boolean z2 = this.mRubberbandingEnabled && this.mExpandedHeight > getFullHeight() && this.mVel >= (-this.mFlingGestureMindistPx);
        this.mRubberbanding = z2;
        if (this.mRubberbanding) {
            this.mClosing = true;
        } else if (this.mVel == 0.0f) {
            if (this.mFinalTouchY / getFullHeight() >= 0.5f) {
                z = false;
            }
            this.mClosing = z;
        } else {
            if (this.mExpandedHeight <= 0.0f || this.mVel >= 0.0f) {
                z = false;
            }
            this.mClosing = z;
        }
    } else if (dtms > 0) {
        float dt = ((float) dtms) * 0.001f;
        float fh = getFullHeight();
        this.mAccel = this.mClosing ? -this.mCollapseAccelPx : this.mExpandAccelPx;
        this.mVel += this.mAccel * dt;
        if (false) {
            if (this.mClosing && this.mVel > (-this.mBrakingSpeedPx)) {
                this.mVel = -this.mBrakingSpeedPx;
            } else if (!this.mClosing && this.mVel < this.mBrakingSpeedPx) {
                this.mVel = this.mBrakingSpeedPx;
            }
        } else if (this.mClosing && this.mVel > (-this.mFlingCollapseMinVeLocityPx)) {
            this.mVel = -this.mFlingCollapseMinVeLocityPx;
        } else if (!this.mClosing && this.mVel > this.mFlingGestureMaxOutputVeLocityPx) {
            this.mVel = this.mFlingGestureMaxOutputVeLocityPx;
        }
        float h = this.mExpandedHeight + (this.mVel * dt);
        if (this.mRubberbanding && h < fh) {
            h = fh;
        }
        setExpandedHeightInternal(h);
        this.mBar.panelExpansionChanged(this,this.mExpandedFraction);
        if (this.mVel == 0.0f || ((this.mClosing && getTargetExpandedHeight() == 0) || ((this.mRubberbanding || !this.mClosing) && this.mExpandedHeight == fh))) {
            this.handler.post(this.mStopAnimator);
            if (this.mClosing && getTargetExpandedHeight() == 0) {
                this.handler.post(this.closePanelsRunnable);
            }
        }
    } else {
        Log.v(TAG,"animationTick called with dtms=" + dtms + "; nothing to do (h=" + this.mExpandedHeight + " v=" + this.mVel + ")");
    }
}
项目:xDrip    文件:XDripDreamService.java   
public Bouncer(Context context,AttributeSet attrs,int flags) {
    super(context,attrs,flags);
    mAnimator = new TimeAnimator();
    mAnimator.setTimeListener(this);
}
项目:xDrip-plus    文件:XDripDreamService.java   
public Bouncer(Context context,flags);
    mAnimator = new TimeAnimator();
    mAnimator.setTimeListener(this);
}
项目:androidtv-daydream    文件:Bouncer.java   
public Bouncer(Context context,flags);
    mAnimator = new TimeAnimator();
    mAnimator.setTimeListener(this);
}
项目:adt-leanback-support    文件:RowsSupportFragment.java   
@Override
public void onTimeUpdate(TimeAnimator animation,long deltaTime) {
    if (mSelectAnimator.isRunning()) {
        updateSelect(totalTime,deltaTime);
    }
}
项目:adt-leanback-support    文件:RowsFragment.java   
@Override
public void onTimeUpdate(TimeAnimator animation,deltaTime);
    }
}
项目:Bugstick    文件:BugView.java   
@Override
public void onTimeUpdate(TimeAnimator animation,long deltaTime) {
    final float dt = deltaTime / 1000f; // seconds

    position.x += veLocity.x * dt;
    position.y += veLocity.y * dt;

    bound();

    path.lineto(position.x,position.y);

    invalidate();
}
项目:DemoForPropertyAnimation    文件:TimeDrawView.java   
@Override
public void onTimeUpdate(TimeAnimator animation,long deltaTime) { 

        invalidate();

}

Android进程启动与Activity显示

Android进程启动与Activity显示

前言

这段时间,leader安排的任务进行Android插件化,热修复相关的调研,对于插件化和热修复涉及到的核心技术点,在于对于类装载,资源装载的认识还有对于启动流程的熟悉,带着该任务,于是有了接下来,一系列的文章,从进程启动,Activity显示,Dex装载,资源装载,最后主流几个插件化,热修复源码实现的分析。本篇先从进程的启动,到一个Activity的显示流程出发分析。

启动一个进程

在Anroid中,进程是一个运行组件的容器,系统运行一个组件的时候,启动包含它的进程,当组件不再使用,进程会被关闭。AMS负责对应应用进程的启动。

开启一个新的进程,在AMS中首先调用addAppLocked

final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
        String abiOverride) {
    ProcessRecord app;
    if (!isolated) {
        //从已经开启记录下的进程中查找进程记录
        app = getProcessRecordLocked(info.processName, info.uid, true);
    } else {
        app = null;
    }
    //app为空的时候,创建一个新的进程,同时更新内部进程管理结构
    if (app == null) {
        app = newProcessRecordLocked(info, null, isolated, 0);
        updateLruProcessLocked(app, false, null);
        updateOomAdjLocked();
    }

    .....
    if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
        app.persistent = true;
        app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
    }
    if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
        mPersistentStartingProcesses.add(app);
      //调用进程的启动方法,启动一个新的进程
        startProcessLocked(app, "added application", app.processName, abiOverride,
                null /* entryPoint */, null /* entryPointArgs */);
    }

    return app;
}

首先会从已经启动的进程中查找相应的进程信息,ProcessRecord,如果不存在则会创建一个出来,然后调用startProcessLocked 方法,来开启一个新的进程。


private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    //启动应用
    ....
    Process.ProcessStartResult startResult = Process.start(entryPoint,
            app.processName, uid, uid, gids, debugFlags, mountExternal,
            app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
            app.info.dataDir, entryPointArgs);
      ....
  //发送定时消息,如果App的启动超时,则会ANR
    synchronized (mPidsSelfLocked) {
        this.mPidsSelfLocked.put(startResult.pid, app);
        if (isActivityProcess) {
            Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
            msg.obj = app;
            mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                    ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
        }
    }
    ....

}

进程的开启调用的是Process的start方法。

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
      
    }
}

start方法中,通过调用startViaZygote,通过zygote进程来开启一个新的进程。

private static ProcessStartResult startViaZygote(final String processClass, ...){

    //配置通过Zygote启动的参数,最终通过socket写入到Zygote进程,来开启一个新的进程

}

方法的具体执行是通过socket将进程的启动信息,写入到zygote中,然后通过其启动一个新的进程,同时对于该进程,也指定了一个类作为执行的入口类,这个类就是ActivityThread。

entryPoint = "android.app.ActivityThread";

start方法中的entryPoint,这个就是进程启动后要执行的Java类,进程启动后,所有操作就转交到ActivityThread的执行,因此,这个类也是整个应用执行的核心。这个类首先被执行的是其main函数。

image.png

public static void main(String[] args) {
      ...
      Looper.prepareMainLooper();
     ActivityThread thread = new ActivityThread();
    thread.attach(false);
     Looper.loop();
    ....
}

ActivityThread的attach方法。

private void attach(boolean system) {
      ......
final IActivityManager mgr = ActivityManagerNative.getDefault();
    try {
        //调用AMS的attachApplication方法,传递ApplicationThread进去
        mgr.attachApplication(mAppThread);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
      .....
}

Ams的attachApplication方法会调用到Ams的attachApplicationLocked方法,

thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,...)

这个方法的主要功能是创建出应用程序中的各种对象,是比较核心的方法。

private void handleBindApplication(AppBindData data) {
    // 注册当前UI线程到Runtime作为一个敏感线程
    VMRuntime.registerSensitiveThread();

    // 设置进程的启动时间
    Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());

    // 创建进程的配置对象
    mBoundApplication = data;
    mConfiguration = new Configuration(data.config);
    mCompatConfiguration = new Configuration(data.config);


    //当版本低于Honeycomb MR1,将AsyncTask的实现通过使用线程池
    if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
        AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    //设置应用的时区和应用的地区
    TimeZone.setDefault(null);
    LocaleList.setDefault(data.config.getLocales());

    synchronized (mResourcesManager) {
        mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
        mCurDefaultDisplayDpi = data.config.densityDpi;
        applyCompatConfiguration(mCurDefaultDisplayDpi);
    }


    // 创建Instrumentation
    final InstrumentationInfo ii;
    if (data.instrumentationName != null) {
        try {
            ii = new ApplicationPackageManager(null, getPackageManager())
                    .getInstrumentationInfo(data.instrumentationName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(
                    "Unable to find instrumentation info for: " + data.instrumentationName);
        }

        mInstrumentationPackageName = ii.packageName;
        mInstrumentationAppDir = ii.sourceDir;
        mInstrumentationSplitAppDirs = ii.splitSourceDirs;
        mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);
        mInstrumentedAppDir = data.info.getAppDir();
        mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
        mInstrumentedLibDir = data.info.getLibDir();
    } else {
        ii = null;
    }

    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
    updateLocaleListFromAppContext(appContext,
            mResourcesManager.getConfiguration().getLocales());


    // Continue loading instrumentation.
    if (ii != null) {
        final ApplicationInfo instrApp = new ApplicationInfo();
        ii.copyTo(instrApp);
        instrApp.initForUser(UserHandle.myUserId());
        final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                appContext.getClassLoader(), false, true, false);
        final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
        //
        try {
            final ClassLoader cl = instrContext.getClassLoader();
            mInstrumentation = (Instrumentation)
                cl.loadClass(data.instrumentationName.getClassName()).newInstance();
        } catch (Exception e) {
            throw new RuntimeException(
                "Unable to instantiate instrumentation "
                + data.instrumentationName + ": " + e.toString(), e);
        }

        final ComponentName component = new ComponentName(ii.packageName, ii.name);
        mInstrumentation.init(this, instrContext, appContext, component,
                data.instrumentationWatcher, data.instrumentationUiAutomationConnection);

        if (mProfiler.profileFile != null && !ii.handleProfiling
                && mProfiler.profileFd == null) {
            mProfiler.handlingProfiling = true;
            final File file = new File(mProfiler.profileFile);
            file.getParentFile().mkdirs();
            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
        }
    } else {
        mInstrumentation = new Instrumentation();
    }


    //Application中指定了big heap,清除限制
    if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
        dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
    } else {
        dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
    }


    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
    try {
        //生成Application对象
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;
            .....

        try {
            //调用Instrumentation的onCreate方法
            mInstrumentation.onCreate(data.instrumentationArgs);
        }
        catch (Exception e) {
            
        }

        try {
            //调用Application的onCreate方法
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
           
        }
    } finally {
        StrictMode.setThreadPolicy(savedPolicy);
    }
}

至此一个应用进程被打开,同时其Instrumentation和Application的onCreate方法也被调用了,接下来就是Activity的执行。

ActivityThread mian函数执行

Activity启动到显示

从上面的进程启动可以得知每一个进程对应一个Application,对应一个ActivityThread,也对应这一个Instrumentation。对于Activity的启动会调用到其handleLaunchActivity方法。

handleLaunchActivity

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ....
     WindowManagerGlobal.initialize();
     Activity a = performLaunchActivity(r, customIntent);
     if (a != null) {
         handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed,             r.lastProcessedSeq, reason);
                    ...
     } else {
        ActivityManagerNative.getDefault()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
    }
}

该方法首先对WindowManagerGlobal做了初始化操作,然后调用了performLaunchActivity方法,返回一个Activity对象后,返回对象伪非空,则调用handleResumeActivity。如果为空调用ActivityManager的finishActivity方法。对于启动,这里performLaunchActivityhandleResumeActivity两个方法是核心。接下来将针对这两个方法来进行分析。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

   //获取该Activity的包信息,这里为LoadedApk类型
   ActivityInfo aInfo = r.activityInfo;
   if (r.packageInfo == null) {
       r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
   }
        ...
      //创建Activity实例
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    activity = mInstrumentation.newActivity(    
    cl, component.getClassName(), r.intent);
    //获取Application实例
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);

   //创建窗口实例,并调用activity的attch方法,attach该窗口    
    Window window = null;
    if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
       window = r.mPendingRemoveWindow;
       r.mPendingRemoveWindow = null;
       r.mPendingRemoveWindowManager = null;
     }

     activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);

                    ....
     //为Activity设置主题
    int theme = r.activityInfo.getThemeResource();
    if (theme != 0) {
         activity.setTheme(theme);
     }
     ....
   //调用该Activity的onCreate方法
    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    ....
    mActivities.put(r.token, r);
    ...
}

首先根据Activity的信息来获取相关的包信息,这里调用了getPackInfo来获得相关的包信息。得到一个LoadedApk类型来表示当前的Activity的包信息。

public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
            int flags) {
    return getPackageInfo(packageName, compatInfo, flags, UserHandle.myUserId());
}

其中包含了Activity相关的信息Application信息,资源目录等等。在获得了LoadedApk实例之后,调用其makApplication方法,我们会疑问,在启动一个Activity的时候,难道每次都要创建一个Application对象吗?跟进源码。

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
  if (mApplication != null) {
      return mApplication;
  }
    ....
 //创建Application实例
  java.lang.ClassLoader cl = getClassLoader();
  if (!mPackageName.equals("android")) {
       initializeJavaContextClassLoader();
   }
   ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
   app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
   appContext.setOuterContext(app);

   mActivityThread.mAllApplications.add(app);
   mApplication = app;
    //调用Application的onCreate方法
   instrumentation.callApplicationOnCreate(app);
}

通过makeApplication的方法实现,我们可以看到其首先判断Application对象是否创建,如果没有创建,则初始化类装载器,然后创建Application对象,创建完成,则调用Application对象的onCreate方法。这里也就是我们所熟知的在我们自定义Application的时候重写的onCreate方法将会被调用。
继续回到上面代码的分析,这里的Activity通过类装载器被装载出来,然后实例化出一个对象,然后调用了其attach方法,进行了一系列信息的配置。然后调用了mInstrumentation,调用了callActivityOnCreate。同时也会将我们的Activity添加到mActivitys中,这里其定义如下。

final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();

通过这段代码可以看到,调用了acticity的attach方法,跟进attach方法。

final void attach(Context context, ....,Window window) {
     mWindow = new PhoneWindow(this, window);
     mWindow.setWindowControllerCallback(this);
     mWindow.setCallback(this);
     mWindow.setOnWindowDismissedCallback(this);
       
        .....
     mWindow.setWindowManager(                    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
          .....);
       .....
    mWindowManager = mWindow.getWindowManager();
}

至此,我们Activity中的Window已经被创建出来了。Window实际类型为PhoneWindow。同时为该Window设置了WindowManager。至此,我们虽然不了解Window是个什么东西,但是至少,我们可以知道的一点就是每一个Activity的创建是会有持有一个Window对象的。然后Instrumentation的callActivityOnCreate方法被调用。

callActivityOnCreate

public void callActivityOnCreate(Activity activity, Bundle icicle) {
    prePerformCreate(activity);
    activity.performCreate(icicle);
    postPerformCreate(activity);
}

这里对于Activity的具体启动细节,我们不做关心,具体细节,接下来的源码分析会做介绍,这里先看一下Activity的performCreate方法。

final void performCreate(Bundle icicle) {
   restoreHasCurrentPermissionRequest(icicle);
   onCreate(icicle);
   mActivityTransitionState.readState(icicle);
   performCreateCommon();
}

这个时候调用了Activity的performCreate函数,调用了Activity的onCreate,我们一般会在onCreate中调用setContentView,进行我们布局文件的设置。这也是比较奇怪的一点,为什么,我们调用了该方法,传递一个xml布局文件,我们的View就显示出来了呢?这便是这次代码分析的核心,所有围绕的相关知识点也会在此被引出。接下来,让我们剥茧抽丝,逐层递进。

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

此处的Window即为在attach中得到的PhoneWindow的实例。

public void setContentView(int layoutResID) {
    if (mContentParent  ==  null) {
          installDecor();
       } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
          mContentParent.removeAllViews();
       }
    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
          final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
          transitionTo(newScene);
      } else {
         mLayoutInflater.inflate(layoutResID, mContentParent);
    }
        ...
}

首先判断mContentParent是否为空,mContentParent是用来放置contentView的,如果不为空则要清理掉所有的view,如果为null,调用installDecor(),其中,我们可以看到有调用对于transitions这个feature的判断,这个是在Android系统5.0之后添加的一个功能,可以用来实现Activity的过渡,同时还是实现Activity之间的元素共享,使得Activity间切换更加的丝滑流畅。这里对于该场景不做分析,我们跳过看其具体的View装载,然后调用了

mLayoutInflater.inflate(layoutResID, mContentParent);

private void installDecor() {
    mDecor = generateDecor(-1);
    ....
    mContentParent = generateLayout(mDecor);
    ...
     //过渡动画,标题,logo,UI选项的显示处理
}

在installDecor中,首先调用了generateDecor方法,然后根据创建的DecorView,来生成ContentView。

protected DecorView generateDecor(int featureId) {
    Context context;
    if (mUseDecorContext) {
        Context applicationContext = getContext().getApplicationContext();
          if (applicationContext == null) {
              context = getContext();
          } else {
            context = new DecorContext(applicationContext, getContext().getResources());
             if (mTheme != -1) {
                context.setTheme(mTheme);
             }
         }
     } else {
         context = getContext();
    }
     return new DecorView(context, featureId, this, getAttributes());
    }

根据是否使用DecorContext来创建相应的context,然后利用该Context来创建DecorView。那么这个DecorView到底是个什么呢?

public class DecorView extends FrameLayout

DecorView其实就是一个FrameLayout。这个FrameLayout则是我们所看到的Activity试图的根View,在创建了一个DecorView之后,又根据这个DecorView实例来创建了ContentView。

这里创建的DecorView其实是一个FrameLayout,

由上面函数可以看出,mContentParent是和mDecor有关的,下面来看一下ContentParent的创建过程。

protected ViewGroup generateLayout(DecorView decor) {
...    
//根据样式,选择相应的资源文件,进行相应的资源装载
    mDecor.startChanging();
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    ...
        return contentParent;
}

开始之前调用了DecorView的onResourcesLoaded,然后通过findViewById的方式,返回一个VieGroup作为contentParent。这里的findViewById的实现在基类Window中。

public View findViewById(@IdRes int id) {
   return getDecorView().findViewById(id);
}

onResourcesLoaded的方法如下。

void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
    ....
    mDecorCaptionView = createDecorCaptionView(inflater);
    final View root = inflater.inflate(layoutResource, null);
    if (mDecorCaptionView != null) {
         if (mDecorCaptionView.getParent() == null) {
             addView(mDecorCaptionView,
                        new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
         }
         mDecorCaptionView.addView(root,
                    new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
        } else {
          addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
    mContentRoot = (ViewGroup) root;
    initializeElevation();
}

根据相应的UI样式配置,选择合适的布局资源文件,然后通过inflate装载相应的资源文件,创建ContentView,同时将其添加到DecorView中。
在创建了DecorView和ContentParent之后,接下来,则利用了我们传递的xml布局文件id。

mLayoutInflater.inflate(layoutResID, mContentParent);

LayoutInflater中inflate的实现如下

 public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
     return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    final Resources res = getContext().getResources();
       
    final XmlResourceParser parser = res.getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
   ....
   final View temp = createViewFromTag(root, name, inflaterContext, attrs);
   ....
   if (root != null && attachToRoot) {
      root.addView(temp, params);
   }
   ...
}

根据我们的布局文件ID,创建出一个View,然后将该View添加到我们的contentView之中。在setContentView中,当我们结束了instalDecor方法之后,会调用initWindowDecorActionBar来进行ActionBar的初始化操作,创建ActionBar。

private void initWindowDecorActionBar() {
     Window window = getWindow();
     window.getDecorView();
     if (isChild() || !window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) {
         return;
     }
    mActionBar = new WindowDecorActionBar(this);
    mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
    mWindow.setDefaultIcon(mActivityInfo.getIconResource());
    mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
}

handleResumeActivity

通过performLaunchActivity,我们已经装载出了资源,同时创建了DecorView和contentParentView,同时也完成了Window的创建,同时也将我们设置的资源文件,装载出来成为了View。但是我们知道一个Activity可见时,我们的onResume方法是被调用的了,在performLaunchActivity被调用之后又调用了handleResumeActivity()

final void handleResumeActivity(IBinder token,
            boolean clearHide, ....) {
   ActivityClientRecord r = mActivities.get(token);
    ...
   r = performResumeActivity(token, clearHide, reason);
   if (r.window == null && !a.mFinished && willBeVisible) {
      r.window = r.activity.getWindow();
      View decor = r.window.getDecorView();
      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 (r.mPreserveWindow) {
         a.mWindowAdded = true;
         r.mPreserveWindow = false;
         ViewRootImpl impl = decor.getViewRootImpl();
         if (impl != null) {
             impl.notifyChildRebuilt();
         }
      }
      if (a.mVisibleFromClient && !a.mWindowAdded) {
         a.mWindowAdded = true;
         wm.addView(decor, l);
      }
}

该方法首先调用了performResumeActivity函数。performResumeActivity中进行了大量的状态相关的判断,而对于首次启动的分析,我们所关心的核心就是其调用了Activity的performResume,也就是Activity的onResume函数被调用了。

public final ActivityClientRecord performResumeActivity(IBinder token,boolean clearHide, String reason) {
    ...
    r.activity.performResume();
    ...
}

最开始调用了Activity的Resume 函数,然后进行了后续的调用。这里看到一个ViewRootImpl中,通过decor调用getViewRootImpl()来获得

public ViewRootImpl getViewRootImpl() {
   if (mAttachInfo != null)  {
      return mAttachInfo.mViewRootImpl;
   }
    return null;
}

该方法中核心代码为

wm.addView(decor, l);

调用了WindowManager的addView方法,来添加当前的DecorView。

 @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
     ....
    ViewRootImpl root;
    View panelParentView = null;
     ....
     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
     root.setView(view, wparams, panelParentView);
}

在WindowManager中的addView调用了WindowManagerGlobal的addView方法,在最开始的时候,我们调用过

WindowManagerGlobal.initialize();

WindowManagerGlobal是个单例类,其保证了对于整个应用层,只具备一个WindowManagerService。同时其具备三个ArryList,分别保存一个应用的根View,ViewRootImpl和LayoutParams,该方法,创建了一个ViewRootImpl实例,然后将View,ViewRoot,LayoutParams添加到相应的ArrayList中,最后调用ViewRoot的setView方法。这里的setView方法会将其设置为自身的View,以后的绘制等事件都交给ViewRootImpl来实现。绘制涉及到布局,测量,绘制三个环节,具体的过程此处不再展开,本篇主要目的是为了接下来的插件化和热修复做一个基础。

总结

View创建流程

至此,我们已经知道了从一个Activity的启动到我们的View逐步被创建的过程,但是这里并没有涉及到绘制相关的内容,那么这个View最终如何绘制出来的呢?接下来,我们首先从ViewRootImpl来切入做分析,逐步理清楚接下来做的事情。

今天的关于路径运动与anime.js路径运动和定位运动的分享已经结束,谢谢您的关注,如果想了解更多关于Android ScaleAnimation和TranslateAnimation,如何避免ScaleAnimation运动、android.animation.TimeAnimator.TimeListener的实例源码、android.animation.TimeAnimator的实例源码、Android进程启动与Activity显示的相关知识,请在本站进行查询。

本文标签: