返回介绍

2.1. TN

发布于 2024-12-23 21:45:11 字数 6116 浏览 0 评论 0 收藏 0

TN 类继承自 ITransientNotification.Stub,ITransientNotification.aidl,用于进程间通信,源码位于 frameworks\base\core\java\android\app\ITransientNotification.aidl

  private static class TN extends ITransientNotification.Stub {
 
    final Runnable mShow = new Runnable() {
      @Override
      public void run() {
        //显示处理
        handleShow();
      }
    };

    final Runnable mHide = new Runnable() {
      @Override
      public void run() {
        //消失处理
        handleHide();
        // Don't do this in handleHide() because it is also invoked by handleShow()
        mNextView = null;
      }
    };
		//应用程序窗口
    private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
    final Handler mHandler = new Handler();  
		//出现在屏幕的位置
    int mGravity;
    //分别是出现在屏幕的 X、Y 方向偏移量
    int mX, mY;
    //横向 margin 值
    float mHorizontalMargin;
    //竖向 margin 值
    float mVerticalMargin;

		//当前 view
    View mView;
    //下个 Toast 显示的 view
    View mNextView;

    WindowManager mWM;
		//TN 构造函数
    TN() {
      // XXX This should be changed to use a Dialog, with a Theme.Toast
      // defined that sets up the layout params appropriately.
      final WindowManager.LayoutParams params = mParams;
      params.height = WindowManager.LayoutParams.WRAP_CONTENT;
      params.width = WindowManager.LayoutParams.WRAP_CONTENT;
      // 不设置这个弹出框的透明遮罩显示为黑色
			params.format = PixelFormat.TRANSLUCENT;
		  // 动画
      params.windowAnimations = com.android.internal.R.style.Animation_Toast;
      // 类型
			params.type = WindowManager.LayoutParams.TYPE_TOAST;
      params.setTitle("Toast");
      // 设置 flag
      params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
          | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
          | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    }

    /**
     * schedule handleShow into the right thread
     */
    @Override
    public void show() {
      if (localLOGV) Log.v(TAG, "SHOW: " + this);
      mHandler.post(mShow);
    }

    /**
     * schedule handleHide into the right thread
     */
    @Override
    public void hide() {
      if (localLOGV) Log.v(TAG, "HIDE: " + this);
      mHandler.post(mHide);
    }
    
		/**
		 * 显示 Toast
		 */
    public void handleShow() {
      if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
          + " mNextView=" + mNextView);
      //判断下个 view 是否一样
      if (mView != mNextView) {
        // remove the old view if necessary
        //移除当前 view
        handleHide();
        mView = mNextView;
        //获取当前 view 上下文
        Context context = mView.getContext().getApplicationContext();
        String packageName = mView.getContext().getOpPackageName();
        if (context == null) {
          context = mView.getContext();
        }
				//获得 WindowManager 对象
        mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        // We can resolve the Gravity here by using the Locale for getting
        // the layout direction
        final Configuration config = mView.getContext().getResources().getConfiguration();
				//获取绝对的 Gravity
        final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());
        mParams.gravity = gravity;
        if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
          mParams.horizontalWeight = 1.0f;
        }
        if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
          mParams.verticalWeight = 1.0f;
        }
        mParams.x = mX;
        mParams.y = mY;
        mParams.verticalMargin = mVerticalMargin;
        mParams.horizontalMargin = mHorizontalMargin;
        mParams.packageName = packageName;
        if (mView.getParent() != null) {
          if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
          //如果当前 view 存在,先移除
          mWM.removeView(mView);
        }
        if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
        //通过 WindowManager 调用 addView 加载
        mWM.addView(mView, mParams);
        trySendAccessibilityEvent();
      }
    }
		
    private void trySendAccessibilityEvent() {
      AccessibilityManager accessibilityManager =
          AccessibilityManager.getInstance(mView.getContext());
      if (!accessibilityManager.isEnabled()) {
        return;
      }
      // treat toasts as notifications since they are used to
      // announce a transient piece of information to the user
      AccessibilityEvent event = AccessibilityEvent.obtain(
          AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
      event.setClassName(getClass().getName());
      event.setPackageName(mView.getContext().getPackageName());
      mView.dispatchPopulateAccessibilityEvent(event);
      accessibilityManager.sendAccessibilityEvent(event);
    }
        
		/** 
		 * WindowManager 调用 removeView 方法来将 Toast 视图移除
		 */
    public void handleHide() {
      if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
      if (mView != null) {
        // note: checking parent() just to make sure the view has
        // been added...  i have seen cases where we get here when
        // the view isn't yet added, so let's try not to crash.
        if (mView.getParent() != null) {
          if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
          mWM.removeView(mView);
        }

        mView = null;
      }
    }
  }

来看下 ITransientNotification ,就两个方法,如下:

  /** @hide */
  oneway interface ITransientNotification {
    void show();
    void hide();
  }

具体实现就在 TN 类,其他进程回调 TN 类,来操作 Toast 的显示和消失:

  @Override
  public void show() {
    if (localLOGV) Log.v(TAG, "SHOW: " + this);
      //显示
      mHandler.post(mShow);
  }

  /**
   * schedule handleHide into the right thread
   */
  @Override
  public void hide() {
    if (localLOGV) Log.v(TAG, "HIDE: " + this);
    //消失
    mHandler.post(mHide);
  }

这里可以看出 Toast 显示和消失用的 Handler 机制实现的。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文