如何使用ListView实现一个带有网络请求,解析,分页,缓存的公共的List页面来大大的提高工作效率

在平常的开发中经常会有很多列表页面,每做一个列表页就需要创建这个布局文件那个Adapter适配器文件等等一大堆与之相关的附属的不必要的冗余文件。如果版本更新迭代比较频繁,如此以往,就会使项目工程变得无比庞大臃肿。

如果看过这篇文章或者在使用过这种方式之后呢,所有的工作都可以被压缩成只有两个文件,一个JAVA文件一个XML布局文件。而且代码还少少的。


咱们来看看实际情况:

平常的一个列表页面的生成需要以下文件:

  • 一个Activity文件,有时候可能还会忘记注册
  • 一个包含上下拉刷新控件以及无数据时提示的布局文件
  • 一个Listview的item的布局文件
  • 一个Adapter适配器文件
  • 一个需要被解析的Bean文件

当然在Activity中还需要处理以下功能:
  • 数据解析
  • 分页加载
  • 数据缓存
  • 网络请求
当然,以上功能可以通过频繁的复制粘贴来实现,但是这会给以后的维护留下不少不小的坑,比如突然需要更换Listview为Recyclerview,你是不是顿时就想哭了呢?是不是就得一个个文件去改呢?现在不用了,改俩地方就行了。

现在你可能想知道一个公共的List页有什么特点呢?
  • 无需再关心网络请求、数据解析、分页、缓存等相同的功能
  • 不需要写那么多的相同的布局文件,只用写那些不同的item布局文件就可以,只需要关心你关心的
  • 只会有一个Adapter适配器,一个ViewHolder存在,Activity也可以只有一个
  • 可复用性超强,无论是Activity中展示,还是在被要求放在ViewPager中显示都没问题
  • 大大减小项目的工程文件数量,提高编译速度,不用再把一天的时间都浪费在编译时间上
  • 提高你的工作效率,不用再复制粘贴,那个时间没有这个快,只用实现你的getView方法就可以
  • 减少维护成本,如果某一天需要在网络请求加上某个参数,以前的方法需要改无数个地方,而现在只用改一个地方就OK,如果如探需要更改上下拉刷新控件,比如需要将XListView改成PullToRefreshListView,你是不是就苦逼了?很多地方都需要跟着改,现在不用了,只用动一个地方全都OK
  • 还有很多我一时间想不起来等你去发掘的功能

好,BB了这么多,到底是怎么实现和怎么使用呢?容我慢慢道来:

好,先来看看使用起来有多便捷:
/*** 示例代码,将关键的部分放在fragment中,无论是viewpager还是Activity,还是其它容器,都可以将fragment嵌入其中显示* * @author Sahadev**/
public class ExampleFragment extends SuperAbstListFragment<ExampleBean> {public static AbstListFragment getInstance(String requestUrl) {AbstListFragment fragment = new ExampleFragment();Bundle bundle = new Bundle();bundle.putString(AbstListFragment.URL, requestUrl);fragment.setArguments(bundle);return fragment;}@Overridepublic Type getInstanceType() {// 返回需要实例化的对象类型return new TypeToken<List<ExampleBean>>() {}.getType();}/*** 需要实例化的类,这里仅用一个属性做例子* * @author Work**/public static class ExampleBean implements Serializable {/*** */private static final long serialVersionUID = 7624541082621792974L;@SerializedName("title")public String title;}//在这里完成数据绑定就可以了,支持链式调用@Overridepublic void setView(ViewHolder viewHolder, ExampleBean t) {viewHolder.setText(R.id.title, t.title);}@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {}
}


这是实际运行效果图:仅仅通过短短的几行代码就可以实现强大的功能,是不是很方便?


好,效果先看到了,接下来描述一下是如何完成这么多功能的:
当然,子类写的代码少,那说明父类已经帮它完成了不少功能,所以咱们先看看整体的目录结构:


这个图可能画的有些毛糙,还是再用小文来简述一下,BaseFragment含有一些基本的功能,比如快速弹出一个toast,显示一个等待对话框等待,它还有子类常用的一些属性,activity,LayoutInflater,ImageLoader 等等:
/*** 基本类,提供一些常用的基本的方法属性供子类使用* * @author Sahadev**/
public class BaseFragment extends Fragment {/*** 图片加载工具*/protected ImageLoader mImageLoader;/*** 等待对话框*/private LoadingDialog mLoadingDialog;/*** 布局填充器*/protected LayoutInflater mInflater;/*** context*/protected Activity mContext;@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);mContext = activity;mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);}@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);// 在此处初始化mImageLoader,mLoadingDialog等属性mLoadingDialog = LoadingDialog.getInstance(mContext);// imageLoader属性可在自定义的Application中设置全局的单例,由自定义Application暴露接口获取单例,比如// mImageLoader = CustomApplication.getImageLoaderInstance();}/*** 吐司* * @param message*/protected void toast(String message) {Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();}/*** 显示等待对话框,显示默认文本*/protected void showLoadingDialog() {if (mLoadingDialog != null) {mLoadingDialog.show();}}/*** 显示等待对话框,显示传入的文本* * @param message*/public void showLoadingDialog(String message) {if (mLoadingDialog != null) {mLoadingDialog.setMessage(message);mLoadingDialog.show();}}/*** 关闭等待对话框*/protected void dismissLoadingDialog() {if (mLoadingDialog != null) {mLoadingDialog.dismiss();}}@Overridepublic void onDestroy() {super.onDestroy();dismissLoadingDialog();}}

AbstListFragment则是咱们项目的关键部分了,它集成了界面生成、空数据展示界面、网络请求及分页请求,网络请求回调,item点击回调,界面主动刷新广播接收器等功能,
可以使用户自己定义适配器:
/*** 含有ListView的Fragment* 抽取公共的含有ListView的Fragment,此Fragment已经包括基本的下拉刷新,网络加载,分页加载等公共功能,只需要关心实现 推荐使用* {@link #SuperAbstListFragment}实例化子类方式参见{@link #ExampleFragment}* * @author Sahadev* */
public abstract class AbstListFragment extends BaseFragment implements OnItemClickListener, OnClickListener,Listener<JSONObject>, ErrorListener, OnRefreshListener2<ListView> {protected PullToRefreshListView mListView;protected ImageView emptyView;private AnimationDrawable rocketAnimation;private View rootView;protected int page = 0;public static final String URL = "ABST_LIST_FRAGMENT_URL";public static final String NEED_REFRESH_BROADCAST_RECEIVER = "NEED_REFRESH_BROADCAST_RECEIVER";/*** 请求的链接地址*/protected String requestUrl;/*** 由子类实现,安全传参* * @param requestUrl* @return*/public static AbstListFragment getInstance(String requestUrl) {return null;}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {if (rootView == null) {rootView = inflater.inflate(R.layout.activity_list_layout, container, false);emptyView = (ImageView) rootView.findViewById(R.id.empty_view);mListView = (PullToRefreshListView) rootView.findViewById(R.id.list);mListView.setEmptyView(emptyView);mListView.getRefreshableView().setLayoutTransition(new LayoutTransition());mListView.setOnRefreshListener(this);mListView.setOnItemClickListener(this);mListView.getRefreshableView().setOnItemClickListener(this);emptyView.setOnClickListener(this);Bundle bundle = getArguments();if (bundle != null) {requestUrl = getArguments().getString(AbstListFragment.URL);}}ViewGroup parent = (ViewGroup) rootView.getParent();if (parent != null) {parent.removeView(rootView);}return rootView;}@Overridepublic void onStart() {super.onStart();if (mListView != null) {mListView.setRefreshing(false);}}@Overridepublic void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) {page = 0;getData(requestUrl + "&p=" + page);// 这里可以添加分页和其它请求服务器所需要的必要参数,比如token或者其它什么的,所以在传入的地方只用传入必要的参数就OK}@Overridepublic void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) {page++;getData(requestUrl + "&p=" + page);}protected void getData(String requestUrl) {if (isNeedLoadDataFromNet()) {if (page == 0) {// 可以在这里设置加载动画emptyView.setImageResource(R.drawable.loading_animation);// R.drawable.loading_animation代表动画资源rocketAnimation = (AnimationDrawable) emptyView.getDrawable();rocketAnimation.start();}RequestUtils.requesGet(requestUrl, this, this);}}/*** 这个方法用于返回是否是从网络加载,有些数据是需要从本地加载的,这个 方法就可以由子类来控制具体是什么* * @return*/protected boolean isNeedLoadDataFromNet() {return true;}@Overridepublic void onResponse(JSONObject response) {// 设置请求完毕之后的状态rocketAnimation.stop();emptyView.setImageResource(R.drawable.nocontent);mListView.onRefreshComplete();}@Overridepublic void onErrorResponse(VolleyError error) {// 设置请求完毕之后的状态rocketAnimation.stop();emptyView.setImageResource(R.drawable.nocontent);toast("咦?网络状况貌似出了点问题.");mListView.onRefreshComplete();}@Overridepublic void onClick(View v) {switch (v.getId()) {// 当点击无数据提示的时候重新加载case R.id.empty_view:mListView.setRefreshing();break;default:break;}}private BroadcastReceiver receiver;@Overridepublic void onResume() {super.onResume();receiver = new NeedRefreshBroadcastReceiver();IntentFilter filter = new IntentFilter(NEED_REFRESH_BROADCAST_RECEIVER);filter.addCategory(Intent.CATEGORY_DEFAULT);mContext.registerReceiver(receiver, filter);}@Overridepublic void onPause() {super.onPause();mContext.unregisterReceiver(receiver);}/*** 主动刷新广播接收器,当数据发生改变的时候(比如添加或者删除)主动刷新* * @author Work**/private class NeedRefreshBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {mListView.setCurrentMode(Mode.PULL_FROM_START);mListView.setRefreshing(false);}}}

SuperAbstListFragment<T> 是对父类AbstListFragment的进一步抽象,它里面集成了一个适配器与一个万能的ViewHolder,使子类只用
实现几个基本的方法就可以,比如要解析的类型、当item点击之后的处理方式、数据与界面如何绑定等等,来看看这个
类都有什么:

/*** 抽象的AbstListFragment中间层,具有更强大的功能* * @author Work**/
public abstract class SuperAbstListFragment<T> extends AbstListFragment {protected AbstBaseAdapter<T> adapter;@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);try {// 如果有些Adapter中不满足实际情况的话,可以使用反射来实例化// adapter = (AbstBaseAdapter<T>)// getAdapterClass().getConstructor(Context.class).newInstance(mContext);adapter = new SuperAdapter(mContext);mListView.setAdapter(adapter);} catch (IllegalArgumentException e) {e.printStackTrace();}}/*** 万能适配器,它只是个中间件* * @author Work**/public class SuperAdapter extends AbstBaseAdapter<T> {public SuperAdapter(Context context) {super(context);}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return SuperAbstListFragment.this.getView(position, convertView, parent);}}/*** * * @param position* @param convertView* @param parent* @return*/public View getView(int position, View convertView, ViewGroup parent) {// 这里使用的是万能的ViewHolderViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent, R.layout.fragment_list_item, position);// 这一行可以进一步的抽取到父类中T t = adapter.getData().get(position);setView(viewHolder, t);return viewHolder.getConvertView();}/*** 绑定数据,使用户真正关心的只有他们想要关心的* * @param viewHolder* @param t*/public abstract void setView(ViewHolder viewHolder, T t);/*** 如果单单的getView方法不满足需求的话,可以通过自定义Adapter的方法来实现,该方法用来返回需要实例化的Adapter的类名* * @return*/public Class<?> getAdapterClass() {return null;}/*** 需要解析的数据类型是一个对象还是对象的集合,由这个返回* * @return*/public abstract Type getInstanceType();/** (non-Javadoc)* * @see* com.sahadev.general_assembly.base.AbstListFragment#onResponse(org.json* .JSONObject) 当网络请求成功之后回调该方法,开始解析数据*/@Overridepublic void onResponse(JSONObject response) {super.onResponse(response);if (response != null && response.optBoolean("success")) {Gson gson = new Gson();List<T> datas = gson.fromJson(response.optJSONArray("data").toString(), getInstanceType());initAdapter(datas);}}/*** 数据解析完毕之后刷新数据* * @param list*/protected void initAdapter(List<T> list) {if (page == 0) {adapter.addFirstPageData(list);} else {adapter.addOtherPageData(list);}}}


通过以上几个类的不断抽取,当最后在使用的时候,实现类只用简单的几行代码就可以完成很多很多的功能,怎么样,是不是很简单?

接下来简单介绍一下如何在各种页面只用一个Activity来装载不同页面的Fragment呢:
/*** 含有ListFragment的Activity* * @author 尚斌* */
public class IncludeListFragmentActivity extends FragmentActivity {private String mFragmentClass = "x.x.x.x.x.x";private String mRequestUrl = "http://www.baidu.com";private String title = "标题未定义";public static final String TITLE = "TITLE";public static final String CLASS = "CLASS";public static final String URL = "URL";/*** @param context* @param fragmentClass*            需要实例化的Fragment的包名* @param requestUrl*            该Fragment内部的请求地址* @return*/public static Intent getIntent(Context context, String fragmentClass, String requestUrl, String title) {Intent intent = new Intent(context, IncludeListFragmentActivity.class);Bundle bundle = new Bundle();bundle.putString(TITLE, title);bundle.putString(CLASS, fragmentClass);bundle.putString(URL, requestUrl);intent.putExtras(bundle);return intent;}@SuppressWarnings("unchecked")@Overrideprotected void onCreate(Bundle savedInstanceState) {requestWindowFeature(Window.FEATURE_NO_TITLE);super.onCreate(savedInstanceState);Intent intent = getIntent();Bundle bundle = intent.getExtras();mFragmentClass = bundle.getString(CLASS);mRequestUrl = bundle.getString(URL);title = bundle.getString(TITLE);// 设置标题setTitle(title);// 设置布局文件setContentView(R.layout.activity_include_list_fragment);try {Class<BaseFragment> newInstance = (Class<BaseFragment>) Class.forName(mFragmentClass);Method method = null;BaseFragment fragment = null;method = newInstance.getMethod("getInstance", String.class);fragment = (BaseFragment) method.invoke(null, mRequestUrl);if (fragment != null) {getSupportFragmentManager().beginTransaction().add(R.id.container, fragment).commit();} else {throw new Exception("You must be have a named getInstance method!");}} catch (Exception e) {e.printStackTrace();}}

就是这个文件,可以通过传入的标题,需要实现的Fragment类,需要请求的地址来生成多种多样的界面,所以在实现子类的时候每个子类都需要重写public static AbstListFragment getInstance(String requestUrl) 方法以供外部可以调用到它。

说了这么多,在这里面其实是没有缓存的,其实这个公共的项目与缓存关系是不大的,既然提到就说一下是怎么实现的,在项目开发的时候很多时候都用到了第三方网络框架,也是有源码的,这里就用Volley举个栗子:
在Volley请求的时候,在请求的基类方法中,根据请求的URL去数据库中寻找,数据库这里推荐使用xUtils提供的数据库存储,如果没找到,则调用网络请求,在网络请求成功回调的部分将请求的数据存入数据库,以便第二次查找,基本思路就是这样:
使用代码举例:
网络请求部分:
	public JsonRequest(int method, String url, Map<String, String> body, Listener<T> listener,ErrorListener errorListener, boolean isNeedCache, Type type) {super(method, url + "&token=token" + "&vid=vid"), errorListener);mListener = listener;mRequestBody = null;mType = type;if (isNeedCache && !(检查网络是否可用)) {url += "&token=token" + "&vid=vid";try {//使用自定义的方式去数据库中查找,这里使用的是xUtils举例:List<Cache> datas = xUtils.getInstance().getDbUtils().findAll(Selector.from(Cache.class).where("requestUrl", "=", url).orderBy("time", false).limit(1));if (!netAccessed && datas != null & listener != null) {for (Cache cache : datas) {//如果查找成功就进行回调listener.onResponse((T) new JSONObject(cache.jsonString));}}} catch (DbException e) {e.printStackTrace();} catch (JSONException e) {e.printStackTrace();}}bodyMap = body;}
网络回调部分,将服务器数据存储:
@Overrideprotected void deliverResponse(final T response) {if (response != null&& (response.getClass().equals(String.class) || response.getClass().equals(JSONObject.class))) {new Thread(new Runnable() {@Overridepublic void run() {Cache cache = new Cache(mUrl, response.toString());try {//使用xUtils进行存储xUtils.getInstance().getDbUtils().save(cache);} catch (DbException e) {e.printStackTrace();}}}).start();}netAccessed = true;if (mListener != null && (如果网络可用)) {if (mType != null) {try {String simString1 = response.getClass().getName();String simString2 = mType.toString();//有多种类型回调,如果只是回调String类,则调用以下if (simString2.contains(simString1)) {mListener.onResponse(response);} else {mListener.onResponse(null);}} catch (Exception e1) {}} else {//还有一种是JsonObject类型,则调用以下mListener.onResponse(response);}}}
大伙可能实际情况不是这个样子,但是思路可能差不多,仅供参考。

当然,在该项目中还集成了不少别的基本的东西,比如ImageLoader图片加载,Volley请求工具,json解析工具等,如果是作为一个新项目的话,本项目还是可以作为一个最基本的起始项目来用用。

项目地址在这里:https://git.oschina.net/sahadev/General-Assembly
项目是一个开源项目,迫切的想要更多的人可以加入进来,将自己工作中可以提高工作效率的知识和成果分享出来,出一份力。如果想加入 请联系我:sahadev@foxmail.com,希望可以一起发展壮大,拥有很多为大家减轻负担的成果。



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

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

相关文章

从信息检索顶会CIKM'20看搜索、推荐与计算广告新进展

文 | 谷育龙Eric源 | 搜索推荐广告排序艺术我是谷育龙Eric&#xff0c;研究方向有深度学习、搜索推荐&#xff0c;喜欢为大家分享深度学习在搜索推荐广告排序应用的文章。CIKM作为信息检索、数据挖掘等领域的国际一流会议&#xff0c;每年都有很多搜索推荐广告领域的精彩论文。…

复杂风控场景下,如何打造一款高效的规则引擎

| 在互联网时代&#xff0c;安全已经成为企业的命脉。美团信息安全团队需要采用各种措施和手段来保障业务安全&#xff0c;从而确保美团平台上的用户和商户利益不会受到侵害。 本文主要介绍了美团在打造自有规则引擎Zeus&#xff08;中文名“宙斯”&#xff09;的过程中&#x…

Android消息队列图片记录

很早之前为了给学生讲明白整个消息队列是怎么个情况&#xff0c;于是大概阅读了一下消息队列的整个工作过程&#xff0c;鉴于网上大部分都是文字说明&#xff0c;没有一个图例&#xff0c;于是做出了下面这张图&#xff0c;权当作以后复习之用&#xff0c;也供大家学习参考&…

Git使用教程:最详细、最傻瓜、最浅显、真正手把手教!

原文连接&#xff1a;https://blog.csdn.net/u011535541/article/details/83379151 转载自 Git使用教程 预警&#xff1a;因为详细&#xff0c;所以行文有些长&#xff0c;新手边看边操作效果出乎你的预料&#xff09;一&#xff1a;Git是什么&#xff1f; Git是目前世界上最先…

主动学习入门篇:什么是主动学习?有哪些具体应用

文 | 淘系技术部 初类来源 | 知乎在大数据和算力的助力下&#xff0c;深度学习掀起了一波浪潮&#xff0c;在许多领域取得了显著的成绩。以监督学习为主的深度学习方法&#xff0c;往往期望能够拥有大量的标注样本进行训练&#xff0c;模型能够学到更多有价值的知识&#xff08…

LeetCode 59. 螺旋矩阵 II LeetCode 54. 螺旋矩阵

文章目录1. 题目信息2. LeetCode 59 解题3. LeetCode 54. 螺旋矩阵4.《剑指Offer》面试题291. 题目信息 给定一个正整数 n&#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的正方形矩阵。 示例:输入: 3 输出: [[ 1, 2, 3 ],[ 8, 9, 4 ],[ 7…

如何查看Activity任务栈以及dumpsys_activity命令的简要使用及介绍

今天看到淘宝客户端的某个页面效果&#xff0c;效果是在两个Activity中做动画&#xff0c;为了知道究竟是不是在同一个Activity中做的效果&#xff0c;就必须采取一种手段来知道是不是同一个Activity.描述一下这个动画效果&#xff1a;列表页面点击图片&#xff0c;图片会滑动到…

论文浅尝 | 基于微量资源的神经网络跨语言命名实体识别

论文笔记整理&#xff1a;谭亦鸣&#xff0c;东南大学博士生&#xff0c;研究方向为跨语言知识图谱问答。来源&#xff1a;EMNLP 2018链接&#xff1a;https://www.aclweb.org/anthology/D18-1034问题背景与动机本文关注小语种/资源匮乏语言的跨语言命名实体识别问题&#xff0…

美团命名服务的挑战与演进

| 本文根据美团基础架构部技术专家舒超在2019 ArchSummit&#xff08;全球架构师峰会&#xff09;上的演讲内容整理而成。 命名服务主要解决微服务拆分后带来的服务发现、路由隔离等需求&#xff0c;是服务治理的基石。美团命名服务&#xff08;以下简称MNS&#xff09;作为服务…

NeurIPS 2020 | 自步对比学习:充分挖掘无监督学习样本

文 | 葛艺潇源 | PaperWeekly本文介绍一篇我们发表于 NeurIPS-2020 的论文《Self-paced Contrastive Learning with Hybrid Memory for Domain Adaptive Object Re-ID》&#xff0c;该工作提出自步对比学习框架及混合记忆模型&#xff0c;旨在解决无监督及领域自适应表征学习中…

Postman安装与使用

原文链接&#xff1a;https://blog.csdn.net/fxbin123/article/details/80428216 一、Postman背景介绍 用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的&#xff0c;用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具。…

LeetCode 35. 搜索插入位置(二分查找)

文章目录1. 题目信息2. 解题2.1 暴力遍历2.2 二分查找1. 题目信息 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 你可以假设数组中无重复元素。 示例 1:输入…

青年人在美团是怎样成长的?

2020年五四青年节&#xff0c;我们采访了美团技术团队9位青年代表&#xff0c;他们是来自清华大学、北京大学、中国科学院大学等国内高校的2位博士研究生和7位硕士研究生。在这个属于青年人的特别的日子里&#xff0c;我们请他们分享了自己在美团成长的故事。 道阻且长&#xf…

它来了它来了!2020深度学习硬核技术干货集锦!

这份干货来自于今天要给大家推荐的一个深度学习与计算机视觉领域知名公众号&#xff1a;「极市平台」。从2016年创立至今&#xff0c;极市平台深耕于DL与CV领域&#xff0c;输出300篇高质量原创文章&#xff0c;并积累了近10万名海内外专业算法开发者。极市平台公众号坚持每日更…

容器的使用和创建虚拟环境 vitualenv

xshell jupter容器的使用方法 #容器相当于子服务器 1 创建指定python版本的虚拟环境 方法1&#xff1a; 1.安装虚拟环境的第三方包 venv pip install venv 2.创建虚拟环境 cd 到存放虚拟环境的地址 在当前目录下创建名为env的虚拟环境&#xff1a; python -m venv env python…

Android中动态的更改selector中某张图片的属性

在我们平常开发的时候会有许多状态按钮&#xff0c;比如state_pressed&#xff0c;android:state_checked&#xff0c;或者就正常状态等等&#xff0c;我们做这样的效果通常需要三个文件&#xff0c;一张是按下的图片&#xff0c;一张是正常状态的图片&#xff0c;一张是管理它…

LeetCode 17. 电话号码的字母组合(回溯)

文章目录1. 题目信息2. 解题1. 题目信息 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例:输入&#xff1a;"23" 输出&#xff1a;[&…

细数一行代码改变结局的炼丹骚操作

文 | 陀飞轮&圈圈&年年的铲屎官源 | 知乎tips总结知乎答主&#xff1a;陀飞轮谈一下自己知道的。尽量避开优化器、激活函数、数据增强等改进。。先上完整列表&#xff1a;Deep Learning: Cyclic LR、FloodingImage classification: ResNet、GN、Label Smoothing、Shuff…

推荐收藏 | 美团技术团队的书单

4月23日对于世界文学而言是一个具有象征性意义的日子。1616年的这一天&#xff0c;塞万提斯、莎士比亚、印卡加西拉索德拉维加几位大师相继与世长辞。此外&#xff0c;这一天也是其他一些著名作家的出生和去世的日期&#xff0c;例如&#xff1a;莫里斯德吕翁、哈尔多尔K拉克斯…

论文浅尝 | 采用多层注意力机制的事件检测

笔记整理&#xff1a;杨帆&#xff0c;浙江大学计算机学院硕士&#xff0c;研究方向知识图谱。动机事件编码&#xff08;event encoding&#xff09;之前的工作集中在提取实体&#xff0c;检测触发单词以及匹配预定义的模板&#xff0c;这些方法存在以下缺点&#xff1a;首先它…