Android Mvp案例解析
目录
- 后端数据接口
- 数据格式
- App客户端
- 布局逻辑
- 主界面布局
- M(Model)
- V(View)
- P(Presenter)
- Okhttp+Retrofit+RxJava网络http请求
- Mvp架构-初学者
- MVP架构的契约者
后端数据接口
接口地址:https://apis.tianapi.com/caipu/index
请求示例:https://apis.tianapi.com/caipu/index?key=你的APIKEY&word=黄瓜
支持协议:http/https
请求方式:get/post
返回格式:utf-8 json
数据格式
{"code": 200,"msg": "success","result": {"curpage": 1,"allnum": 5,"newslist": [{"id": "90e761e707dd996c431992c8e2a0a88b","ctime": "2023-07-07 08:29","title": "为避免轨道碰撞 SpaceX星链卫星6个月内“让路”","description": "7月7日消息,在过去6个月里,为了避免轨道碰撞,埃隆·马斯克(ElonMusk)旗下SpaceX公司的星链卫星机动次数激增,这引发了人们对卫星长期可持续性运行的担忧,因为未来几年将有数万颗新卫星进入轨道。在最近向美国联邦通信委员会(FCC...[]","source": "网易科技","picUrl": "https://nimg.ws.126.net/?url=http%3A%2F%2Fcms-bucket.ws.126.net%2F2023%2F0707%2F0f703849p00rxeh90001cc0009c0070c.png&thumbnail=200y140&quality=100&type=jpg","url": "https://www.163.com/tech/article/I91GDFVG00097U81.html"},{"id": "e8e49d6dd77be1a6ea82929a14abe6ef","ctime": "2023-07-07 06:32","title": "推特指责 Meta 挖角员工创建 Threads","description": "","source": "网易科技","picUrl": "https://nimg.ws.126.net/?url=http%3A%2F%2Fbjnewsrec-cv.ws.126.net%2Flittle730693cc23fj00rxebr3004xc000fw00lcg.jpg&thumbnail=200y140&quality=100&type=jpg","url": "https://www.163.com/dy/article/I919NRS10511B8LM.html"},{"id": "55cf44c545e02e8d9fc30e8b07980d3d","ctime": "2023-07-06 21:08","title": "分析人士:Meta的Threads对马斯克的Twitter构成","description": "","source": "网易科技","picUrl": "https://nimg.ws.126.net/?url=http%3A%2F%2Fbjnewsrec-cv.ws.126.net%2Flittle32088c42c3cj00rxdlrp000xc000sg00hgg.jpg&thumbnail=200y140&quality=100&type=jpg","url": "https://www.163.com/dy/article/I909EBMH0511B8LM.html"},{"id": "0bbc1f1f13121586804bb72e245448b2","ctime": "2023-07-06 20:26","title": "中国电信研究院副院长李安民:发展元宇宙,要提","description": "","source": "网易科技","picUrl": "https://nimg.ws.126.net/?url=http%3A%2F%2Fbjnewsrec-cv.ws.126.net%2Flittle64910ee1b6bj00rxctez005jd000j600anp.jpg&thumbnail=200y140&quality=100&type=jpg","url": "https://www.163.com/dy/article/I9071U0D0519DFFO.html"},{"id": "1962b01db3569398109fe336d5f8ff29","ctime": "2023-07-06 20:42","title": "XR“失宠”?头显出货量下降超三成,元宇宙再降","description": "","source": "网易科技","picUrl": "https://nimg.ws.126.net/?url=http%3A%2F%2Fbjnewsrec-cv.ws.126.net%2Flittle252508775e3j00rxdev60080c000se00fsg.jpg&thumbnail=200y140&quality=100&type=jpg","url": "https://www.163.com/dy/article/I907V12305199NPP.html"}]}
}
App客户端
MVP规范接口:IView、IModel、IPresenter,用于规范接口
package com.xzln.eatwhatjava.view;public interface IView {} // 用于规范View层接口
package com.xzln.eatwhatjava.model;public interface IModel {} // 用于规范Model层接口
package com.xzln.eatwhatjava.presenter;import com.xzln.eatwhatjava.view.IView;/*** 抽离公共接口* 所有的P层对象都公有* 而V层和M层对象则都是根据具体的业务进行定制* @param <V>*/
public interface IPresenter<V extends IView> {/*** 依附生命view* @param view v层对象*/void attachView(V view);/*** 分离View*/void detachView();/*** 判断View是否已经销毁* @return 是否销毁*/boolean isViewAttached();
}
回调规范接口:ICallBack
package com.xzln.eatwhatjava.contact;public interface ICallBack<T, K> {void onSuccess(T data);void onFail(K data);
}
布局逻辑
ViewPager2+Fragment
其中Fragment由refreshLayout+RecycleView组成,RecycleView放新闻条目。
ViewPager2用于对新闻进行分类
主界面布局
// activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".view.MainActivity"android:orientation="vertical"><com.google.android.material.tabs.TabLayoutandroid:id="@+id/tab_layout"android:layout_width="match_parent"android:layout_height="40dp"android:background="@color/colorPrimary"app:tabGravity="fill"app:tabMode="fixed"app:tabTextColor="@android:color/white" /><androidx.viewpager2.widget.ViewPager2android:id="@+id/view_pager2"android:layout_width="match_parent"android:layout_height="match_parent" />
</LinearLayout>

M(Model)
// INewsModel.java
package com.xzln.eatwhatjava.model;import com.xzln.eatwhatjava.contact.ICallBack;/*** 定义规范接口:(新闻)* 单一接口的M层*/
public interface INewsModel extends IModel {// post请求void getData(int page, int num, final ICallBack callback);
}
// NewsModel.java
package com.xzln.eatwhatjava.model;import android.util.Log;import com.xzln.eatwhatjava.api.NewsApi;
import com.xzln.eatwhatjava.bean.NewsListBean;
import com.xzln.eatwhatjava.bean.Result;
import com.xzln.eatwhatjava.config.NewsConfig;
import com.xzln.eatwhatjava.contact.ICallBack;
import com.xzln.eatwhatjava.utils.RetrofitUtils;import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
/*** 定义了News功能模块的M层类* 调用retrofit网络API,通过CallBack将数据传到P层* TODO: onNext中发生错误的情况 和 onError中发生错误的情况 都有哪些*/
public class NewsModel implements INewsModel {public static final String TAG = "com.xzln.eatwhatjava.model.NewsModel";@Overridepublic void getData(int page, int num, ICallBack callback) {fetchKejiNews(page, num).observeOn(AndroidSchedulers.mainThread()) // Android 主线程观察.subscribeOn(Schedulers.io()) // 消费.subscribe(new Observer<Result<NewsListBean>>() { // URL访问成功@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Result<NewsListBean> newsListBeanResult) { // 数据迭代器?if (null == newsListBeanResult) { callback.onFail("出现错误: null == newsListBeanResult"); } else if (newsListBeanResult.getCode() != 200) { callback.onFail(newsListBeanResult.getMsg());} else { callback.onSuccess(newsListBeanResult); }}@Overridepublic void onError(Throwable e) { // 访问错误或者数据解析错误e.printStackTrace();callback.onFail("出现错误: onError");}@Overridepublic void onComplete() { Log.d(TAG, "onComplete"); }});}protected Observable<Result<NewsListBean>> fetchKejiNews(int page, int num) {return RetrofitUtils.getRetrofit().create(NewsApi.class).fetchKejiNews(NewsConfig.getKejiNewsFieldMap(page, num));}
}
V(View)
// INewsView.java
package com.xzln.eatwhatjava.view;import com.xzln.eatwhatjava.presenter.IPresenter;/*** 定义News功能模块的View类的规范接口* (P层和V层的桥梁)* @param <P> P层对象类型* @param <T> P层访问成功时返回的类型* @param <V> P层访问失败时返回的类型*/
public interface INewsView<P extends IPresenter, T, V> extends IView{void showNewsSuccess(T newsBeans);void showNewsFail(V data);
}
package com.xzln.eatwhatjava.base;import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import com.xzln.eatwhatjava.presenter.IPresenter;
import com.xzln.eatwhatjava.view.IView;/*** 抽象类,Fragment的公共抽象类* @param <P>*/
public abstract class BaseFragment<P extends IPresenter> extends Fragment implements IView {protected P mPresenter; // P层对象,用于和V层、M层进行联系protected View mView; // V层对象,通过V层对象完成P和V之间的联系/*** 完成P层对象的创建和初始化* @param savedInstanceState If the fragment is being re-created from* a previous saved state, this is the state.*/@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);initPresenter();init();}/**** @param inflater The LayoutInflater object that can be used to inflate* any views in the fragment,* @param container If non-null, this is the parent view that the fragment's* UI should be attached to. The fragment should not add the view itself,* but this can be used to generate the LayoutParams of the view.* @param savedInstanceState If non-null, this fragment is being re-constructed* from a previous saved state as given here.** @return 视图对象*/@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentmView = inflater.inflate(getLayoutId(), container, false);return mView;}/*** Fragment销毁时,先取消P层对象和Fragment的绑定,避免空指针异常*/@Overridepublic void onDestroy() {if (mPresenter != null && mPresenter.isViewAttached()) {mPresenter.detachView();}super.onDestroy();}/*** 创建和初始化P层对象,将P层对象生命周期与当前Fragment绑定*/protected void initPresenter() {mPresenter = createPresenter();//绑定生命周期if (mPresenter != null) {mPresenter.attachView(this);}}/*** 抽象方法,由子类根据对应的布局来实现,返回其布局ID,用于Fragment的OnCreateView* @return 布局ID*/public abstract int getLayoutId();/*** 创建一个Presenter** @return P层对象*/protected abstract P createPresenter();/*** 用于子类的其他数据的初始化*/protected abstract void init();}
//NewsFragment.java
package com.xzln.eatwhatjava.view;import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;import com.xzln.eatwhatjava.R;
import com.xzln.eatwhatjava.adapter.NewsRecycleViewAdapter;
import com.xzln.eatwhatjava.base.BaseFragment;
import com.xzln.eatwhatjava.bean.NewsBean;
import com.xzln.eatwhatjava.presenter.NewsPresenter;import java.util.LinkedList;
import java.util.List;/*** News的布局碎片*/
public class NewsFragment extends BaseFragment<NewsPresenter> implements INewsView<NewsPresenter, List<NewsBean>, String> {private static final String TAG = "com.xzln.eatwhatjava.view.NewsFragment";protected int mNewsType; // News的类别,由创建者传入protected SwipeRefreshLayout mSwipeRefreshLayout; // 顶部的刷新布局protected RecyclerView mRecycleView;protected List<NewsBean> mNewsBeans; // 数据列表protected int mCurPage = 0; // 当前页码protected int mNumOfPage = 25; // 每页中数据数目protected NewsRecycleViewAdapter mNewsRecycleViewAdapter; // RecycleView适配器protected LinearLayoutManager mLinearLayoutManager;private int mTotalItemCount;/*recycleView下的总item数目*/private int mFirstVisibleItem;/*当前可见区内最后一个item的position*/private int mLastVisibleItem;/*当前可见区内最后一个item的position*//*Return the current number of child views attached to the parent RecyclerView.*/private int mVisibleItemCount;/*当前recycleView下可见的item数*/public NewsFragment(int newsType) { mNewsType = newsType; }/*** 刷新时调用:页码清零、数据清空、重新获取数据*/protected void refreshView() {mCurPage = 0;mNewsBeans.clear();mNewsRecycleViewAdapter.clearData();mPresenter.getNewsData(mCurPage++, mNumOfPage);}@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {return super.onCreateView(inflater, container, savedInstanceState);}@Overridepublic void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);mSwipeRefreshLayout = mView.findViewById(R.id.layout_swipe_refresh);mRecycleView = mView.findViewById(R.id.view_recycle);// mPresenter.getNewsData(mCurPage++, mNumOfPage);refreshView();setupListener();}/*** 用于创建P层对象,由子类具体定制实现* @return P层对象*/@Overrideprotected NewsPresenter<NewsFragment> createPresenter() { return new NewsPresenter<>(this); }/*** 由子类定制,用于完成子类中的数据初始化* 视图id的绑定不可在这完成。因为视图View对象的生成在OnCreateView,而init函数在OnCreate中*/@Overrideprotected void init() {mNewsBeans = new LinkedList<>();mNewsRecycleViewAdapter = new NewsRecycleViewAdapter(getActivity(), mNewsBeans);}/*** @return 视图布局文件的ID*/@Overridepublic int getLayoutId() { return R.layout.activity_fragment_main; }/*** 启动监听器* 1. 刷新头* 2. RecycleView适配器、布局管理器*/private void setupListener() {mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {@Overridepublic void onRefresh() {Log.d(TAG, "mSwipeRefreshLayout.setOnRefreshListener.onRefresh");
// mSwipeRefreshLayout.setRefreshing(false);refreshView();new Handler().postDelayed(new Runnable() {@Overridepublic void run() { mSwipeRefreshLayout.setRefreshing(false); }},2000);}});mLinearLayoutManager = new LinearLayoutManager(getActivity());mRecycleView.setLayoutManager(mLinearLayoutManager);mRecycleView.setAdapter(mNewsRecycleViewAdapter);/*recycleView*/mRecycleView.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {super.onScrollStateChanged(recyclerView, newState);Log.d(TAG, "onScrollStateChanged --> newState" + newState);// 获取数据逻辑// 滚动状态改变 && 最后一个position + 1 >= totalif (newState == RecyclerView.SCROLL_STATE_DRAGGING &&mLastVisibleItem + 1 >= mTotalItemCount &&mVisibleItemCount <= mTotalItemCount) {mPresenter.getNewsData(mCurPage++, mNumOfPage);}@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);mLinearLayoutManager.findFirstVisibleItemPosition();mTotalItemCount = mLinearLayoutManager.getItemCount();mFirstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();mLastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition();/*当前可见区内最后一个item的position*//*Return the current number of child views attached to the parent RecyclerView.*/mVisibleItemCount = mLinearLayoutManager.getChildCount();/*当前recycleView下可见的item数*/}});}/*** 与P层联系的函数* @param newsBeans P层成功返回的数据*/@Overridepublic void showNewsSuccess(List<NewsBean> newsBeans) {Log.d(TAG, "showNewsSuccess newsBeans.size()=" + newsBeans.size());mNewsRecycleViewAdapter.addData(newsBeans);}/*** 与P层联系的函数* @param data P层失败返回的数据*/@Overridepublic void showNewsFail(String data) {Log.d(TAG, "showNewsSuccess");}
}
P(Presenter)
// IPresenter.java
package com.xzln.eatwhatjava.presenter;import com.xzln.eatwhatjava.view.IView;/*** 抽离公共接口* 所有的P层对象都公有* @param <V>*/
public interface IPresenter<V extends IView> {/*** 依附生命view* @param view v层对象*/void attachView(V view);/*** 分离View*/void detachView();/*** 判断View是否已经销毁* @return 是否销毁*/boolean isViewAttached();
}
// BasePresenter.java
package com.xzln.eatwhatjava.base;import com.xzln.eatwhatjava.presenter.IPresenter;
import com.xzln.eatwhatjava.view.IView;/*** IPresenter接口需要所有的P层实现类继承* 对于生命周期这部分功能P层都是通用的,因此可以抽出来一个抽象基类BasePresenter,去实现IPresenter的接口.* @param <V>*/
public abstract class BasePresenter<V extends IView> implements IPresenter<V> {protected V mView;@Overridepublic void attachView(V view) { mView = view; }@Overridepublic void detachView() { mView = null; }@Overridepublic boolean isViewAttached() { return mView != null; }
}
P层对象中持有V层对象和M层对象
P层调用M层获取数据,并设置CallBack。通过CallBack完成M层和P层间的联系。
在CallBack中调用View对象,完成P层与V层的联系。
// NewsPresenter.java
package com.xzln.eatwhatjava.presenter;import android.util.Log;import com.xzln.eatwhatjava.base.BasePresenter;
import com.xzln.eatwhatjava.bean.NewsListBean;
import com.xzln.eatwhatjava.bean.Result;
import com.xzln.eatwhatjava.contact.ICallBack;
import com.xzln.eatwhatjava.model.INewsModel;
import com.xzln.eatwhatjava.model.NewsModel;
import com.xzln.eatwhatjava.view.INewsView;
import com.xzln.eatwhatjava.view.IView;/*** News功能模块P层逻辑* @param <V>*/
public class NewsPresenter<V extends IView> extends BasePresenter<V> {private static final String TAG = "com.xzln.eatwhatjava.presenter.NewsPresenter";protected INewsView mNewsView;protected INewsModel mNewsModel;public NewsPresenter(V view) {mNewsView = (INewsView) view;createModel();}private void createModel() {if (mNewsModel == null) { mNewsModel = new NewsModel(); }}public void getNewsData(int page, int num) {mNewsModel.getData(page, num,new ICallBack<Result<NewsListBean>, String>() { // P层定义CallBack,从而将数据从@Overridepublic void onSuccess(Result<NewsListBean> data) {Log.d(TAG, ".getData.onSuccess");mNewsView.showNewsSuccess(data.getResult().getNewslist());}@Overridepublic void onFail(String data) {mNewsView.showNewsFail("数据获取失败");Log.d(TAG, ".getData.onFail --> " + data);}});}
}
// ICallBack.java
package com.xzln.eatwhatjava.contact;public interface ICallBack<T, K> {void onSuccess(T data);void onFail(K data);
}
Okhttp+Retrofit+RxJava网络http请求
RetrofitUtil
//RetrofitUtils.java
package com.xzln.eatwhatjava.utils;import com.xzln.eatwhatjava.config.NewsConfig;import java.util.concurrent.TimeUnit;import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;public class RetrofitUtils {private static Retrofit retrofit;private static OkHttpClient okhttp;/*** 自定义okhttp客户端** @return okhttp客户端*/public static OkHttpClient getOkhttp() {if (okhttp == null) {synchronized (RetrofitUtils.class) {if (okhttp == null) {okhttp = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS).readTimeout(15, TimeUnit.SECONDS).writeTimeout(15, TimeUnit.SECONDS).build();}}}return okhttp;}/*** 单例retrofit客户端** @return retrofit客户端*/public static Retrofit getRetrofit() {if (retrofit == null) {synchronized (RetrofitUtils.class) {if (retrofit == null) {retrofit = new Retrofit.Builder().baseUrl(NewsConfig.newsBaseUrl).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(GsonConverterFactory.create()).client(getOkhttp()).build();}}}return retrofit;}
}
//NewsApi.java
package com.xzln.eatwhatjava.api;import com.xzln.eatwhatjava.bean.NewsListBean;
import com.xzln.eatwhatjava.bean.Result;import java.util.Map;
import io.reactivex.Observable;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;public interface NewsApi {// POST请求数据@FormUrlEncoded@POST("keji/index")Observable<Result<NewsListBean>> fetchKejiNews(@FieldMap Map<String, Object> map);
// Observable<Result<List<NewsBean>>> fetchKejiNews(@FieldMap Map<String, Object> map);
}
Mvp架构-初学者
MVP架构是为了让各个模块之间降低耦合,方便维护,也可以让代码更简洁,让代码简洁的意思是让代码更清晰,并不是让代码更少;MVP契约者是为了进一步的低耦合、接口统一管理。
MVP对接口灵活的调用可以轻松的应对产品的变更。
presenter
类与View 和 Model 通信,做到视图和逻辑的解耦。
MVP架构的契约者
TODO
相关文章:

Android Mvp案例解析
目录 后端数据接口数据格式 App客户端布局逻辑主界面布局 M(Model)V(View)P(Presenter)OkhttpRetrofitRxJava网络http请求 Mvp架构-初学者MVP架构的契约者 后端数据接口 接口地址:https://apis.…...

vue的双向绑定的原理,和angular的对比
目录 前言 Vue的双向绑定用法 代码 Vue的双向绑定原理 Angular的双向绑定用法 代码 Angular的双向绑定原理 理解 效率: 虽然Vue和Angular的双向绑定原理不同,但它们都致力于提供高效的数据更新机制。但是,由于Vue使用的是数据劫持,其…...

平衡树相关笔记
引入 二叉查找树 二叉查找树(Binary Search Tree),又名二叉搜索树。满足以下性质: 对于非空的左子树,左子树点权值小于根节点。对于非空的右子树,左子树点权值大于根节点。二叉查找树的左右子树均是二叉…...
ASP.net C# 用Aspose.pdf实现pdf合并
直接上代码,供参考,备忘! using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data; using System.Data.SqlClient; using System.Xml; using System…...
C语言实现原码一位除
具体代码如下,直接运行即可。 #include <stdio.h> int main() {int i, a 0, b 0, c 0, flag 3; // flag相当于指针来指明Q的位置char x[6], y[6];int R[6], Q[6], yb[6], y1[6]; // yb是-y的补码,y1为绝对值yprintf("请输入X(带一位符号位四位数值位…...

three.js点滴yan(整理后)
场景、相机和渲染器 Three.js整个系统主要包含场景Scene、相机Camera和WebGL渲染器WebGLRenderer三大块,其中场景又包含模型和光源。WebGL渲染器的主要作用就是把相机对应场景渲染出来,显示在网页Cnavas画布上。 Three.js源码 Three.js各个构造函数对应…...

VMware安装CentOS最小化开发环境导引
目录 一、概要 二、介绍 三、下载 四、安装 4.1 创建虚拟机 4.2 安装CentOS 五、配置网卡 六、配置本地安装源 七、安装软件 7.1 gcc/g 7.2 C的atomic库 7.3 java 7.4 Cmake 7.5 MariaDB客户端(兼容mysql) 八、用户配置文件.bash_profile…...
服务器端编程/数据库驱动程序/RESTful API:介绍
目录 服务器端编程数据库驱动程序RESTful API 👍 点赞,你的认可是我创作的动力! ⭐️ 收藏,你的青睐是我努力的方向! ✏️ 评论,你的意见是我进步的财富! 服务器端编程 服务器端编程是一种计…...

Qwt QwtThermo绘制温度计
1.简介 QwtThermo 是一个基于 Qt 框架的类库,用于创建温度计控件。它提供了一些方便的功能来展示和处理温度计相关的数据。 QwtThermo 添加了特定于温度计的功能。 使用 QwtThermo,可以实现以下功能: 设置温度范围:可以通过设置…...

U_boot介绍
系统移植之前的了解的: 首先需要移植一个 bootloader 代码,这个 bootloader 代码用于启动 Linux 内核,bootloader 有很多,常用的就是 U-Boot;移植好 U-Boot 以后再移植 Linux 内核,移植完 Linux 内核以后 Linux 还不能…...
Flink -- window(窗口)
1、窗口主要分成三大种: 1、Time Window (时间窗口):固定时间触发一次窗口 a、SlidingEventTimeWindows: 滑动的事件时间窗口 public class Demo1TImeWindow {public static void main(String[] args) throws Exception {/*** 时…...

原语:串并转换器
串并转换器OSERDESE2 可被Select IO IP核调用。 OSERDESE2允许DDR功能 参考: FPGA原语学习与整理第二弹,OSERDESE2串并转换器 - 知乎 (zhihu.com) 正点原子。 ISERDESE2原语和OSERDESE2原语是串并转换器,他的的功能都是实现串行数据和并行…...

没网络也能安装.Net 3.5!如何脱机安装.NET Framework 3.5
.NET框架是由微软制定的一个软件框架。它有助于在Windows上运行控制台、Web或移动应用程序。此有用的工具适用于Windows设备。 如何脱机安装.NET Framework 3.5 如果你拥有Windows 10、8、8.1或7,有时第三方软件可能会导致问题。你可能会在图片中看到这样的问题。 看这张照片…...

JVM运行时数据区-虚拟机栈
目录 一、内存中的栈 二、基本内容 三、优点 四、栈的存储单位 五、栈运行原理 六、栈的内部结构 (一)局部变量表 (二)操作数栈 (三)动态链接 (四)方法返回地址 …...
Java中介者模式
目录 定义 结构 案例 优点 缺点 使用场景 定义 又叫调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。 结构 中介者模式包含以下主要角色: 抽象中介者角…...

前端框架Vue学习 ——(五)前端工程化Vue-cli脚手架
文章目录 Vue-cliVue项目-创建Vue项目-目录结构Vue项目-启动Vue项目-配置端口Vue项目开发流程 Vue-cli 介绍:Vue-cli 是 Vue 官方提供的一个脚手架,用于快速生成一个 Vue 的项目模版 安装 NodeJS安装 Vue-cli npm install -g vue/cliVue项目-创建 图…...

App备案-iOS云管理式证书 Distribution Managed 公钥及证书SHA-1指纹的获取方法
根据近日工业和信息化部发布的《工业和信息化部关于开展移动互联网应用程序备案工作的通知》,相信不少要进行IOS平台App备案的朋友遇到了一个问题,就是apple不提供云管理式证书的下载,也就无法获取公钥及证书SHA-1指纹。 已经上架的应用不想重…...
Spring -Spring之依赖注入源码解析
依赖注入底层原理流程图:Spring中Bean的依赖注入原理| ProcessOn免费在线作图,在线流程图,在线思维导图 Spring中到底有几种依赖注入的方式? 首先分两种: 手动注入自动注入 手动注入 在XML中定义Bean时,就是手动注入…...

Spire.Office for .NET 8.10.2 同步更新-Crk
Spire.Office for .NET是 E-iceblue 提供的企业级 Office .NET API 的组合。它包括Spire.Doc、Spire.XLS、Spire.Spreadsheet、Spire.Presentation、Spire.PDF、Spire.DataExport、Spire.OfficeViewer、Spire.PDFViewer、Spire.DocViewer、Spire.Barcode和Spire.Email。Spire.O…...

MFC 基础篇(一)
目录 一.SDK编程 二.为什么要学MFC? 三.MFC能做什么? 四.MFC开发环境搭建 五.MFC项目创建 六.消息映射机制 一.SDK编程 Application Programming Interface 应用程序编程接口。 Software Development Kit 软件开发工具包,一般会包括A…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...