目录
第一节: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是support-v7包中的新组件,与经典的ListView相比,同样拥有item回收复用的功能。
RecyclerView是ListView的升级版,有如下优点:
(一)RecyclerView封装了ViewHolder的回收复用
(二)提供了一种插拔式的体验,高度的解耦,异常的灵活,内置了三种LayoutManager:
(三)可以控制Item增删的动画,并支持自定义动画
在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'
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);
}
}
}
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
layoutManager.setOrientation(RecyclerView.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
//设置RecyclerView的配器
mAdapter = new MyRecyclerViewAdapter(this);
mRecyclerView.setAdapter(mAdapter);
由于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();
}
});
//切换布局
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);
}
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全称是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代码嵌入式平台移植性好
• 方便使用各种开源库
缺点:
• 调用步骤繁琐
• 互调过程开销较大
• 需要处理资源分配与释放
• 要了解的知识更多
使用场景:
1、下载NDK
2、命令行:vi ~/.bash_profile
添加一行:export NDK_ROOT="~/...(ndk路径)"
在export PATH="..."中加入:$NDK_ROOT
3、source ~/.bash_profile,使配置生效。
电脑--右键--属性--高级系统设置--环境变量--在系统变量中新建(变量名:NDK_ROOT;变量值:ndk路径)--Path中添加NDK_ROOT
注:ndk使用命令行操作比较方便,cygwin是window下模拟unix的一个工具,推荐使用cygwin操作。
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