Android widget 小部件使用指南强化版
Android widget 小部件使用指南强化版
- 一、简单UI的小部件
- 二、含集合的小部件
- 三、可配置的小部件
- 四、可控制的小部件
- 五、Android 12 Widget 更新
小部件是主屏幕定制的一个重要方面。您可以将它们视为应用程序最重要的数据和功能的“概览”视图,这些数据和功能可以直接在用户的主屏幕上访问。用户可以在主屏幕面板上移动小部件,如果支持的话,还可以调整它们的大小以根据自己的喜好定制小部件中的信息量。
一、简单UI的小部件
此类小部件通常仅显示关键信息元素,布局简单。小部件属于RemoteViews
,常用的控件是支持的,如TextView、Images,但是不支持自定义的控件,具体参考:创建应用微件布局
- 声明
AppWidgetProviderInfo
XML:
定义了小部件的基本品质。AppWidgetProviderInfo
使用单个元素在 XML 资源文件中 定义对象<appwidget-provider>
并将其保存在项目的res/xml/
文件夹中。
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"android:initialLayout="@layout/all_note_appwidget_layout"android:minWidth="150dp"android:minHeight="54dp"android:previewImage="@drawable/todo_appwidget_preview"android:resizeMode="none"android:updatePeriodMillis="86400000"android:widgetCategory="home_screen" />
- initialLayout:指向定义小部件布局的布局资源
- previewImage:在选择应用小部件时看到的预览图
- updatePeriodMillis:小部件更新频率,实际更新不完全按时进行
- widgetCategory:声明您的小部件是否可以显示在主屏
home_screen
、锁定屏幕keyguard
或两者上
- 在清单中声明一个小部件:
AndroidManifest.xml
中声明小部件信息
<receiverandroid:name=".widget.AllNoteAppWidgetProvider"android:label="@string/all_notes"android:exported="true"><intent-filter><action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <!-- 必须 --><action android:name="com.android.note.widget.UPDATE_ALL_NOTE"/> <!-- 自定义 --></intent-filter><meta-dataandroid:name="android.appwidget.provider"android:resource="@xml/all_note_appwidget_info" />
</receiver>
- receiver:指定AppWidgetProvider小部件
- intent-filter:指定接受 AppWidgetProvider广播。
ACTION_APPWIDGET_UPDATE
这是您必须显式声明的唯一广播。根据需要自动 AppWidgetManager 将所有其他小部件广播发送到AppWidgetProvider。还可以自定义其他广播用于更新小部件的数据视图 - meta-data:
android:name
指定元数据名称,用于android.appwidget.provider
将数据标识为 AppWidgetProviderInfo描述符。android:resource
指定AppWidgetProviderInfo资源位置。
- 使用AppWidgetProvider来处理小部件广播
类AppWidgetProvider扩展 BroadcastReceiver为一个便利类来处理小部件广播,它仅接收与小部件相关的事件广播,例如小部件何时更新、删除、启用和禁用。所以我们重写AppWidgetProvider处理小部件广播并更新小部件以响应小部件生命周期事件。
public class AllNoteAppWidgetProvider extends AppWidgetProvider {public static final String UPDATE_ALL_NOTE_COUNT_ACTION = "com.android.note.widget.UPDATE_ALL_NOTE";@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {// 当添加相同的小部件时,需要全部遍历更新for (int appWidgetId : appWidgetIds) {updateAppWidget(context, appWidgetManager, appWidgetId);}}@Overridepublic void onReceive(Context context, Intent intent) {// 接收到自定义的广播,用于做处理后更新小部件if (UPDATE_ALL_NOTE_COUNT_ACTION.equals(intent.getAction())) {final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context,this.getClass()));for (int appWidgetId : appWidgetIds) {updateAppWidget(context, appWidgetManager, appWidgetId);}} else {super.onReceive(context, intent);}}static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {// 小部件的布局,实际就是RemoteViewsRemoteViews views = new RemoteViews(context.getPackageName(), R.layout.all_note_appwidget_layout);//做数据处理NoteDataManager manager = NoteDataManagerImpl.getInstance(context);int size = manager.getNotesForPresetFolder(NoteDataManagerImpl.ALL_NOTE_FOLDER).size();// 更新视图,作为RemoteViews,只能使用其通过的方法来设置值views.setTextViewText(R.id.size, context.getString(R.string.widget_note_count, size));// 添加一个跳转应用的意图Intent composeIntent = new Intent(context, NoteEditorActivity.class);composeIntent.putExtra(NoteEditorPresenter.OPEN_TYPE, 1);composeIntent.putExtra(FolderUtil.KEY_ID, 0);composeIntent.putExtra(FolderUtil.KEY_FILTER_TYPE, 0);PendingIntent composeNoteIntent = PendingIntent.getActivity(context, WidgetUtil.getUniqueCode(),composeIntent, PendingIntent.FLAG_IMMUTABLE);views.setOnClickPendingIntent(R.id.btn_add, composeNoteIntent);Intent intent = new Intent(context, MainActivity.class);intent.putExtra(Constants.KEY_DEFAULT_VIEW, Constants.TAG_NOTE);PendingIntent pendingIntent = PendingIntent.getActivity(context, WidgetUtil.getUniqueCode(),intent, PendingIntent.FLAG_MUTABLE);views.setOnClickPendingIntent(R.id.header, pendingIntent);// 通过 appWidgetManager 更新视图appWidgetManager.updateAppWidget(appWidgetId, views);}// 用于外部调用更新小部件public static void updateCount(Context context) {context.sendBroadcast(new Intent(UPDATE_ALL_NOTE_COUNT_ACTION, null, context, AllNoteAppWidgetProvider.class));}
}
- onReceive(Context, Intent):接收来自小部件的广播或者自定义的广播,以便来做一些操作。
- onUpdate():更新小部件调用此方法。当用户添加小部件时也会调用此方法,因此它应该执行基本设置,例如为 View对象定义事件处理程序或启动作业来加载要在小部件中显示的数据。
- 需要更新小部件时的更新方法
AllNoteAppWidgetProvider.updateCount(context);
- 效果参考
二、含集合的小部件
集合小部件专门用于显示相同类型的许多元素,例如来自图库应用程序的图片集合、来自新闻应用程序的文章或来自通信应用程序的消息。集合小部件通常专注于两个用例:浏览集合以及将集合的元素打开到其详细视图。集合小部件可以垂直滚动。小部件使用以下视图类型之一呈现数据,这些视图类型称为集合视图:
- ListView:显示垂直滚动列表中的项目的视图。
- GridView:显示二维滚动网格中的项目的视图。
- StackView:堆叠卡片视图(有点像名片盒),用户可以向上或向下轻拂前面的卡片以分别查看上一张或下一张卡片。
- AdapterViewFlipper:一个由适配器支持的简单动画 ViewAnimator,可以在两个或多个视图之间进行动画处理。一次只显示一个孩子。
由于这些集合视图由适配器支持,因此 Android 框架必须包含额外的架构来支持它们在小部件中的使用。在小部件的上下文中,Adapter
被替换为 RemoteViewsFactory
,它是界面的薄包装Adapter。当请求集合中的特定项目时,RemoteViewsFactory将创建集合的项目并将其作为对象返回 RemoteViews。要在您的小部件中包含集合视图,请实现RemoteViewsService
和 RemoteViewsFactory
。
关于创建小部件的大部分配置同简单UI小部件操作,关于集合视图的小部件其他操作步骤如下:
- 小部件的配置的
initialLayout
中含有集合视图,如ListView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/app_widget_background"android:orientation="vertical"android:padding="16dp"><ListViewandroid:id="@+id/note_list"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/widget_header"android:listSelector="@drawable/transparent_selector"android:scrollbars="none" /></RelativeLayout>
- 在
AndroidManifest.xml
中声明RemoteViewsService
<serviceandroid:name=".widget.NoteListWidgetService"android:exported="true"android:permission="android.permission.BIND_REMOTEVIEWS" />
- permission:通过在清单文件中使用 权限 声明该服务来执行此操作
BIND_REMOTEVIEWS
,可以防止其他应用程序随意访问您的小部件的数据。
- 实现
RemoteViewsService
和RemoteViewsFactory
public class NoteListWidgetService extends RemoteViewsService {private static final String TAG = "NoteListWidgetService";public NoteListWidgetService() {super();}@Overridepublic IBinder onBind(Intent intent) {return super.onBind(intent);}@Overridepublic RemoteViewsFactory onGetViewFactory(Intent intent) {// 创建 RemoteViewsFactoryreturn new ListViewRemoteViewsFactory(this, intent);}private static class ListViewRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {private Context mContext;private int mAppWidgetId;private ArrayList<NoteItem> mItems = new ArrayList<>();private AppWidgetManager mAppWidgetManager;public ListViewRemoteViewsFactory(Context context, Intent intent) {mContext = context;// 获取传递来的 AppWidgetIdmAppWidgetId =intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);}@Overridepublic void onCreate() {// 加载数据NoteDataManager mManager = NoteDataManagerImpl.getInstance(mContext);mItems = (ArrayList)mManager.getNotesForPresetFolder(2);}@Overridepublic void onDataSetChanged() {// 更新数据NoteDataManager mManager = NoteDataManagerImpl.getInstance(mContext);mItems = (ArrayList) mManager.getNotesForPresetFolder(2);}@Overridepublic void onDestroy() {mItems.clear();}@Overridepublic int getCount() {return Constants.WIDGET_LIST_COUNT;}@Overridepublic RemoteViews getViewAt(int i) {int size = mItems.size();if (i < size) {NoteItem item = mItems.get(i);Date date = new Date(item.getLongDate());// 创建的ListView项的第一种布局类型RemoteViews itemView = new RemoteViews(mContext.getPackageName(), R.layout.widget_listview_item_note);itemView.setTextViewText(R.id.note_time, DateUtil.getDisplayNoteTime(mContext, date));itemView.setTextViewText(R.id.note_title, NoteUtils.parseContent(mContext, item.getContent(), true));// 点击跳转应用,及传递参数,这里没有使用PendingIntent,而是在AppWidgetProvider中//通过setPendingIntentTemplate创建了模板,这里只需要Intent即可Intent fillInIntent = new Intent();fillInIntent.putExtra(FolderUtil.KEY_ID, item.getId());fillInIntent.putExtra(NoteEditorPresenter.OPEN_TYPE, NoteEditorPresenter.TYPE_EDIT_NOTE);itemView.setOnClickFillInIntent(R.id.listview_linearlayout, fillInIntent);return itemView;}//这里属于ListView项的第二种布局类型return new RemoteViews(mContext.getPackageName(), R.layout.app_widget_note_placeholder);}@Overridepublic RemoteViews getLoadingView() {return null;}@Overridepublic int getViewTypeCount() {// 布局类型的数目return 2;}@Overridepublic long getItemId(int i) {return i;}@Overridepublic boolean hasStableIds() {return false;}}
}
关于 RemoteViewsService.RemoteViewsFactory
:类似于Adapter的使用
- onCreate:首次加载,提供数据
- onDataSetChanged:后续更新,提供新数据
- onDestroy:清除数据
- getCount:ListView显示数据的条数
- getViewAt:返回ListView每项的视图,数据和界面更新的操作都在这里
- getViewTypeCount:ListView项的视图种类的个数,用于实现不同的布局,至少返回
1
,否则有数据也不显示,显示正在加载中
- getItemId:返回当前项的位置
- 在
AppWidgetProvider
更新时候调用
// 通过 NoteListWidgetService 更新,需要传递appWidgetId
Intent serviceIntent = new Intent(context, NoteListWidgetService.class);
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetIds[i]);
views.setRemoteAdapter(R.id.note_list, serviceIntent);// 创建 PendingIntent 模板
// 但是不支持添加多个PendingIntent 模板,那就意味着所有数据交互都只能走这一个PendingIntent
Intent itemIntent = new Intent(context, NoteEditorActivity.class);
PendingIntent listPendingIntent = PendingIntent.getActivity(context, 1,itemIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
views.setPendingIntentTemplate(R.id.note_list, listPendingIntent);// 通过appWidgetManager更新 ListView,调用 RemoteViewsFactory 的 onDataSetChanged
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds[i], R.id.note_list);
- 效果参考:默认显示3条数据,若无,则使用空白占位
三、可配置的小部件
如果您想让用户配置您的小部件的设置,请创建小部件配置Activity,此活动由应用程序小部件主机在创建小部件时或稍后自动启动,具体取决于您指定的配置选项。
- 应用程序小部件宿主调用配置活动,并且配置活动必须始终返回结果。结果必须包括启动该活动的意图传递的应用程序小部件 ID - 在意图附加中保存为
EXTRA_APPWIDGET_ID
. - 启动配置活动时系统不会发送广播 ,这意味着创建小部件时
ACTION_APPWIDGET_UPDATE
不会调用该方法。onUpdate()配置活动有责任在AppWidgetManager第一次创建小部件时请求更新。但是, onUpdate()会在后续更新中调用 - 仅在第一次时跳过。
此类小部件可以根据配置来显示不同用的小部件内容。
关于创建小部件的大部分配置同简单UI小部件操作,关于可配置的小部件其他操作步骤如下:
- 声明配置Activity:在
AndroidManifest.xml
中将配置活动声明为普通Activity
<activity android:name=".widget.FolderAppWidgetConfigure"android:exported="true"><intent-filter><action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/></intent-filter>
</activity>
- intent-filter:应用程序小部件主机通过
ACTION_APPWIDGET_CONFIGURE
操作启动它,因此活动需要接受此意图
- 在
AppWidgetProviderInfo.xml
使用属性声明配置的Activity
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"android:configure="com.android.note.widget.FolderAppWidgetConfigure"android:initialLayout="@layout/folder_appwidget_layout"android:minWidth="250dp"android:minHeight="110dp"android:previewImage="@drawable/todo_appwidget_preview"android:resizeMode="none"android:updatePeriodMillis="86400000"android:widgetCategory="home_screen" />
android:configure
:必须配置才可以生效
- 小部件Activity配置的具体实现
public class ExampleAppWidgetConfigure extends Activity {static final String TAG = "ExampleAppWidgetConfigure";private static final String PREFS_NAME= "com.example.android.apis.appwidget.ExampleAppWidgetProvider";private static final String PREF_PREFIX_KEY = "prefix_";int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;EditText mAppWidgetPrefix;public ExampleAppWidgetConfigure() {super();}@Overridepublic void onCreate(Bundle icicle) {super.onCreate(icicle);// 设置Activity布局,可以当作一个普通Activity来操作即可,例如设置文本、设置点击事件等setContentView(R.layout.appwidget_configure);mAppWidgetPrefix = (EditText)findViewById(R.id.appwidget_prefix);findViewById(R.id.save_button).setOnClickListener(mOnClickListener);// 必须:从intent获取 widget idIntent intent = getIntent();Bundle extras = intent.getExtras();if (extras != null) {mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);}// 如果 widget id 无效则放弃if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {finish();}mAppWidgetPrefix.setText(loadTitlePref(ExampleAppWidgetConfigure.this, mAppWidgetId));}View.OnClickListener mOnClickListener = new View.OnClickListener() {public void onClick(View v) {final Context context = ExampleAppWidgetConfigure.this;// 点击确定按钮时,根据AppWidgetId保存一些我们需要的信息到prefs中// 你可以保存更多您需要的信息,用于后续更新小部件的内容String titlePrefix = mAppWidgetPrefix.getText().toString();saveTitlePref(context, mAppWidgetId, titlePrefix);// 使用新设置的前缀将小部件更新推送到视图上AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);ExampleAppWidgetProvider.updateAppWidget(context, appWidgetManager,mAppWidgetId, titlePrefix);// 必须:需要返回接受到的原始的appWidgetId// 你可以传递更多的值,用于后续更新小部件的内容Intent resultValue = new Intent();resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);setResult(RESULT_OK, resultValue);finish();}};// 将此前缀写入该小部件的 SharedPreferences 对象static void saveTitlePref(Context context, int appWidgetId, String text) {SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();prefs.putString(PREF_PREFIX_KEY + appWidgetId, text);prefs.commit();}// 从该小部件的 SharedPreferences 对象中读取前缀。如果没有保存首选项,则从资源获取默认值static String loadTitlePref(Context context, int appWidgetId) {SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);String prefix = prefs.getString(PREF_PREFIX_KEY + appWidgetId, null);if (prefix != null) {return prefix;} else {return context.getString(R.string.appwidget_prefix_default);}}
}
EXTRA_APPWIDGET_ID
:必须接收从intent中的AppWidgetId
,最后完成配置后也必须返回此AppWidgetId
- SharedPreferences存值:我们需要用
appWidgetId
作为key
,以便添加多个小部件时不混淆
- 允许用户重新配置放置的小部件
默认情况下,应用程序小部件主机仅在用户将小部件添加到主屏幕后立即启动配置活动一次。但是,您可以指定选项,使用户能够重新配置现有小部件或通过提供默认小部件配置来跳过初始小部件配置。
要让用户重新配置现有小部件,需要在widgetFeatures
中指定标志 reconfigurable
<appwidget-providerandroid:configure="com.myapp.ExampleAppWidgetConfigurationActivity"android:widgetFeatures="reconfigurable">
</appwidget-provider>
reconfigurable
标志:在 Android 9(API 级别 28)中引入的,但直到 Android 12 才得到广泛支持。
四、可控制的小部件
控制小部件的主要目的是显示常用功能,以便用户可以从主屏幕触发它们,而无需打开应用程序。例如待办事项的复选框的,与元素交互,将它们标记为完成,由于从Android 12(API 级别 31)才开始支持这种复合按钮:CheckBox
、Switch
、RadioButton
。
而在 Android 12 之前我们也可以实现,没有可以通过使用ImageView
来达到这种效果,RemoteViews 提供了 setImageViewResource
用于更新ImageView资源,我们只需要准备2张图片资源即可。
RemoteViews itemView = new RemoteViews(mContext.getPackageName(), R.layout.widget_listview_item_todo);
itemView.setImageViewResource(R.id.todo_check, item.isComplete() ? R.drawable.todo_on : R.drawable.todo_off);
然而这仅仅是更新了小部件的UI,我们如何更新UI背后的数据逻辑呢? 这里是有方案,但是有缺陷,由于待办事项属于ListView布局,而本身具备点击事件,点击跳转到对应的待办内容详情页(Activity),因此需要在AppWidgetProvider
中设置PendingIntent 模板,但在我们需要更新待办完成数据时,就还需要利用这个PendingIntent 模板,如下:
Intent intent = new Intent();
intent.setAction(TodoAppWidgetProvider.CHECK_TODO_ACTION);
intent.putExtra(TodoAppWidgetProvider.KEY_ITEM_CHECK_ID, item.getId());
itemView.setOnClickFillInIntent(R.id.todo_check, intent);
这个时候可以在Activity中完成数据的更新操作,但是会跳转到Activity中,这个是我们不想要的,所以跳转后就需要finish
此Activity,但实际测试仍会出现闪一下Activity的现象,这就是缺陷,使用子线程仍会出现。
if (action != null && action.equals(TodoAppWidgetProvider.CHECK_TODO_ACTION)) {updateTodoWidget(intent);finish();return;
}private void updateTodoWidget(Intent intent) {new Thread(new Runnable() {@Overridepublic void run() {int id = intent.getIntExtra(TodoAppWidgetProvider.KEY_ITEM_CHECK_ID, 0);TodoItem todoItem = mNoteDataManager.getTodoItem(id);// 这里省略了对此todoItem的一些数据操作,使其完成或未完成if (mNoteDataManager.updateTodo(todoItem) > 0) {TodoAppWidgetProvider.updateWidget(mContext);}}}).start();
}
五、Android 12 Widget 更新
Google官方文档:[1] Android 12 微件改进 [2] AppWidget 示例 - Android 12 - Kotlin
- 实现圆角:Android 12 中的微件采用圆角设计。将应用微件用在搭载 Android 12 或更高版本的设备上时,启动器会自动识别微件的背景,并将其剪裁成具有圆角。
- 添加设备主题:微件可以为按钮、背景及其他组件使用设备主题颜色,包括浅色主题和深色主题。
- 使微件的个性化设置更容易:使用 appwidget-provider 的 configure 属性指定配置 activity,添加了一些新选项
- 添加新的复合按钮:
CheckBox
、Switch
、RadioButton
- 使用改进的 API 设置微件大小和布局
- 改进应用的微件选择器体验
- 实现更流畅的过渡
- 使用简化的 RemoteViews 集合:Android 12 添加了
setRemoteAdapter(int viewId, RemoteViews.RemoteCollectionItems items)
方法,可让您的应用在填充 ListView 时直接传递集合。 - 使用 RemoteViews 的运行时修改:Android 12 添加了几个
RemoteViews
方法,可用于在运行时修改 RemoteViews 属性。
相关参考:
[1] https://developer.android.google.cn/develop/ui/views/appwidgets/overview
[2] https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/appwidget
相关文章:
Android widget 小部件使用指南强化版
Android widget 小部件使用指南强化版 一、简单UI的小部件二、含集合的小部件三、可配置的小部件四、可控制的小部件五、Android 12 Widget 更新 小部件是主屏幕定制的一个重要方面。您可以将它们视为应用程序最重要的数据和功能的“概览”视图,这些数据和功能可以直…...
Linux下C语言操作网卡的几个代码实例?特别实用
前面写了一篇关于网络相关的文章:如何获取当前可用网口。 《简简单单教你如何用C语言列举当前所有网口!》 那么如何使用C语言直接操作网口? 比如读写IP地址、读写MAC地址等。 一、原理 主要通过系统用socket()、ioctl()、实现 int sock…...
noip2011选择旅馆
1.审题:第一个人与第二个人入住的旅馆要求是同色的; 两个人去消费的旅馆并没有要求与入住的旅馆是同色的(这点要小心) 2.要求记录以下数据: 1)a[color]表示当前同为颜色color的旅馆数 2)b[co…...
vue造轮子完整指南--npm组件包开发步骤
一、项目包文件的创建和初始化。 1. 新建项目包。 vue create <Project Name> //用于发布npm包的项目文件名 ps:一般选择自定义,然后不需要Vuex和Router,其他选项按自己实际情况选择安装即可。 2.修改原始src文件名、新增组件项目存放文件和修改…...
28 drf-Vue个人向总结-1
文章目录 前后端分离开发展示项目项补充知识开发问题浏览器解决跨域问题 drf 小tips设置资源root目录使用自定义的user表设置资源路径media数据库补充删除表中数据单页面与多页面模式过滤多层自关联后端提交的数据到底是什么jwt token登录设置普通的 token 原理使用流程解析 jw…...
线性代数(七) 矩阵分析
前言 从性线变换我们得出,矩阵和函数是密不可分的。如何用函数的思维来分析矩阵。 矩阵的序列 通过这个定义我们就定义了矩阵序列的收敛性。 研究矩阵序列收敛性的常用方法,是用《常见向量范数和矩阵范数》来研究矩阵序列的极限。 长度是范数的一个特…...
myArm 全新七轴桌面型机械臂
引言 在不断演进的科技世界中,我们始终追求创新和卓越,以满足客户的需求并超越他们的期望。今天,我们很高兴地宣布我们的最新产品——myArm 300 Pi,一款七轴的桌面型机械臂。这款产品的独特之处在于其灵活性和可编程性,…...
tomcat乱码解决
解决乱码 1、修改bin\catalina.bat配置文件 修改tomcat的配置文件,找到tomcat路径下的\bin目录下的catalina.bat文件,修改 set “JAVA_OPTS%JAVA_OPTS% %JSSE_OPTS% -Dfile.encodingUTF-8 -Dsun.jnu.encodingUTF-8 ” 2、修改conf\logging.properties配置…...
【Linux】详解线程第三篇——线程同步和生产消费者模型
线程同步和生消模型 前言正式开始再次用黄牛抢票来讲解线程同步的思想通过条件变量来实现线程同步条件变量接口介绍初始化和销毁pthread_cond_waitsignal和broadcast 生产消费者模型三种关系用基本工程师思维再次理解基于生产消费者模型的阻塞队列版本一版本二多生多消 利用RAI…...
k8s 安装
文章目录 k8s 客户端安装k8s集群minikubekindkubeadm 验证 k8s 客户端 用于连接k8s集群,建议下载1.23.x的版本,其他的版本本地运行可能会有莫名其妙的报错 https://dl.k8s.io/release/v1.23.16/bin/linux/amd64/kubectl 安装k8s集群 minikube Minik…...
红队打靶:THE PLANETS: MERCURY打靶思路详解(vulnhub)
目录 写在开头 第一步:主机发现和端口扫描 第二步:Web渗透 第三步:获取初步立足点并搜集信息 第四步:软连接劫持sudo提权 总结与思考 写在开头 本篇博客在自己的理解之上根据大佬红队笔记的视频进行打靶,详述了…...
【网络协议】IP
当连接多个异构的局域网形成强烈需求时,用户不满足于仅在一个局域网内进行通信,他们希望通过更高一层协议最终实现异构网络之间的连接。既然需要通过更高一层的协议将多个局域网进行互联,那么这个协议就必须为不同的局域网环境定义统一的寻址…...
Python 布尔类型
布尔值表示两个值之一:True(真)或False(假)。 布尔值 在编程中,您经常需要知道一个表达式是否为True或False。 您可以在Python中评估任何表达式,并获得两个答案之一:True或False。…...
iOS设备管理器iMazing比iTunes好用吗?有哪些优势
虽然 iTunes 是 Apple 官方指定的 iPhone 数据备份和管理工具,但是一直以来 iTunes 卡顿的使用体验和过慢的备份过程为不少人诟病。如果大家也被 iTunes 体验不佳的备份和管理功能所困扰,那么简单易用、功能强大的iMazing 能为你解决这个问题。 iMazing…...
Opengl之深度测试
在坐标系统小节中,我们渲染了一个3D箱子,并且运用了深度缓冲(Depth Buffer)来防止被阻挡的面渲染到其它面的前面。在这一节中,我们将会更加深入地讨论这些储存在深度缓冲(或z缓冲(z-buffer))中的深度值(Depth Value),以及它们是如何确定一个片段是处于其它片段后方的。 …...
利用ICG-NH2/Amine进行DNA标记1686147-55-6星戈瑞
ICG-NH2(吲哚菁绿胺)可以用于DNA标记,这种标记方法通常涉及到DNA上的胺基反应基团和ICG-NH2之间的化学反应。以下是一种常见的方法,用于利用ICG-NH2标记DNA分子: 步骤: 1.准备目标DNA:你需要准…...
Pyecharts数据可视化
Pyecharts数据可视化 1、Pyecharts模块2、柱状图3、折线图4、饼图5、散点图6、图表合并7、词云8、地图 1、Pyecharts模块 ECharts是百度提供的基于JavaScript的开源可视化库,主要用于Web端数据可视化 Echarts是通过JS实现的,Pyecharts则可以使用Python来…...
集合-List集合
系列文章目录 1.集合-Collection-CSDN博客 2.集合-List集合-CSDN博客 文章目录 目录 系列文章目录 文章目录 前言 一 . 什么是List? 二 . List集合的特点 三 . 常用方法 1.void add(int index, E element): 将指定的元素插入到列表的指定位置。 2.E remove(int in…...
vuex的使用
1 vuex的使用 1 vuex的使用 store/index.js -在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式 的管理(读/写),也是一种组件间通信的方式,且适用于任意…...
raw图片处理软件:DxO PhotoLab 6 mac中文版支持相机格式
DxO PhotoLab 6 mac是一款专业的RAW图片处理软件,适用于Mac操作系统。它具有先进的图像处理技术和直观易用的界面,可帮助用户轻松地将RAW格式的照片转换为高质量的JPEG或TIFF图像。 DxO PhotoLab 6支持多种相机品牌的RAW格式,包括佳能、尼康、…...
ReactPortals传送门
ReactPortals传送门 React Portals提供了一种将子节点渲染到父组件以外的DOM节点的解决方案,即允许将JSX作为children渲染至DOM的不同部分,最常见用例是子组件需要从视觉上脱离父容器,例如对话框、浮动工具栏、提示信息等。 描述 <div&…...
【GDB】 command 命令
GDB command 命令 语法 command 命令是一个很好用的调试命令,它配合断点使用,可以在指定的断点执行预先设置的命令 其语法为:command bread_id,这样会提示你输入你要执行的命令,以 end 结束。这个 bread_id 就是用 …...
1038 统计同成绩学生
输入样例: 10 60 75 90 55 75 99 82 90 75 50 3 75 90 88 输出样例: 3 2 0 solution #include <stdio.h> int main(){int n, d, k, hash[101] {0}, a[100000];scanf("%d", &n);for(int i 0; i < n; i){scanf("%d&quo…...
git报错:Failed to connect to 127.0.0.1 port 1080
Bug描述 由于在试了网上的这条命令 git config --global http.proxy socks5 127.0.0.1:1080 git config --global https.proxy socks5 127.0.0.1:1080git config --global http.proxy 127.0.0.1:1080 git config --global https.proxy 127.0.0.1:1080Bug描述:Faile…...
php eayswoole node axios crypto-js 实现大文件分片上传复盘
不啰嗦 直接上步骤 步骤1.开发环境配置 项目需要node.js 做前端支撑 官网下载地址: http://nodejs.cn/download/ 根据自己需要下载对应的版本,我下载的是windows系统64位的版本。 包下载好后 进行安装,安装步骤在此省略... 测试是否安装成功 …...
《Upload-Labs》01. Pass 1~13
Upload-Labs 索引前言Pass-01题解 Pass-02题解总结 Pass-03题解总结 Pass-04题解 Pass-05题解总结 Pass-06题解总结 Pass-07题解总结 Pass-08题解总结 Pass-09题解 Pass-10题解 Pass-11题解 Pass-12题解总结 Pass-13题解 靶场部署在 VMware - Win7。 靶场地址:https…...
v-for中的key
在Vue中,当使用v-for指令循环渲染元素时,添加:key是一个推荐做法,尤其是在循环的元素可能会被重新排序、添加或删除的情况下。 :key的作用是为每个循环的元素提供一个唯一的标识符,以便Vue能够跟踪和管理这些元素的状态。Vue使用…...
MySQL学习笔记17
MySQL权限管理grant: 权限说明: Table 6.2 Permissible Privileges for GRANT and REVOKE PrivilegeGrant Table ColumnContextALL [PRIVILEGES]Synonym for “all privileges”Server administrationALTERAlter_privTablesALTER ROUTINEAlter_routin…...
跨境电商建站:选择域名需要注意什么?
在跨境电商建站过程中,选择一个合适的域名至关重要,尤其是对于跨境电商独立站来说,它对未来的seo排名和品牌建设都有着重要影响。关于本文,我会先从域名的定义开始,到域名选择的重要性,再到如何选择一个完美…...
jupyterlab
1. 环境:linux 环境(基于ubuntu-fork 镜像实现) 2. pip install jupyter notebook 3. 编译jupyterlab源代码必须使用 node 14.21.3 高版本编译报错#下载 node 14.21.3 :wget https://nodejs.org/download/release/latest-v14.x/node-v14.21.…...
好发信息网站建设/媒介
这两天打算看看Petshop4.0的代码。下面记录一下遇到的问题。我的系统是Windows XP with SP3;开发环境是VS2005。1、在提交订单时,出错:MSDTC on server ‘(...)\SQLEXPRESS’ is unavailable.这是由于MSDTC服务没有运行的原因。启动服务下面即…...
如何做简洁网站/免费推广的网站有哪些
在数据聚合与分组中,主要包括: 根据一个或多个键(函数、数组、或dataframe的列名)拆分pandas对象 计算分组后数据的统计值,包括:计数,平均值,标准差,自定义函数 对datafr…...
上海市政府网站建设与对策分析/比较好的网络优化公司
前言 从刚接触前端开发起,跨域这个词就一直以很高的频率在身边重复出现,一直到现在,已经调试过N个跨域相关的问题了,16年时也整理过一篇相关文章,但是感觉还是差了点什么,于是现在重新梳理了一下。 个人见识…...
淘宝网站建设哪个类目/营销成功的案例
文章目录简单选择排序基本思想:以炒股为喻,冒泡像炒短线,选择则是炒长线代码:交换次数非常少时间复杂度:O(n2)O(n^2)O(n2)堆排序:充分利用了完全二叉树的深度和序号信息堆 heap堆排序的原理堆排序的例子堆排序的代码&a…...
网站维护成本/谷歌seo网站优化
原标题:【深度解析】第三方支付的分类、接口与支付流程 目录 - - - - - 1. 概述 2. 支付环节 3. 分类 4. 银行接口 如今第三方支付已经发展的非常成熟,但是至今仍未有一个比较权威的定义,下面将根据自己的工作经历说明一下第三方支付…...
影院网站建设/湛江百度网站快速排名
图片上传及路径设置对于在该编辑器中生成的图片为 base64 编码,所生成的字符占据太大空间,可考虑将其上传至服务器中,在该图片设置保存好的文件路径即可,以 php 为例。js 代码// 圖片上傳quill.on(text-change, function(delta, o…...