之前发了下拉通知栏开关修改的一篇文章。
这篇文章呢,主要介绍一下Android状态栏信号图标显示的流程。
便于在Android源生上开发的碰到问题的朋友,希望能对读者有所帮助。内容可能比较长
首先还是先介绍布局。

一、状态栏信号布局

路径:android\frameworks\base\packages\SystemUI\res\layout\status_bar.xml
如下代码就是状态栏的布局,包含:时钟、通知、system_icons等。

<?xml version="1.0" encoding="utf-8"?>
<com.android.systemui.statusbar.phone.PhoneStatusBarViewxmlns:android="http://schemas.android.com/apk/res/android"xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"android:layout_width="match_parent"android:layout_height="@dimen/status_bar_height"android:id="@+id/status_bar"android:background="@drawable/system_bar_background"android:orientation="vertical"android:focusable="false"android:descendantFocusability="afterDescendants"><ImageViewandroid:id="@+id/notification_lights_out"android:layout_width="@dimen/status_bar_icon_size"android:layout_height="match_parent"android:paddingStart="6dip"android:paddingBottom="2dip"android:src="@drawable/ic_sysbar_lights_out_dot_small"android:scaleType="center"android:visibility="gone"/><LinearLayout android:id="@+id/status_bar_contents"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingStart="6dp"android:paddingEnd="8dp"android:orientation="horizontal"><!-- The alpha of this area is controlled from both PhoneStatusBarTransitions andPhoneStatusBar (DISABLE_NOTIFICATION_ICONS). --><com.android.systemui.statusbar.AlphaOptimizedFrameLayoutandroid:id="@+id/notification_icon_area"android:layout_width="0dip"android:layout_height="match_parent"android:layout_weight="1"android:orientation="horizontal" /><com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"android:layout_width="wrap_content"android:layout_height="match_parent"android:orientation="horizontal"><include layout="@layout/system_icons" /><com.android.systemui.statusbar.policy.Clockandroid:id="@+id/clock"android:textAppearance="@style/TextAppearance.StatusBar.Clock"android:layout_width="wrap_content"android:layout_height="match_parent"android:singleLine="true"android:paddingStart="@dimen/status_bar_clock_starting_padding"android:paddingEnd="@dimen/status_bar_clock_end_padding"android:gravity="center_vertical|start"/></com.android.keyguard.AlphaOptimizedLinearLayout></LinearLayout><ViewStubandroid:id="@+id/emergency_cryptkeeper_text"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout="@layout/emergency_cryptkeeper_text"/>
</com.android.systemui.statusbar.phone.PhoneStatusBarView>

~
~
system_icons:信号区域:signal_cluster_view、状态栏电池, statusIcons(蓝牙、飞行模式statusIcons)。

system_icons内容如下图:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/system_icons"android:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center_vertical"><com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/statusIcons"android:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center_vertical"android:orientation="horizontal"/><include layout="@layout/signal_cluster_view"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="@dimen/signal_cluster_margin_start"/><com.android.systemui.BatteryMeterView android:id="@+id/battery"android:layout_height="match_parent"android:layout_width="wrap_content"/>
</LinearLayout>

~

signal_cluster_view有对应的布局,代码上写了,内容如下,内容较多、我就只截取部分展示了。其中mobile_signal_group就是信号区域了,它也对应一个布局 mobile_signal_group.xmlmobile_signal_group中主要是信号图标、数据流量箭头等位置显示了。

   <LinearLayoutandroid:id="@+id/mobile_signal_group"android:layout_height="wrap_content"android:layout_width="wrap_content"></LinearLayout><FrameLayoutandroid:id="@+id/no_sims_combo"android:layout_height="wrap_content"android:layout_width="wrap_content"android:contentDescription="@string/accessibility_no_sims"><com.android.systemui.statusbar.AlphaOptimizedImageViewandroid:theme="?attr/lightIconTheme"android:id="@+id/no_sims"android:layout_height="wrap_content"android:layout_width="wrap_content"android:src="@drawable/stat_sys_no_sims"/><com.android.systemui.statusbar.AlphaOptimizedImageViewandroid:theme="?attr/darkIconTheme"android:id="@+id/no_sims_dark"android:layout_height="wrap_content"android:layout_width="wrap_content"android:src="@drawable/stat_sys_no_sims"android:alpha="0.0"/></FrameLayout>

~

mobile_signal_group.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:systemui="http://schemas.android.com/apk/res-auto"android:id="@+id/mobile_combo"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="2dp"android:id="@+id/data_inout"android:visibility="gone"/><FrameLayoutandroid:layout_height="17dp"android:layout_width="wrap_content"><ImageViewandroid:id="@+id/mobile_in"android:layout_height="wrap_content"android:layout_width="wrap_content"android:src="@drawable/ic_activity_down"android:visibility="gone"android:paddingEnd="2dp"/><ImageViewandroid:id="@+id/mobile_out"android:layout_height="wrap_content"android:layout_width="wrap_content"android:src="@drawable/ic_activity_up"android:paddingEnd="2dp"android:visibility="gone"/></FrameLayout><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"><FrameLayoutandroid:id="@+id/mobile_signal_single"android:layout_width="wrap_content"android:layout_height="wrap_content"><com.android.systemui.statusbar.AnimatedImageViewandroid:theme="@style/DualToneLightTheme"android:id="@+id/mobile_signal"android:layout_height="wrap_content"android:layout_width="wrap_content"systemui:hasOverlappingRendering="false"/><com.android.systemui.statusbar.AnimatedImageViewandroid:theme="@style/DualToneDarkTheme"android:id="@+id/mobile_signal_dark"android:layout_height="wrap_content"android:layout_width="wrap_content"android:alpha="0.0"systemui:hasOverlappingRendering="false"/><ImageViewandroid:id="@+id/mobile_type"android:layout_height="wrap_content"android:layout_width="wrap_content"/><ImageViewandroid:id="@+id/mobile_roaming"android:layout_width="wrap_content"android:layout_height="17dp"android:paddingStart="22dp"android:paddingTop="1.5dp"android:paddingBottom="3dp"android:scaleType="fitCenter"android:src="@drawable/stat_sys_roaming"android:contentDescription="@string/accessibility_data_connection_roaming"android:visibility="gone" /></FrameLayout><LinearLayoutandroid:id="@+id/mobile_signal_stacked"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:visibility="gone"><ImageViewandroid:id="@+id/mobile_signal_data"android:layout_width="wrap_content"android:layout_height="wrap_content"/><ImageViewandroid:id="@+id/mobile_signal_voice"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout></FrameLayout>
</LinearLayout>

~

~

二、状态栏信号显示流程

接下来是信号的显示流程,android 8.0开始,与之前的android版本信号显示不太一样了。8.0源生代码中信号图标都是代码画出来的,并非与之前版本一样,直接使用图片显示了。所以,在开发中,我需要自己去修改,定制自己的信号样式,显示规格。
SignalClusterView.java
路径:frameworks\base\package\SystemUI\src\com\android\systemui\statusbar\SignalClusterView.java。它对应布局signal_cluster_view.xml,刚刚上面介绍过。
SignalClusterView.java完成控件的初始化、赋予图片显示。
下面,来说说它的逻辑。
SignalClusterView.java中有个内部类:PhoneState。
PhoneState中的apply()方法中对信号控件进行赋值。
其中mMobile就是信号控件
如下代码。

 public boolean apply(boolean isSecondaryIcon) {if (mMobileVisible && !mIsAirplaneMode) {if (mLastMobileStrengthId != mMobileStrengthId) {if (mReadIconsFromXML) {setIconForView(mMobile, mMobileStrengthId);setIconForView(mMobileDark, mMobileStrengthId);} else {mMobile.getDrawable().setLevel(mMobileStrengthId);mMobileDark.getDrawable().setLevel(mMobileStrengthId);}mLastMobileStrengthId = mMobileStrengthId;}if (mLastMobileTypeId != mMobileTypeId) {mMobileType.setImageResource(mMobileTypeId);mLastMobileTypeId = mMobileTypeId;}mDataActivity.setImageResource(mDataActivityId);if (mStackedDataId != 0 && mStackedVoiceId != 0) {mStackedData.setImageResource(mStackedDataId);mStackedVoice.setImageResource(mStackedVoiceId);mMobileSingleGroup.setVisibility(View.GONE);mMobileStackedGroup.setVisibility(View.VISIBLE);} else {mStackedData.setImageResource(0);mStackedVoice.setImageResource(0);mMobileSingleGroup.setVisibility(View.VISIBLE);mMobileStackedGroup.setVisibility(View.GONE);}mMobileGroup.setContentDescription(mMobileTypeDescription+ " " + mMobileDescription);mMobileGroup.setVisibility(View.VISIBLE);} else {mMobileGroup.setVisibility(View.GONE);}// When this isn't next to wifi, give it some extra padding between the signals.mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0,0, 0, 0);mMobile.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,0, 0, 0);mMobileDark.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,0, 0, 0);if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",(mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);mMobileRoaming.setVisibility((mRoaming && !mReadIconsFromXML)? View.VISIBLE : View.GONE);mMobileActivityIn.setVisibility(mActivityIn ? View.VISIBLE : View.GONE);mMobileActivityOut.setVisibility(mActivityOut ? View.VISIBLE : View.GONE);mDataActivity.setVisibility(mDataActivityId != 0 ? View.VISIBLE : View.GONE);return mMobileVisible;}

~
mReadIconsFromXML:是定义在config.xml中config_read_icons_from_xml的值,顾名思义。
setIconForView:设置图片,mIconScaleFactor是定义在dimen.xml中的值:status_bar_icon_scale_factor;

下面是setIconForView

private void setIconForView(ImageView imageView, @DrawableRes int iconId) {// Using the imageView's context to retrieve the Drawable so that theme is preserved.Drawable icon = imageView.getContext().getDrawable(iconId);if (mIconScaleFactor == 1.f) {imageView.setImageDrawable(icon);} else {imageView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor));}}

~
~
下面主要来说说: setIconForView(mMobile, mMobileStrengthId);中的 mMobileStrengthId,这个特别重要。在 MobileSignalController.java中的方法notifyListeners()中调用 SignalClusterView.javasetMobileDataIndicators()方法传进来的。

下面是setMobileDataIndicators()

 @Overridepublic void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,int qsType, boolean activityIn, boolean activityOut, int dataActivityId,int stackedDataId, int stackedVoiceId,String typeContentDescription,String description, boolean isWide, int subId, boolean roaming) {PhoneState state = getState(subId);if (state == null) {return;}state.mMobileVisible = statusIcon.visible && !mBlockMobile;#state.mMobileStrengthId = statusIcon.icon;state.mMobileTypeId = statusType;state.mMobileDescription = statusIcon.contentDescription;state.mMobileTypeDescription = typeContentDescription;state.mIsMobileTypeIconWide = statusType != 0 && isWide;state.mRoaming = roaming;state.mActivityIn = activityIn && mActivityEnabled && !mWifiVisible;state.mActivityOut = activityOut && mActivityEnabled && !mWifiVisible;state.mDataActivityId = dataActivityId;state.mStackedDataId = stackedDataId;state.mStackedVoiceId = stackedVoiceId;apply();}

~
~
MobileSignalController.java中的方法notifyListeners()

 @Overridepublic void notifyListeners(SignalCallback callback) {if (mConfig.readIconsFromXml) {generateIconGroup();}MobileIconGroup icons = getIcons();String contentDescription = getStringIfExists(getContentDescription());String dataContentDescription = getStringIfExists(icons.mDataContentDescription);final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED&& mCurrentState.userSetup;// Show icon in QS when we are connected or data is disabled.boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,getCurrentIconId(), contentDescription);int qsTypeIcon = 0;IconState qsIcon = null;String description = null;// Only send data sim callbacks to QS.if (mCurrentState.dataSim) {qsTypeIcon = showDataIcon ? icons.mQsDataType : 0;qsIcon = new IconState(mCurrentState.enabled&& !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);description = mCurrentState.isEmergency ? null : mCurrentState.networkName;}boolean activityIn = mCurrentState.dataConnected&& !mCurrentState.carrierNetworkChangeMode&& mCurrentState.activityIn;boolean activityOut = mCurrentState.dataConnected&& !mCurrentState.carrierNetworkChangeMode&& mCurrentState.activityOut;showDataIcon &= mCurrentState.isDefault || dataDisabled;if (SystemProperties.getBoolean("persist.vendor.radio.L_L_4G", false)&& (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE_CA|| mDataNetType == TelephonyManager.NETWORK_TYPE_LTE)) showDataIcon = true;int typeIcon = (showDataIcon && mStyle == STATUS_BAR_STYLE_ANDROID_DEFAULT) ? icons.mDataType : 0;int dataActivityId = showDataIcon && !showMobileActivity() ? icons.mActivityId : 0;callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,activityIn, activityOut, dataActivityId,icons.mStackedDataIcon, icons.mStackedVoiceIcon,dataContentDescription, description, icons.mIsWide,mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);}

~

~

statusIcon.icon对应下面代码getCurrentIconId()。不明白可以看下面NetworkController.java。

 IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,getCurrentIconId(), contentDescription);

NetworkController.java中的内部类IconState
路径:\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\NetworkController.java

 public static class IconState {public final boolean visible;public final int icon;public final String contentDescription;public IconState(boolean visible, int icon, String contentDescription) {this.visible = visible;this.icon = icon;this.contentDescription = contentDescription;}public IconState(boolean visible, int icon, int contentDescription,Context context) {this(visible, icon, context.getString(contentDescription));}}

android8.0和以前版本的区别就在这里。getCurrentIconId():

下面是8.0的代码,在8.0中是直接通过信号级别然后通过SignalDrawable代码绘制图片完成的。先对来说比往常版本要简单,但是如果要使用自己的信号样式,就是说定制信号样式。那么可以根据往常的版本来做。

 @Overridepublic int getCurrentIconId() {if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {return SignalDrawable.getCarrierChangeState(getNumLevels());} else if (mCurrentState.connected) {int level = mCurrentState.level;if (mConfig.inflateSignalStrengths) {level++;}if (mConfig.readIconsFromXml) {return getIcons().mSingleSignalIcon;} else {return SignalDrawable.getState(level, getNumLevels(),false);}} else if (mCurrentState.enabled) {if (mConfig.readIconsFromXml) {return getIcons().mSbDiscState;} else {return SignalDrawable.getEmptyState(getNumLevels());}} else {return 0;}}

~
~
~
以下是8.0之前的处理情况,直接获取信号级别图片,而这个图片呢是在你的res资源文件中。下面细看。
如果你要定制信号,请将readIconsFromXml 设置为true或改写代码。
readIconsFromXml 之前介绍过,在config中有定义。

 @Overridepublic int getCurrentIconId() {if (mConfig.readIconsFromXml && mCurrentState.connected) {return getIcons().mSingleSignalIcon;} else {return super.getCurrentIconId();}}

情况一、没有改写readIconsFromXml 。
return super.getCurrentIconId();
父类\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policySignalController.java中的getCurrentIconId()和getIcons();

  public int getCurrentIconId() {if (mCurrentState.connected) {return getIcons().mSbIcons[mCurrentState.inetCondition][mCurrentState.level];} else if (mCurrentState.enabled) {return getIcons().mSbDiscState;} else {return getIcons().mSbNullState;}}
 protected I getIcons() {return (I) mCurrentState.iconGroup;}

这里有点小复杂,MobileSignalController.java继承了SignalController.java。
并在generateIconGroup()对mCurrentState.iconGroup进行了赋值。
sbIcons 后面那个null是qsIcons,源生代码上状态栏下拉数据开关是显示信号的,一般看到手机上的都是开发者修改后的。
这里sbIcons使用了TelephonyIcons中的一个数组,数组中对应res中的信号图片文件。

       int[][] sbIcons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;mCurrentState.iconGroup = new MobileIconGroup(TelephonyManager.getNetworkTypeName(dataType),sbIcons , null, contentDesc, 0, 0, sbDiscState, 0, discContentDesc,dataContentDesc, dataTypeIcon, false, qsDataTypeIcon,singleSignalIcon, stackedDataIcon, stackedVoiceIcon, dataActivityId);

~~以上这种情况是简单的定制。但是比较复杂一点的定制这样就无法完成,比如三星的部分手机,还有个品牌手机电信卡信号显示双层信号。
~~
~~

下面说说第二种情况。

 @Overridepublic int getCurrentIconId() {if (mConfig.readIconsFromXml && mCurrentState.connected) {return getIcons().mSingleSignalIcon;} else {return super.getCurrentIconId();}}

当修改过mConfig.readIconsFromXml的值。
return getIcons().mSingleSignalIcon;
mSingleSignalIcon:对应上方代码
mCurrentState.iconGroup = new MobileIconGroup(.........){........}

中的参数singleSignalIcon。
而singleSignalIcon是通过generateIconGroup()方法从TelephonyIcons中获取的。(generateIconGroup详情,请看源码MobileSignalController.java)

singleSignalIcon = TelephonyIcons.getSignalStrengthIcon(slotId, inet, level, roaming);

~
~

下面介绍一下TelephonyIcons.java

getSignalStrengthIcon():返回值就是根据传进参数获取的信号级别图片。

mSignalStrengthArray:

获取的是res中array.xml中的三维数组,数组中存放着图片名称。R.array.multi_signal_strength

  readIconsFromXml()方法中:mSignalStrengthArray = mRes.getStringArray(R.array.multi_signal_strength);
 static int getSignalStrengthIcon(int slot, int inet, int level, boolean roaming) {log(TAG, "getSignalStrengthIcon: " + String.format("slot=%d, inetCondition=%d, level=%d, roaming=%b", slot, inet, level, roaming));String[] signalStrengthArray, selectedTypeArray;signalStrengthArray = mRes.getStringArray(mRes.getIdentifier(!roaming ?mSignalStrengthArray[slot] : mSignalStrengthRoamingArray[slot], null, NS));log(TAG, String.format("signalStrengthArray.length=%d", signalStrengthArray.length));selectedTypeArray = mRes.getStringArray(mRes.getIdentifier(signalStrengthArray[mSelectedSignalStreagthIndex[slot]], null, NS));log(TAG, String.format("selectedTypeArray.length=%d", selectedTypeArray.length));String[] inetArray = mRes.getStringArray(mRes.getIdentifier(selectedTypeArray[inet], null, NS));log(TAG, String.format("inetArray.length=%d", inetArray.length));return mRes.getIdentifier(inetArray[level], null, NS);}

~
这里在说一下,如果定制自己的信号样式的时候。发现代码修改都没有问题,R.array.multi_signal_strength的修改也没有问题。咦,怎么显示的和我在R.array.multi_signal_strength写的图片不一样,这个时候,检查一下android\vendor\qcom\proprietary\qrdplus\China下面。有三个文件夹ChinaMobile、ChinaTelecom、ChinaUnicom。一般是默认使用ChinaTelecom。为什么看这里呢,因为如果这里的array.xml的R.array.multi_signal_strength中和SystemUI中的R.array.multi_signal_strength中有相同的数组名字,它会使用ChinaTelecom中array.xml中的值。有点绕,希望能看明白。
~
~
~

信号定制、信号显示流程就到这里,能看懂的其实数据流量图标显示样式也能这样修改。下次有时间再写写信号是如何上报的,WIFI开启流程等等。欢迎读者交流,相互成长。

Android 8.0 状态栏信号显示、信号定制相关推荐

  1. Android 10.0状态栏居中显示时间和修改时间显示样式

    1.概述 状态栏系统时间默认显示在左边和通知显示在一起,但是客户想修改显示位置,想显示在中间,所以就要修改SystemUI 的Clock.java 文件这个就是管理显示时间的,居中显示的话就得修改布局 ...

  2. Android 5.0状态栏通知图标的实现

    Android 5.0状态栏通知图标的实现 我之前的博客文章中有一片是介绍了关于Android5.0 下拉通知栏快捷开关的添加,文章牵扯到一个知识点就是Android 5.0状态栏通知图标的实现.那么 ...

  3. Android 5.0 Launcher客制化定制之 主题包协议(MIUI主题、乐蛙主题兼容)

    Android 5.0 Launcher客制化定制之 主题包协议(MIUI主题.乐蛙主题兼容) 春节更新

  4. Android 6.0 状态栏信号图标分析

    先来一张状态栏的分区图.今天要分析的是信号显示这一小块,就是图中的signal_cluster,对应源码中的View就是SignalClusterView. 这是一个自定义View,我们看一下他的定义 ...

  5. Android 7.0 状态栏显示运营商名称

    1 在mobile_signal_group布局中增加 <TextViewandroid:id="@+id/carrier_text"android:layout_width ...

  6. android 5.0状态栏下载地址,Android沉浸式状态栏(5.0以上系统)

    Android沉浸式状态栏(5.0以上系统) 沉浸式状态栏可以分为两种: 1.直接给状态栏设置颜色 (如下图:) 这里写图片描述 java代码形式: if (Build.VERSION.SDK_INT ...

  7. PopWindow Android 7.0位置显示不准确以及Android 8.0全面屏显示导航键留白解决办法

    popWindow 在Android7.0上的显示位置不管怎么设置都在屏幕的顶部,这是7.0的bug,已在7.1修复,但是7.0还是需要我们自己解决的,以及在小米mix2全面屏导航键留白,显示不全. ...

  8. Android 9.0 APP中显示导航栏的menu键

    PS:以前  Android 4.0 时代,写了个APP,用屏幕底部菜单键提供两个刷新及退出按钮,但是现在 android 动不动就更新下,现在我手机已经到 9.0 版了,原来的导航栏三个小点点菜单键 ...

  9. android灰字体什么意思,Android 6.0状态栏使用灰色文字和图标

    Android StatusBar中的字体和图标默认都是白色的,但是Android在6.0之前是没有办法更改这个颜色, 在Android 6.0中提供了一个SYSTEM_UI_FLAG_LIGHT_S ...

最新文章

  1. 如何对付费广告流量进行标记?
  2. java发送小程序模板消息,记录_小程序发送模板消息
  3. nginx ---- nginx.conf核心配置文件
  4. 添加元素:让图片变废为宝
  5. 华为IS-IS基础配置
  6. ntp时间校准服务器的调试方法
  7. python 多线程ping_Python快速多线程ping实现
  8. 胧月初音未来计算机,胧月(流星P所作歌曲《胧月》)_百度百科
  9. 车牌识别-基于模板匹配
  10. 安卓火狐浏览器wifi远程调试没有扫描二维码应用的问题
  11. php主机安装教程,easypanel 主机面板安装教程
  12. 微信小程序更改checkbox和radio样式
  13. 深入 Parcel架构与流程
  14. ps 简笔画效果制作
  15. rails网站分享到朋友圈功能是怎么实现的
  16. Android github上优秀开源项目分类汇总
  17. dock运行环境对linux的版本要求,Latte Dock 0.8发布,KDE Plasma 5.12或更高版本才能用...
  18. python爬虫,虎牙房间爬取(selenium)
  19. 零基础学python 视频_零基础入门学习PYTHON(第2版)(微课视频版)
  20. HYSBZ 2251 外星联络

热门文章

  1. AutoGPT是什么?超简单安装使用教程
  2. 好用的在线二维码生成器网站PHP源码
  3. Android 画廊控件Gallary
  4. Python PYQT5中用Label控件显示以numpy表示的灰度图像
  5. 人到中年这种茶要多喝,越喝血管越干净!坚持一个月,头晕眼花不再来!
  6. PS安装出现浏览器或操作系统不支持以及需要登录的处理方式
  7. 超声波传感器--Arduino
  8. 深度对比:电子合同与纸质合同到底有哪些差异?
  9. ubuntu_pip-install_WARRING:XXX is not on PATH ...
  10. mysql和ocr_图文识别OCR的作用和优势是什么?