Android SystemUI组件(06)导航栏创建分析虚拟按键

该系列文章总纲链接:专题分纲目录 Android SystemUI组件


本章关键点总结 & 说明:

说明:本章节持续迭代之前章节的思维导图,主要关注左侧SystemBars分析中导航栏部分即可。

1 导航栏创建之makeStatusBarView

通过上一篇文章的分析,我们知道 addNavigationBar是在addStatusBarWindow之后执行的,addStatusBarWindow代码实现如下:

private void addStatusBarWindow() {makeStatusBarView();//创建statusbar视图mStatusBarWindowManager = new StatusBarWindowManager(mContext);mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}

addStatusBarWindow中makeStatusBarView也执行了导航栏相关逻辑,相关代码如下:

protected PhoneStatusBarView makeStatusBarView() {final Context context = mContext;//...try {//关键点1:导航栏显示与否boolean showNav = mWindowManagerService.hasNavigationBar();//是否显示导航栏if (showNav) {//关键点2:加载导航栏布局mNavigationBarView =(NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);mNavigationBarView.setDisabledFlags(mDisabled);mNavigationBarView.setBar(this);mNavigationBarView.setOnVerticalChangedListener(new NavigationBarView.OnVerticalChangedListener() {@Overridepublic void onVerticalChanged(boolean isVertical) {if (mSearchPanelView != null) {mSearchPanelView.setHorizontal(isVertical);}mNotificationPanel.setQsScrimEnabled(!isVertical);}});//设置导航栏触摸事件mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {checkUserAutohide(v, event);return false;}});}} catch (RemoteException ex) {// no window manager? good luck with that}//...startGlyphRasterizeHack();return mStatusBarView;
}

这里主要分析两个部分:navigationBar显示与否 和 导航栏Layout相关。

1.1 navigationBar显示与否

导航栏显示与否关键在于方法mWindowManagerService.hasNavigationBar的实现,这里最终是掉用到了PhoneWindowManager中的hasNavigationBar方法。代码如下所示:

public class PhoneWindowManager implements WindowManagerPolicy {//...public boolean hasNavigationBar() {return mHasNavigationBar;}//...
}

这里变量mHasNavigationBar的赋值操作为:

mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);

这里可以看到 导航栏的配置主要是在/res/res/values中名为config_showNavigationBar的标识,即为默认的配置,如下所示:

    <!-- Whether a software navigation bar should be shown. NOTE: in the future this may beautodetected from the Configuration. --><bool name="config_showNavigationBar">false</bool>

因此,这里可以根据需求修改该配置。

1.2 导航栏Layout相关

加载导航栏布局的语句为:

NavigationBarView = (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);

从布局文件(res\layout\navigation_bar.xml)中来来看,xml文件内容如下:

<com.android.systemui.statusbar.phone.NavigationBarViewxmlns:android="http://schemas.android.com/apk/res/android"xmlns:systemui="http://schemas.android.com/apk/res-auto"android:layout_height="match_parent"android:layout_width="match_parent"android:background="@drawable/system_bar_background"><!--横向导航栏--><FrameLayout android:id="@+id/rot0"android:layout_height="match_parent"android:layout_width="match_parent"><LinearLayoutandroid:layout_height="match_parent"android:layout_width="match_parent"android:orientation="horizontal"android:clipChildren="false"android:clipToPadding="false"android:id="@+id/nav_buttons"android:animateLayoutChanges="true"><!-- navigation controls --><Viewandroid:layout_width="@dimen/navigation_side_padding"android:layout_height="match_parent"android:layout_weight="0"android:visibility="invisible"/><!--back按钮--><com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"android:layout_width="@dimen/navigation_key_width"android:layout_height="match_parent"android:src="@drawable/ic_sysbar_back"systemui:keyCode="4"android:layout_weight="0"android:scaleType="center"android:contentDescription="@string/accessibility_back"/><View android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:visibility="invisible"/><!--home按钮--><com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"android:layout_width="@dimen/navigation_key_width"android:layout_height="match_parent"android:src="@drawable/ic_sysbar_home"systemui:keyCode="3"systemui:keyRepeat="false"android:layout_weight="0"android:scaleType="center"android:contentDescription="@string/accessibility_home"/><View android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:visibility="invisible"/><!--recent按钮--><com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"android:layout_width="@dimen/navigation_key_width"android:layout_height="match_parent"android:src="@drawable/ic_sysbar_recent"android:layout_weight="0"android:scaleType="center"android:contentDescription="@string/accessibility_recent"/><FrameLayoutandroid:layout_width="@dimen/navigation_side_padding"android:layout_height="match_parent"android:layout_weight="0" ><com.android.systemui.statusbar.policy.KeyButtonViewandroid:id="@+id/menu"android:layout_width="@dimen/navigation_extra_key_width"android:layout_height="match_parent"android:contentDescription="@string/accessibility_menu"android:src="@drawable/ic_sysbar_menu"android:visibility="invisible"android:scaleType="centerInside"android:layout_gravity="end"systemui:keyCode="82" /><com.android.systemui.statusbar.policy.KeyButtonViewandroid:id="@+id/ime_switcher"android:layout_width="@dimen/navigation_extra_key_width"android:layout_height="match_parent"android:contentDescription="@string/accessibility_ime_switch_button"android:scaleType="centerInside"android:src="@drawable/ic_ime_switcher_default"android:visibility="invisible"android:layout_gravity="end" /></FrameLayout></LinearLayout><!-- lights out layout to match exactly --><LinearLayoutandroid:layout_height="match_parent"android:layout_width="match_parent"android:orientation="horizontal"android:id="@+id/lights_out"android:visibility="gone"><ImageViewandroid:layout_width="@dimen/navigation_key_width"android:layout_height="match_parent"android:layout_marginStart="@dimen/navigation_side_padding"android:src="@drawable/ic_sysbar_lights_out_dot_small"android:scaleType="center"android:layout_weight="0"/><View android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:visibility="invisible"/><ImageViewandroid:layout_width="@dimen/navigation_key_width"android:layout_height="match_parent"android:src="@drawable/ic_sysbar_lights_out_dot_large"android:scaleType="center"android:layout_weight="0"/><View android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:visibility="invisible"/><ImageViewandroid:layout_width="@dimen/navigation_key_width"android:layout_marginEnd="@dimen/navigation_side_padding"android:layout_height="match_parent"android:src="@drawable/ic_sysbar_lights_out_dot_small"android:scaleType="center"android:layout_weight="0"/></LinearLayout><com.android.systemui.statusbar.policy.DeadZoneandroid:id="@+id/deadzone"android:layout_height="match_parent"android:layout_width="match_parent"systemui:minSize="@dimen/navigation_bar_deadzone_size"systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"systemui:holdTime="@integer/navigation_bar_deadzone_hold"systemui:decayTime="@integer/navigation_bar_deadzone_decay"systemui:orientation="horizontal"android:layout_gravity="top"/></FrameLayout><!--纵向显示--><FrameLayout android:id="@+id/rot90"android:layout_height="match_parent"android:layout_width="match_parent"android:visibility="gone"android:paddingTop="0dp"><LinearLayout android:layout_height="match_parent"android:layout_width="match_parent"android:orientation="vertical"android:clipChildren="false"android:clipToPadding="false"android:id="@+id/nav_buttons"android:animateLayoutChanges="true"><!-- navigation controls --><FrameLayoutandroid:layout_weight="0"android:layout_width="match_parent"android:layout_height="@dimen/navigation_side_padding" ><com.android.systemui.statusbar.policy.KeyButtonViewandroid:id="@+id/ime_switcher"android:layout_width="match_parent"android:layout_height="@dimen/navigation_extra_key_width"android:contentDescription="@string/accessibility_ime_switch_button"android:scaleType="centerInside"android:src="@drawable/ic_ime_switcher_default"android:layout_gravity="top"android:visibility="invisible" /><com.android.systemui.statusbar.policy.KeyButtonViewandroid:id="@+id/menu"android:layout_width="match_parent"android:layout_height="40dp"android:contentDescription="@string/accessibility_menu"android:src="@drawable/ic_sysbar_menu_land"android:scaleType="centerInside"android:layout_gravity="top"android:visibility="invisible"systemui:keyCode="82" /></FrameLayout><!--recent按钮--><com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"android:layout_height="@dimen/navigation_key_width"android:layout_width="match_parent"android:src="@drawable/ic_sysbar_recent_land"android:scaleType="center"android:layout_weight="0"android:contentDescription="@string/accessibility_recent"/><View android:layout_height="match_parent"android:layout_width="match_parent"android:layout_weight="1"android:visibility="invisible"/><!--home按钮--><com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"android:layout_height="@dimen/navigation_key_width"android:layout_width="match_parent"android:src="@drawable/ic_sysbar_home_land"android:scaleType="center"systemui:keyCode="3"systemui:keyRepeat="false"android:layout_weight="0"android:contentDescription="@string/accessibility_home"/><View android:layout_height="match_parent"android:layout_width="match_parent"android:layout_weight="1"android:visibility="invisible"/><!--back按钮--><com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"android:layout_height="@dimen/navigation_key_width"android:layout_width="match_parent"android:src="@drawable/ic_sysbar_back_land"android:scaleType="center"systemui:keyCode="4"android:layout_weight="0"android:contentDescription="@string/accessibility_back"/><Viewandroid:layout_height="@dimen/navigation_side_padding"android:layout_width="match_parent"android:layout_weight="0"android:visibility="invisible"/></LinearLayout><!-- lights out layout to match exactly --><LinearLayout android:layout_height="match_parent"android:layout_width="match_parent"android:orientation="vertical"android:id="@+id/lights_out"android:visibility="gone"><ImageViewandroid:layout_height="@dimen/navigation_key_width"android:layout_marginTop="@dimen/navigation_side_padding"android:layout_width="match_parent"android:src="@drawable/ic_sysbar_lights_out_dot_small"android:scaleType="center"android:layout_weight="0"/><View android:layout_height="match_parent"android:layout_width="match_parent"android:layout_weight="1"android:visibility="invisible"/><ImageViewandroid:layout_height="@dimen/navigation_key_width"android:layout_width="match_parent"android:src="@drawable/ic_sysbar_lights_out_dot_large"android:scaleType="center"android:layout_weight="0"/><View android:layout_height="match_parent"android:layout_width="match_parent"android:layout_weight="1"android:visibility="invisible"/><ImageViewandroid:layout_height="@dimen/navigation_key_width"android:layout_marginBottom="@dimen/navigation_side_padding"android:layout_width="match_parent"android:src="@drawable/ic_sysbar_lights_out_dot_small"android:scaleType="center"android:layout_weight="0"/></LinearLayout><com.android.systemui.statusbar.policy.DeadZoneandroid:id="@+id/deadzone"android:layout_height="match_parent"android:layout_width="match_parent"systemui:minSize="@dimen/navigation_bar_deadzone_size"systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"systemui:holdTime="@integer/navigation_bar_deadzone_hold"systemui:decayTime="@integer/navigation_bar_deadzone_decay"systemui:orientation="vertical"android:layout_gravity="top"/></FrameLayout></com.android.systemui.statusbar.phone.NavigationBarView>

可以看到,横向和纵向是加载两个不同的FrameLayout配置文件。由于文件过长,这里使用简图来描述,如下:

简单解读说明如下:

  • nav_buttons:4个控件,back,home,recent,menu。
  • lights_out:多数情况不可见,当处于低辨识度模式下,nav_buttons隐藏且lights_out显示,显示为三个不明显的小灰点,降低对用户视线的干扰。
  • search_light:多数情况不可见,当HOME按键被禁后serach功能还可用,此时会变成可见,用于提示用户该功能可使用。
  • deadzone:防止边界误触操作。

导航栏显示以及布局由屏幕的方向来决定,而导航栏有两种不同的显示方式,横向显示和竖向显示,同时 我从mRotatedViews变量 分析:

public class NavigationBarView extends LinearLayout {//...View[] mRotatedViews = new View[4];//...//布局加载完成后,会回调onFinishInflate方法@Overridepublic void onFinishInflate() {//屏幕方位0和180方向显示的导航栏为rot0,90和270显示的导航栏为rot90mRotatedViews[Surface.ROTATION_0] =mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];mCurrentView = mRotatedViews[Surface.ROTATION_0];getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);updateRTLOrder();}
}

这里也可以看到,在加载完xml文件后,会根据不同的旋转角度加载不同的layout布局文件。

2 导航栏创建之addNavigationBar 入口分析

addNavigationBar 代码实现如下:

// For small-screen devices (read: phones) that lack hardware navigation buttons
private void addNavigationBar() {if (mNavigationBarView == null) return;//关键点1prepareNavigationBarView();//关键点2: getNavigationBarLayoutParams分析mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
}

2.1 prepareNavigationBarView分析

继续分析prepareNavigationBarView,代码实现如下:

private void prepareNavigationBarView() {mNavigationBarView.reorient();//设置导航栏三个图标的点击事件mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);mNavigationBarView.getRecentsButton().setLongClickable(true);mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);mNavigationBarView.getBackButton().setLongClickable(true);mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);updateSearchPanel();
}

导航栏布局的明确显示在prepareNavigationBarView中的mNavigationBarView.reorient();来决定,我们查看reorient方法,代码实现如下:

public void reorient() {//获取屏幕旋转方向final int rot = mDisplay.getRotation();//隐藏导航栏布局for (int i=0; i<4; i++) {mRotatedViews[i].setVisibility(View.GONE);}//根据屏幕方向显示导航栏布局mCurrentView = mRotatedViews[rot];mCurrentView.setVisibility(View.VISIBLE);getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);//初始化导航栏的转换效果,这些效果可能包括动画和过渡。mBarTransitions.init(mVertical);//根据 mDisabledFlags 设置导航栏的禁用状态setDisabledFlags(mDisabledFlags, true /* force */);//设置菜单按钮的可见性setMenuVisibility(mShowMenu, true /* force */);//如果导航栏处于横屏/垂直模式,mDelegateHelper 对象交换 X 和 Y 坐标,以适应横屏布局。if (mDelegateHelper != null) {mDelegateHelper.setSwapXY(mVertical);}updateTaskSwitchHelper();setNavigationIconHints(mNavigationIconHints, true);
}

2.2 getNavigationBarLayoutParams分析

我们回到PhoneStatusBar的addNavigationBar继续分析最后一个导航栏的LayoutParameters,它决定了导航栏在窗体上的显示位置,getNavigationBarLayoutParams代码实现如下:

private WindowManager.LayoutParams getNavigationBarLayoutParams() {/*初始化参数说明如下:FLAG_TOUCHABLE_WHEN_WAKING:当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到事件FLAG_NOT_FOCUSABLE:不获取焦点FLAG_NOT_TOUCH_MODAL:即使该window在可获得焦点情况下,仍然把该window之外的任何event发送到该window之后的其他windowFLAG_WATCH_OUTSIDE_TOUCH:不接受事件,转发到其他windowFLAG_SPLIT_TOUCH:当window设置这个flag,window会接收来自window边界之外发送给其他window的点击事件,支持多点触控.当这个flag没有设置的时候,第一下点击则决定了哪个window会接收整个点击事件,直到手指拿开.当设置了这个flag,这每一个点击事件(不一定是第一个)都决定了那个window来接收剩下的点击事件,直到手指拿开.点击事件会被分开传递给多个window.*/WindowManager.LayoutParams lp = new WindowManager.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,0| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,PixelFormat.TRANSLUCENT);// this will allow the navbar to run in an overlay on devices that support thisif (ActivityManager.isHighEndGfx()) {//硬件加速参数lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;}lp.setTitle("NavigationBar");//窗口名称lp.windowAnimations = 0;//不设置窗口动画return lp;
}

上面的LayoutParames决定了导航栏在窗体的大小和显示的位置效果,当然这也是受父窗口影响的,当我们有变更导航栏的显示需求时就可以同各国修正LayoutParames参数来解决。

3 导航栏虚拟按键工作原理

虚拟按键是用来替代物理按键的,而这也是导航栏最重要的工作,输入子系统(IMS)中有一个关键的方法:injectInputEvent,即直接模拟物理按键上报输入事件,它是虚拟按键的实现基础。导航栏中的KeyButtonView就是该接口使用者之一,KeyButtonView中最重要的字段是mCode,用于指示其生成的按键事件的键值。

导航栏中有4个KeyButtonView,其中back、home、menu分别产生 KEY_BACK、KEY_HOME 、KEY_MENU 三种按键事件,recent不产生按键事件。

接下来关注KeyButtonView的两个部分:从触屏事件转换到按键事件、键盘事件发送。

3.1 从触屏事件转换到按键事件

这里从KeyButtonView的onTouchEvent()方法(该方法是触屏的回调方法)开始分析,代码实现如下:

public boolean onTouchEvent(MotionEvent ev) {final int action = ev.getAction();int x, y;switch (action) {//触屏事件-按下case MotionEvent.ACTION_DOWN://Log.d("KeyButtonView", "press");mDownTime = SystemClock.uptimeMillis();setPressed(true);//如果mCode被设置有值,则发送按键事件KeyEvent.ACTION_DOWNif (mCode != 0) {sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);} else {// Provide the same haptic feedback that the system offers for virtual keys.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);}if (mSupportsLongpress) {removeCallbacks(mCheckLongPress);postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());}break;//触屏事件-移动case MotionEvent.ACTION_MOVE:x = (int)ev.getX();y = (int)ev.getY();setPressed(x >= -mTouchSlop&& x < getWidth() + mTouchSlop&& y >= -mTouchSlop&& y < getHeight() + mTouchSlop);break;//触屏事件-取消case MotionEvent.ACTION_CANCEL:setPressed(false);//如果mCode被设置有值,则发送按键事件KeyEvent.ACTION_UP,带标记KeyEvent.FLAG_CANCELEDif (mCode != 0) {sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);}if (mSupportsLongpress) {removeCallbacks(mCheckLongPress);}break;//触屏事件-抬起case MotionEvent.ACTION_UP:final boolean doIt = isPressed();setPressed(false);//如果mCode被设置有值,则发送按键事件KeyEvent.ACTION_UPif (mCode != 0) {if (doIt) {sendEvent(KeyEvent.ACTION_UP, 0);sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);playSoundEffect(SoundEffectConstants.CLICK);} else {sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);}} else {//如果没设置,则此时触发OnClickListener//导航栏会采用这种方式来处理事件// no key code, just a regular ImageViewif (doIt) {performClick();}}if (mSupportsLongpress) {removeCallbacks(mCheckLongPress);}break;}return true;
}

整个过程就是 触摸事件转换成按键事件的一个过程。

3.2 键盘事件发送

接下来专注分析KeyButtonView的sendEvent方法,代码实现如下:

public void sendEvent(int action, int flags) {sendEvent(action, flags, SystemClock.uptimeMillis());
}

继续分析,代码实现如下:

void sendEvent(int action, int flags, long when) {//计算重复次数repeatCountfinal int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;//根据参数构建KeyEvent事件final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,InputDevice.SOURCE_KEYBOARD);//将KeyEvent事件加入到InputDispatcher的派发队列。//说明:INJECT_INPUT_EVENT_MODE_ASYNC表示加入派发队列后立刻返回,不阻塞,也不等待事件派发的成功与否。InputManager.getInstance().injectInputEvent(ev,InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}

接下来最关键的就是执行InputManager的injectInputEvent方法了。这一部分属于输入子系统了,感兴趣的伙伴可查看这篇文章的后半部分:

Android Framework 输入子系统 (10)Input命令解读_input swipe

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/421471.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java综合实践——学生成绩查询系统

此系列文章收录大量Java经典代码题&#xff08;也可以算是leetcode刷题指南&#xff09;&#xff0c;剩余文章指路Java题集。希望可以与大家一起探索Java的神秘。3、2、1&#xff0c;请看&#xff01; 本篇文章将带大家一起来写一个学生成绩查询系统。 目录 系统呈现效果 前…

一些硬件知识(二十二)

二极管&#xff08;Diode&#xff09;伏安特性、技术参数和项目中的应用 在正向偏置下&#xff0c;二极管呈现出良好的导电性能&#xff0c;可以允许电流通过&#xff1b;而在反向偏置下&#xff0c;二极管具有很高的阻断能力&#xff0c;几乎不允许电流通过。这是由构成二极管…

new String(),toString()和Arrays.toString()的区别

下面写了一段代码来展示结果 import javax.sound.midi.Soundbank; import java.util.Arrays; import java.util.Scanner;public class Main {public static void main(String[] args) {String str "abc";System.out.println("str:"str);char[] chars st…

Linux编译器-gcc/g++使用

1. 背景知识 1. 预处理&#xff08;进行宏替换) 2. 编译&#xff08;生成汇编) 3. 汇编&#xff08;生成机器可识别代码&#xff09; 4. 连接&#xff08;生成可执行文件或库文件) 2. gcc如何完成 格式 gcc [选项] 要编译的文件 [选项] [目标文件] 预处理(进行宏替换) 编…

SSM校园二手交易平台---附源码78592

摘要 SSM校园二手交易平台是针对大学生群体而设计的一款在线交易平台。该平台的目的是为大学生提供一个便捷、安全、可靠的交易渠道&#xff0c;帮助他们买卖二手商品。平台具有以下特点&#xff1a;注重安全性&#xff1a;平台采取严格的用户认证和身份验证机制&#xff0c;确…

【人工智能学习笔记】4_4 深度学习基础之生成对抗网络

生成对抗网络&#xff08;Generative Adversarial Network, GAN&#xff09; 一种深度学习模型&#xff0c;通过判别模型&#xff08;Discriminative Model&#xff09;和生成模型&#xff08;Generative Model&#xff09;的相互博弈学习&#xff0c;生成接近真实数据的数据分…

html 引入 css文档

1. 三种方法 html 引入 css文档有三种方式&#xff1a; 1.1 内部样式表 1.2 外部样式表 1.3 行内样式表

python 学习一张图

python学习一张图&#xff0c;python的特点的是学的快&#xff0c;一段时间不用&#xff0c;忘记的也快&#xff0c;弄一张图及一些入门案例吧。 写一个简单的测试&#xff1a; #!/usr/bin/python # -*- coding: UTF-8 -*- import osdef add_num(a, b):return a bif __name__…

【深度学习】Pytorch基础

目录 梯度下降算法&#xff08;Gradient Descent&#xff09;代码实现 梯度下降算法&#xff08;Gradient Descent&#xff09; 梯度下降算法在机器学习中应用十分的广泛&#xff0c;不论是在线性回归还是Logistic回归中&#xff0c;它的主要目的是通过迭代找到目标函数的最小…

企业会议室预约管理系统

基于springbootvuemysql实现的企业会议室预约管理系统&#xff08;源码数据库部署视频&#xff09; ### 主要技术 SpringBoot、Vue、MySQL ### 系统角色 员工、管理员 ### 系统功能 1&#xff09;管理员&#xff1a;数据统计&#xff08;会议室使用统计-柱状图、设备状态统计…

通过IDEA的Maven插件清理maven依赖缓冲

问题 有时候&#xff0c;在IDEA编程的时候&#xff0c;会遇到2个服务都依赖同一个模块&#xff0c;但是&#xff0c;其中有1个服务没有生效&#xff0c;但是&#xff0c;在CLI的maven中检查依赖树&#xff0c;没有任何问题&#xff0c;但是在IDEA中那个服务始终就是没有生效。…

计算语言学(一)基础

概率论的几个概念 熵、互信息 神经网络基础 MLP CNN RNN Seq2Seq LSTM Transformer 语料库与知识库

世界时钟 做外贸的朋友你需要这么一个看时间的工具

有很多人需要经常查看世界各地的时间&#xff0c;以前的办法就是去网上找时间&#xff0c;一个个对一下&#xff0c;这样是比较麻烦的&#xff0c;而且效率也非常低。 其实我们可以非常智能的管理这些时间时钟&#xff0c;让你更直观的&#xff0c;便捷的了解世界各地时间。 …

TESSY创建以及设计一个测试用例

我们以tessy5.1 IDE为例&#xff0c;给大家展示编写一个测试用例的过程。 还不会创建工程的&#xff0c;可以参考以下这篇文章&#xff1a; TESSY创建单元测试或集成测试工程_tessy 集成测试-CSDN博客 接下来我们以这个作为开始状态进行介绍 1、添加源文件 2、添加头文件路径…

Vulnhub-RickdiculouslyEasy靶场(9个flag)

flag1 端口9090有一个flag flag2 13337端口 flag3 使用dirb进行扫描网站的80端口&#xff0c;发现一些敏感文件 访问80端口&#xff0c;没有发现有效信息 访问passwords目录 访问FLAG.txt 再返回访问passwords.html文件 查看页面源代码发现一个密码 flag4 之前扫描到了robo…

一些硬件知识(二十)

单端差动放大器并不是指“单输入单输出”。它的意思是&#xff1a;输入端为差分输入&#xff0c;而输出为单端输出。 低压差线性稳压器&#xff08;LDO&#xff0c;Low Dropout Regulator&#xff09;是一种常见的线性稳压器&#xff0c;具有低输入输出电压差的特点&#xff0c…

全视通医院智慧后勤全场景管理+一体化解决方案,让医院管理提质增效

在 “十四五” 时期&#xff0c;公立智慧医院建设正如火如荼地进行着。2021年&#xff0c;国家卫生健康委医政医管局发布《医院智慧管理分级评估标准体系&#xff08;试行&#xff09;》&#xff0c;从政策层面给出了推进面向医务人员的“智慧医疗”、面向患者的“智慧服务”、…

线性方程组求解——预处理Preconditioning介绍

为什么需要预处理&#xff1f; 工程中出现的大规模线性方程组往往是病态的, 对数值求解带来很大的困难: ▶ 使得迭代法(比如Krylov 子空间迭代法) 收敛变得非常缓慢 ▶ 对数值解的精度产生很大的影响(在有限精度计算情形下) 对于第一个问题, 当前的有效处理方法是预处理, 预处…

Flutter的升级和降级步骤

升级 1.版本升级 // 升级到指定版本 flutter upgrade 版本号 // 升级到最新版本 flutter upgrade 2. 更新开发配置 启动 Android Studio。 打开 Settings 对话框&#xff0c;查看 SDK Manager。 如果你已经打开了一个项目&#xff0c;请打开 Tools > SDK Manager。 如果…

strtok函数讲解使用

目录 1.头文件 2.strtok函数介绍 3.解释strtok函数 小心&#xff01;VS2022不可直接接触&#xff0c;否则&#xff01;没这个必要&#xff0c;方源面色淡然一把抓住&#xff01;顷刻炼化&#xff01; 1.头文件 strtok函数的使用需要头文件 #include<string.h> 2.strto…