Android数据通信开发与应用(四):实战开发
目录
第一节:RecyclerView列表流行控件
一、RecyclerView是什么
二、RecyclerView的优点
三、编写一个简单的RecyclerView
1、导入RecyclerView依赖包
2、添加RecyclerView控件
3、创建item的布局文件item_layout.xml
4、创建适配器,这里使用了Gilde需要导包。
5、为RecyclerView设置LayoutManager
6、创建适配器实例,并设置给RecyclerView
7、为RecyclerView添加点击事件。
8、切换布局,三种布局循环切换。
9、插入、删除item,并设置动画:
第二节:NDK入门
一、NDK简介
二、优缺点及使用场景
三、NDK的配置
Mac/Linux配置
Windows配置
Android Studio的配置
第三节:实战:有声阅读器
第四节:扩展学习--GIF介绍
第一节:RecyclerView列表流行控件
一、RecyclerView是什么
RecyclerView是support-v7包中的新组件,与经典的ListView相比,同样拥有item回收复用的功能。
二、RecyclerView的优点
RecyclerView是ListView的升级版,有如下优点:
(一)RecyclerView封装了ViewHolder的回收复用
(二)提供了一种插拔式的体验,高度的解耦,异常的灵活,内置了三种LayoutManager:
- LinearLayoutManager--横向或纵向滑动的列表
- GridLayoutManager--类似于GridView的效果
- StaggeredGridLayoutManager--可以实现瀑布流的效果
(三)可以控制Item增删的动画,并支持自定义动画
三、编写一个简单的RecyclerView
1、导入RecyclerView依赖包
在build.gradle中添加
implementation 'com.android.support:appcompat-v7:28.+'implementation 'com.android.support:recyclerview-v7:28.+'//注意recyclerview的版本号必须与appcompat版本号一致
*补充内容,如果Androidx则只需要导包:
implementation 'com.google.android.material:material:1.0.0'
2、添加RecyclerView控件
3、创建item的布局文件item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
4、创建适配器,这里使用了Gilde需要导包。
implementation "com.github.bumptech.glide:glide:4.9.0"
public class MyRecyclerViewAdapter extends RecyclerView.Adapter { private Context mContext; private List mLists; public MyRecyclerViewAdapter(Context mContext) { this.mContext = mContext; this.mLists = new ArrayList<>(); } public void setDataSource(List dataSource) { mLists = dataSource; notifyDataSetChanged(); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.item_layout, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { //绑定数据 holder.mTitle.setText(mLists.get(position)); Glide.with(mContext).load(getIcon(position)).into(holder.mIcon); } @Override public int getItemCount() { return mLists.size(); } private int getIcon(int position) { switch (position % 5) { case 0: return R.drawable.a; case 1: return R.drawable.b; case 2: return R.drawable.c; case 3: return R.drawable.d; case 4: return R.drawable.e; default: return R.drawable.tree; } } class ViewHolder extends RecyclerView.ViewHolder { public View mItemView; public ImageView mIcon; public TextView mTitle; public ViewHolder(@NonNull View itemView) { super(itemView); mItemView = itemView; mIcon = itemView.findViewById(R.id.iv_icon); mTitle = itemView.findViewById(R.id.tv_title); } }}
5、为RecyclerView设置LayoutManager
LinearLayoutManager layoutManager=new LinearLayoutManager(this); layoutManager.setOrientation(RecyclerView.VERTICAL); mRecyclerView.setLayoutManager(layoutManager);
6、创建适配器实例,并设置给RecyclerView
//设置RecyclerView的配器 mAdapter = new MyRecyclerViewAdapter(this); mRecyclerView.setAdapter(mAdapter);
7、为RecyclerView添加点击事件。
由于RecyclerView本身并没有提供item点击事件,所以需要在Adapter中手动添加
1)第一种方式(高耦合):直接在Viewholder内部类中,或者onBindViewHolder方法中添加点击事件
在ViewHolder类中添加点击事件,需要使用getAdapterPotion()或者getLayoutPosition()获取item位置:
class ViewHolder extends RecyclerView.ViewHolder { public View mItemView; public ImageView mIcon; public TextView mTitle; public ViewHolder(@NonNull View itemView) { super(itemView); mItemView = itemView; mIcon = itemView.findViewById(R.id.iv_icon); mTitle = itemView.findViewById(R.id.tv_title); mItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, "点击了"+getAdapterPosition(), Toast.LENGTH_SHORT).show(); } }); } }
或者onBindViewHOlder方法中添加点击事件,可以直接通过position参数获得item位置:
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { //绑定数据 holder.mTitle.setText(mLists.get(position)); Glide.with(mContext).load(getIcon(position)).into(holder.mIcon); holder.mItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, "点击了"+position, Toast.LENGTH_SHORT).show(); } }); }
2)第二种方式(低耦合):在Adapter中自定义接口实现点击事件
private OnItemClickListener mOnItemClickListener; public void setOnItemClickListener(OnItemClickListener onItemClickListener) { mOnItemClickListener = onItemClickListener; } //定义接口 interface OnItemClickListener { void onItemClick(int position); } ... public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { ... //Item点击事件 holder.mItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mOnItemClickListener != null) { mOnItemClickListener.onItemClick(position); } } }); }
实现接口:
//item点击事件 mAdapter.setOnItemClickListener(new MyRecyclerViewAdapter.OnItemClickListener() { @Override public void onItemClick(int position) { Toast.makeText(MainActivity.this, "第"+position+"数据被点击", Toast.LENGTH_SHORT).show(); } });
8、切换布局,三种布局循环切换。
//切换布局 mBtnChangeLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //利用反射获取布局 if (mRecyclerView.getLayoutManager().getClass() == LinearLayoutManager.class) { GridLayoutManager gridLayoutManager = new GridLayoutManager(MainActivity.this, 2); mRecyclerView.setLayoutManager(gridLayoutManager); } else if (mRecyclerView.getLayoutManager().getClass() == GridLayoutManager.class) { StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(staggeredGridLayoutManager); }else{ LinearLayoutManager layoutManager=new LinearLayoutManager(MainActivity.this); layoutManager.setOrientation(RecyclerView.VERTICAL); mRecyclerView.setLayoutManager(layoutManager); } } });
在onBindViewHolder方法中,为瀑布流布局设置随机高度:
//设置瀑布流布局随机高度 if (mRecyclerView.getLayoutManager().getClass() == StaggeredGridLayoutManager.class) { ViewGroup.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getRandomHeight()); holder.mIcon.setLayoutParams(params); } else { LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(80, 80); holder.mIcon.setLayoutParams(params); }... private int getRandomHeight() { return (int) (Math.random() * 1000); }
9、插入、删除item,并设置动画:
public void insertData(int position) { mInsertPosition = position; mLists.add(position, "插入的数据"); //直接刷新数据,无动画 //notifyDataSetChanged(); //显示插入动画,后面数据的位置不改变,需要手动调用notifyItemRangeChanged更改 notifyItemInserted(position); //刷新item notifyItemRangeChanged(position, mLists.size() - position); } public void removeData(int position) { mInsertPosition = -1; mLists.remove(position); //直接刷新数据,无动画 //notifyDataSetChanged(); //显示插入动画,后面数据的位置不改变,需要手动调用notifyItemRangeChanged更改 notifyItemRemoved(position); //刷新item notifyItemRangeChanged(position, mLists.size() - position); }
为新插入的item设置单独的背景色
//为插入的数据设置不同的背景色 if (position == mInsertPosition) { holder.mItemView.setBackgroundColor(Color.RED); } else { holder.mItemView.setBackgroundColor(Color.parseColor("#bbeedd")); }
第二节:NDK入门
一、NDK简介
官方解释:NDK全称是Native Development Kit。NDK是一套允许开发人员将本地代码嵌入Android 应用程序包,可以将Android应用程序中的部分功能用C/C++语言来实现,并将这部分C/C++代码编译成可直接运行在Android平台上的本地代码。这些本地代码以so链接库的形式存在,并能自动将so和java应用一起打包成apk。
通俗解释:NDK允许开发人员用C/C++开发Android程序。
复习:Android四层结构:APP;Framework;基础库、运行时;Linux内核
运行机制:
Java代码->Class文件->ByteCode->Dex(运行与App层)
C代码->.o目标文件->So链接库(运行于Linux内核层)
Jni:Dex中java代码直接调用so链接库。
二、优缺点及使用场景
优点:
• Native代码执行效率高
• 反编译难度大,保密性好
• 可以直接接触底层系统
• Native代码嵌入式平台移植性好
• 方便使用各种开源库
缺点:
• 调用步骤繁琐
• 互调过程开销较大
• 需要处理资源分配与释放
• 要了解的知识更多
使用场景:
- 编写 Android 驱动
- 对执行效率有高要求
- 对底层系统或一些Native开源库有依赖
- 代码保密性高
三、NDK的配置
Mac/Linux配置
1、下载NDK
2、命令行:vi ~/.bash_profile
添加一行:export NDK_ROOT="~/...(ndk路径)"
在export PATH="..."中加入:$NDK_ROOT
3、source ~/.bash_profile,使配置生效。
Windows配置
电脑--右键--属性--高级系统设置--环境变量--在系统变量中新建(变量名:NDK_ROOT;变量值:ndk路径)--Path中添加NDK_ROOT
注:ndk使用命令行操作比较方便,cygwin是window下模拟unix的一个工具,推荐使用cygwin操作。
Android Studio的配置
SDK Manager--SDK Tools:NDK前打钩;LLDB前打钩;
Project Structure--SDK location--Android SDK location:选择sdk路径(...SDK\ndk-bundle)
第三节:实战:有声阅读器
Live Template的使用:是一个预定义的代码模板,其中的内容能够根据上下文信息自动推断。AS提供了一些定义好的缩写,如
fori、Toast、todo、psfi等,用户也可以自定义代码模块,如:
单例模式实现:
private volatile static $className$ sInstance;public static $className$ getInstance() { if (sInstance == null) { synchronized ($className$.class) { if (sInstance == null) { sInstance = new $className$(); } } } return sInstance;}private $className$() {}
弱引用的静态handler
public static class MyHandler extends Handler{ public final WeakReference<$className$> mWeakReference; public MyHandler($className$ activity) { mWeakReference=new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); $className$ activity = mWeakReference.get(); if(msg.what==$code$){ if(activity!=null){ } } } }
*注: 使用 @SerializedName注解,可以解决Gson解析时名称必须相同的问题
*使用GsonFormat插件快速生成实体类
https://blog.csdn.net/zhang_zxk/article/details/84195784
第四节:扩展学习--GIF介绍
更多相关文章
- android监控SIM卡状态的广播示例代码
- Android(安卓)studio如何使用SVN进行版本控制?
- android Toast大全(五种情形)
- AndroidUI-TxetView嵌套Html的使用
- 在代码中实现按下Home键的效果
- android中设置控件边框以及如何保留上或下边框
- Android(安卓)瀑布流
- webView获取链接后的url和加载经过处理后的HTML
- 如何解决软键盘弹出引起的各种不适