前 言

App数据持久化功能是每个App必不可少的功能,而Android最常用的数据持久化方式主要有以下的五种方式:

  1. 使用SharedPreferences存储数据;
  2. 文件存储数据;
  3. SQLite数据库存储数据;
  4. 使用ContentProvider存储数据;
  5. 网络存储数据。

其中前四种都是缓存数据到本地,这篇主要讲的是使用第三种方式来实现App中的收藏功能,不过不用Android原生自带SQLite数据库来存储数据,而是使用第三方的Realm数据库来来存储数据。

Realm 本质上是一个嵌入式数据库,他并不是基于SQLite所构建的。它拥有自己的数据库存储引擎,可以高效且快速地完成数据库的构建操作。和SQLite不同的是,它允许你在持久层直接和数据对象工作。在它之上是一个函数式风格的查询api,众多的努力让它比传统的SQLite 操作更快 。

Realm不仅支持Android的接入,还支持IOS的接入。那么接下来就使用Realm数据库实现Android App中的收藏功能吧。

需求分析

要使用Realm数据库实现App中的收藏功能,需要实现以下几个功能和步骤:

  1. 在Android项目接入Realm数据库;
  2. 创建收藏数据库表;
  3. 实现对收藏数据库表进行增删查的操作;
  4. 数据库表增删查时界面实时渲染和更新。

接入Realm数据库

然后在AS的外层build.gradle里的buildscript.dependencies添加Realm数据库相关的依赖

buildscript { 
 dependencies {
 ...
 classpath "io.realm:realm-gradle-plugin:6.0.1"
 }
}

然后在AS的内层build.gradle里添加Realm数据库相关的依赖

在顶部 apply plugin: ‘com.android.application' 下添加 apply plugin: ‘realm-android' 的声明,如下图

在这里插入图片描述

在定义的Application里初始化数据库相关的配置(包括数据库名称和版本号,具体代码看Demo源码)

 /**
 * 数据库相关的配置
 *
 * @param context
 */
 private void initRealm(Context context) {
 try {
  Realm.init(context);
  RealmConfiguration config = new RealmConfiguration.Builder()
   .name(RealmConstant.REALM_DB_NAME)
   .schemaVersion(RealmConstant.REALM_DB_VERSION)
   .build();
  Realm.setDefaultConfiguration(config);
 } catch (Exception e) {
  e.printStackTrace();
 }
 }

创建收藏数据库表
首先先创建一张收藏数据库表,代码如下:

/**
 * 电影收藏数据库表名
 */
public class MovieCollectDBModel extends RealmObject {

 // 影视id,主键
 @Required
 @PrimaryKey
 @Index
 private String movieId;
 // 影视名称
 @Required
 private String movieName;
 // 影视海报、封面
 @Required
 private String poster;
 // 影视标签
 @Required
 private String movieLabel;
 // 影视类型
 @Required
 private String videoType;
 // 添加到数据的时间
 @Required
 private String createdTime;

 // 以下省略字段的 set 和 get
}

该类继承于Realm的RealmObject类,其中字段movieId作为该表的主键,也是数据在表里的唯一性。

收藏数据库表的增删查
添加影视数据到到数据库的操作(增)

 /**
 * 添加收藏数据到本地数据库
 *
 * @param mvId
 * @param mvName
 * @param movieImg
 * @param movieLabel
 * @param videoType
 */
 public void addCollectToDB(String mvId, String mvName, String movieImg, String movieLabel, String videoType) {

 MovieCollectDBModel movieCollectDBModel = new MovieCollectDBModel();
 movieCollectDBModel.setMovieId(mvId);
 movieCollectDBModel.setMovieName(mvName);
 movieCollectDBModel.setPoster(movieImg);
 movieCollectDBModel.setMovieLabel(movieLabel);
 movieCollectDBModel.setVideoType(videoType);
 movieCollectDBModel.setCreatedTime(BaseUtil.getNowDateTimeFormat());

 mTransaction = mRealm.executeTransactionAsync(new Realm.Transaction() {
  @Override
  public void execute(Realm realm) {
  realm.copyToRealmOrUpdate(movieCollectDBModel);
  }
 }, new Realm.Transaction.OnSuccess() {
  @Override
  public void onSuccess() {
  L.i("收藏数据添加成功!");
  ToastUtil.showToast(String.format("%s 已收藏", mvName));
  }
 }, new Realm.Transaction.OnError() {
  @Override
  public void onError(Throwable error) {
  L.i("收藏数据添加失败:"   error.toString());
  ToastUtil.showToast(String.format("%s 收藏失败", mvName));
  }
 });

 }

上面的代码是Realm数据插入数据到数据库的操作,这是一样异步插入数据的方式。在业务场景的需要,可以改新增和更新数据的插入方式,比如插入数据时如果数据库中已经存在了该数据则进行更新操作,否则进行了新增操作。

从数据库中删除一条影视数据的操作(删)

 /**
 * 通过键值对来删除指定收藏数据
 *
 * @param key
 * @param value
 */
 public void deleteByKeyCollectData(String key, String value) {

 RealmResults<MovieCollectDBModel> movieCollectDBModels = mRealm.where(MovieCollectDBModel.class)
  .equalTo(key, value)
  .findAllAsync();
 movieCollectDBModels.addChangeListener(new RealmChangeListener<RealmResults<MovieCollectDBModel>>() {
  @Override
  public void onChange(RealmResults<MovieCollectDBModel> movieCollectDBModels1) {
  if (movieCollectDBModels1.isEmpty()) return;
  mRealm.executeTransaction(new Realm.Transaction() {
   @Override
   public void execute(Realm realm) {
   movieCollectDBModels1.deleteFromRealm(0);
   }
  });
  }
 });
 }

从数据库中删除全部影视数据的操作(删)

 /**
 * 清除全部收藏的数据库内容
 */
 public void deleteAllCollectData() {

 RealmResults<MovieCollectDBModel> movieCollectDBModels = mRealm.where(MovieCollectDBModel.class)
  .findAll();
 mRealm.executeTransaction(new Realm.Transaction() {
  @Override
  public void execute(Realm realm) {
  if (movieCollectDBModels.isEmpty()) {
   ToastUtil.showToast("暂无收藏数据可删除");
   return;
  }
  movieCollectDBModels.deleteAllFromRealm();
  ToastUtil.showToast("收藏数据已全部清空");
  }
 });

 }

从数据库中查询全部影视数据的操作(查)

/**
 * 查询所有的收藏数据
 *
 * @param listener
 */
 public void queryAllCollectData(RealmChangeListener<RealmResults<MovieCollectDBModel>> listener) {
 RealmResults<MovieCollectDBModel> movieCollectDBModels = mRealm.where(MovieCollectDBModel.class)
  .sort("createdTime", Sort.DESCENDING)
  .findAllAsync();
 movieCollectDBModels.addChangeListener(listener);
 }

当前用户进入收藏界面的时候,需要从数据库中拉取全部的收藏数据,可以刚才添加收藏时间进行倒序排序。

数据库表增删查时界面的渲染和更新
当用户进入主页的时候,首次从网络获取数据,然后遍历一下网络获取数据是否已经有数据操作收藏数据库中,如果有的话则需要提示用户该数据已经被收藏并更改收藏图标。

public class MainActivity extends AppCompatActivity {

 private MovieAdapter adapter;
 private List<MovieDataModel.DataBean> mList = new ArrayList<>();
 private RealmDBHelp mRealmDBHelp;
 private boolean refreshType;

 @BindView(R.id.mTitleBar)
 TitleBar mTitleBar;
 @BindView(R.id.homeMovieList)
 RecyclerView homeMovieList;
 @BindView(R.id.refreshLayout)
 RefreshLayout refreshLayout;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 initView();
 initRefresh();
 }

 private void initView() {
 ButterKnife.bind(this);
 mTitleBar.setOnTitleBarListener(new OnTitleBarListener() {
  @Override
  public void onLeftClick(View v) {

  }

  @Override
  public void onTitleClick(View v) {

  }

  @Override
  public void onRightClick(View v) {
  // 跳转至我的收藏界面
  startActivity(new Intent(MainActivity.this, MovieCollectActivity.class));
  }
 });
 // 初始化本地数据库帮助类
 mRealmDBHelp = new RealmDBHelp();

 }

 private void initRefresh() {
 // 开启自动加载功能(非必须)
 refreshLayout.setEnableAutoLoadMore(true);
 refreshLayout.setOnRefreshListener(new OnRefreshListener() {
  @Override
  public void onRefresh(@NonNull final RefreshLayout refreshLayout) {
  refreshLayout.getLayout().postDelayed(new Runnable() {
   @Override
   public void run() {
   refreshType = true;
   // 加载数据
   initData();
   refreshLayout.finishRefresh();
   refreshLayout.resetNoMoreData();//setNoMoreData(false);
   }
  }, 2000);
  }
 });
 refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
  @Override
  public void onLoadMore(@NonNull final RefreshLayout refreshLayout) {
  refreshLayout.getLayout().postDelayed(new Runnable() {
   @Override
   public void run() {
   refreshType = false;
   ToastUtil.showToast("暂无更多的数据啦");
   // 将不会再次触发加载更多事件
   refreshLayout.finishLoadMoreWithNoMoreData();
   refreshLayout.setEnableLoadMore(false);
   refreshLayout.finishLoadMore();
   }
  }, 2000);
  }
 });
 //触发自动刷新
 refreshLayout.autoRefresh();
 }

 private void initData() {

 // 模拟从网络获取到json数据 app\src\main\assets\movieData.json
 String jsonData = BaseUtil.getAssetsJson(this, "movieData.json");
// L.i("jsonData:"   jsonData);
 if (TextUtils.isEmpty(jsonData)) {
  ToastUtil.showToast("Json数据为空");
  return;
 }
 if (mList != null) mList.clear();
 // 将json数据解析为Java实体对象
 MovieDataModel movieDataModel = new Gson().fromJson(jsonData, MovieDataModel.class);
 List<MovieDataModel.DataBean> dataBeanList = movieDataModel.getData();
 for (MovieDataModel.DataBean dataBean : dataBeanList) {
  MovieDataModel.DataBean data = new MovieDataModel.DataBean();
  data.setMvid(dataBean.getMvid());
  data.setName(dataBean.getName());
  data.setPoster(dataBean.getPoster());
  data.setUpdateStatus(dataBean.getUpdateStatus());
  data.setTag(dataBean.getTag());
  data.setVideo_type(dataBean.getVideo_type());
  mList.add(data);
 }

 // 查询本地收藏数据库中是否存在收藏的数据(更改收藏图标用的)
 queryAllCollectData();

 try {
  // 设置适配器
  homeMovieList.setLayoutManager(new GridLayoutManager(this, 3));
  adapter = new MovieAdapter(this, mList);
  homeMovieList.setAdapter(adapter);
 } catch (Exception e) {
  e.printStackTrace();
 }

 // 设置条目的点击事件
 adapter.setItemClikListener(new MovieAdapter.OnItemClikListener() {

  @Override
  public void onItemClik(View view, int position) {
  String mvId = mList.get(position).getMvid();
  String mvName = mList.get(position).getName();
  String movieImg = mList.get(position).getPoster();
  String movieTag = mList.get(position).getTag();
  String videoType = mList.get(position).getVideo_type();
  boolean isCollect = mList.get(position).isCollect();
  if (isCollect) {
   // 如果已经收藏了则清除该条收藏
   // 根据Id来删除一条数据
   mRealmDBHelp.deleteByKeyCollectData("movieId", mvId);
   mList.get(position).setCollect(false);
   ToastUtil.showToast(String.format("%s 已取消收藏", mvName));
  } else {
   // 添加收藏数据到本地数据库
   mRealmDBHelp.addCollectToDB(mvId, mvName, movieImg, movieTag, videoType);
   mList.get(position).setCollect(true);
  }
  // 通知适配器数据改变重新更新界面
  adapter.notifyDataSetChanged();
  }

  @Override
  public void onItemLongClik(View view, int position) {

  }

 });

 }

 /**
 * 查询本地收藏数据库中是否存在收藏的数据(更改收藏图标用的)
 */
 private void queryAllCollectData() {

 mRealmDBHelp.queryAllCollectData(new RealmChangeListener<RealmResults<MovieCollectDBModel>>() {
  @Override
  public void onChange(RealmResults<MovieCollectDBModel> movieCollectDBModels) {
  if (movieCollectDBModels.isEmpty()) {
   return;
  }
  for (MovieCollectDBModel movieCollectDBModel : movieCollectDBModels) {
   for (int i = 0; i < mList.size(); i  ) {
   if (mList.get(i).getMvid().equals(movieCollectDBModel.getMovieId())) {
    mList.get(i).setCollect(true);
    break;
   }
   }
  }
  }
 });

 }

 @Override
 protected void onStop() {
 super.onStop();
 mRealmDBHelp.closeTransaction();
 }

 @Override
 protected void onDestroy() {
 super.onDestroy();
 mRealmDBHelp.close();
 }
}

收藏界面的代码,包括查询和删除操作。

public class MovieCollectActivity extends AppCompatActivity {

 private RealmDBHelp mRealmDBHelp;
 private List<MovieCollectModel> mList = new ArrayList<>();
 private MovieCollectAdapter adapter;
 private boolean refreshType;

 @BindView(R.id.mTitleBar)
 TitleBar mTitleBar;
 @BindView(R.id.movieCollectList)
 RecyclerView movieCollectList;
 @BindView(R.id.empty_view)
 RelativeLayout empty_view;
 @BindView(R.id.refreshLayout)
 RefreshLayout refreshLayout;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_movie_collect);
 initView();
 initRefresh();
 }

 private void initView() {
 ButterKnife.bind(this);
 mTitleBar.setOnTitleBarListener(new OnTitleBarListener() {
  @Override
  public void onLeftClick(View v) {
  finish();
  }

  @Override
  public void onTitleClick(View v) {

  }

  @Override
  public void onRightClick(View v) {
  deleteRealmDB();
  }
 });
 mRealmDBHelp = new RealmDBHelp();

 }

 private void initRefresh() {
 // 开启自动加载功能(非必须)
 refreshLayout.setEnableAutoLoadMore(true);
 refreshLayout.setOnRefreshListener(new OnRefreshListener() {
  @Override
  public void onRefresh(@NonNull final RefreshLayout refreshLayout) {
  refreshLayout.getLayout().postDelayed(new Runnable() {
   @Override
   public void run() {
   refreshType = true;
   // 加载数据
   initData();
   refreshLayout.finishRefresh();
   refreshLayout.resetNoMoreData();//setNoMoreData(false);
   }
  }, 2000);
  }
 });
 refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
  @Override
  public void onLoadMore(@NonNull final RefreshLayout refreshLayout) {
  refreshLayout.getLayout().postDelayed(new Runnable() {
   @Override
   public void run() {
   refreshType = false;
   ToastUtil.showToast("暂无更多的数据啦");
   // 将不会再次触发加载更多事件
   refreshLayout.finishLoadMoreWithNoMoreData();
   refreshLayout.setEnableLoadMore(false);
   refreshLayout.finishLoadMore();
   }
  }, 2000);
  }
 });
 //触发自动刷新
 refreshLayout.autoRefresh();
 }

 private void initData() {
 queryAllCollectData();
 }

 /**
 * 查询本地收藏数据库中所有的数据
 */
 private void queryAllCollectData() {

 mRealmDBHelp.queryAllCollectData(new RealmChangeListener<RealmResults<MovieCollectDBModel>>() {
  @Override
  public void onChange(RealmResults<MovieCollectDBModel> movieCollectDBModels) {
  if (movieCollectDBModels.isEmpty()) {
   return;
  }
  if (mList != null) mList.clear();
  for (MovieCollectDBModel movieCollectDBModel : movieCollectDBModels) {
   MovieCollectModel data = new MovieCollectModel();
   data.setMovieId(movieCollectDBModel.getMovieId());
   data.setMovieName(movieCollectDBModel.getMovieName());
   data.setPoster(movieCollectDBModel.getPoster());
   data.setMovieTag(movieCollectDBModel.getMovieLabel());
   data.setVideoType(movieCollectDBModel.getVideoType());
   data.setCreatedTime(movieCollectDBModel.getCreatedTime());
   mList.add(data);
  }
  runOnUiThread(new Runnable() {
   @Override
   public void run() {
   parsingMovieList();
   }
  });
  }
 });

 }

 private void parsingMovieList() {

 movieCollectList.setLayoutManager(new GridLayoutManager(this, 3));
 adapter = new MovieCollectAdapter(this, mList);
 movieCollectList.setAdapter(adapter);

 if (mList.isEmpty()) {
  empty_view.setVisibility(View.VISIBLE);
  movieCollectList.setVisibility(View.GONE);
 } else {
  movieCollectList.setVisibility(View.VISIBLE);
  empty_view.setVisibility(View.GONE);
 }

 adapter.setItemClikListener(new MovieCollectAdapter.OnItemClikListener() {
  @Override
  public void onItemClik(View view, int position) {
  // 根据Id来删除一条数据
  deleteByKeyCollectData(position);
  }

  @Override
  public void onItemLongClik(View view, int position) {

  }
 });
 }

 /**
 * 根据Id来删除一条数据
 *
 * @param position
 */
 private void deleteByKeyCollectData(int position) {

 IOSMsgDialog.Companion.init(getSupportFragmentManager())
  .setTitle("清除影视提示")
  .setMessage("是否要清除该条影视收藏的数据?")
  .setAnimStyle(R.style.LDialogScaleAnimation)
  .setNegativeButton("否", new View.OnClickListener() {
   @Override
   public void onClick(View v) {
   }
  })
  .setPositiveButton("是", new View.OnClickListener() {
   @Override
   public void onClick(View v) {
   // 根据Id来删除一条数据
   mRealmDBHelp.deleteByKeyCollectData("movieId", mList.get(position).getMovieId());
   mList.remove(position);
   adapter.notifyDataSetChanged();

   }
  }, Color.RED)
  .setDismissListener(new OnDialogDismissListener() {
   @Override
   public void onDismiss(DialogInterface dialog) {
   }
  }).setCancelableOutside(true).show();
 }

 /**
 * 删除本地数据库中全部的收藏数据
 */
 private void deleteRealmDB() {

 IOSMsgDialog.Companion.init(getSupportFragmentManager())
  .setTitle("清空全部收藏数据提示")
  .setMessage("是否要立即清空全部我的收藏的数据?如果要清除单条数据的话请点击单条数据列表。")
  .setAnimStyle(R.style.LDialogScaleAnimation)
  .setNegativeButton("否", new View.OnClickListener() {
   @Override
   public void onClick(View v) {
   }
  })
  .setPositiveButton("是", new View.OnClickListener() {
   @Override
   public void onClick(View v) {
   // 清除全部收藏的数据库内容
   mRealmDBHelp.deleteAllCollectData();
   mList.clear();
   empty_view.setVisibility(View.VISIBLE);
   movieCollectList.setVisibility(View.GONE);
   adapter.notifyDataSetChanged();

   }
  }, Color.RED)
  .setDismissListener(new OnDialogDismissListener() {
   @Override
   public void onDismiss(DialogInterface dialog) {
   }
  }).setCancelableOutside(true).show();
 }

 @Override
 protected void onDestroy() {
 super.onDestroy();
 mRealmDBHelp.close();
 }

}

界面运行效果图如下:

在这里插入图片描述

apk安装包下载体验地址:

可以扫描以下二维码进行下载安装,或者点击以下链接 http://app.fukaimei.top/MovieCollect 进行下载安装体验。

总结

到此这篇关于Android使用Realm数据库实现App中的收藏功能(代码详解)的文章就介绍到这了,更多相关android realm数据库实现app收藏内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Android使用Realm数据库实现App中的收藏功能(代码详解)的更多相关文章

  1. html5 canvas合成海报所遇问题及解决方案总结

    这篇文章主要介绍了html5 canvas合成海报所遇问题及解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. 详解前端HTML5几种存储方式的总结

    本篇文章主要介绍了前端HTML5几种存储方式的总结 ,主要包括本地存储localstorage,本地存储sessionstorage,离线缓存(application cache),Web SQL,IndexedDB。有兴趣的可以了解一下。

  4. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  5. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  6. PhoneGap / iOS上的SQLite数据库 – 超过5mb可能

    我误解了什么吗?Phonegap中的sqlitedbs真的有5mb的限制吗?我正在使用Phonegap1.2和iOS5.解决方法您可以使用带有phonegap插件的原生sqliteDB,您将没有任何限制.在iOS5.1中,Websql被认为是可以随时删除的临时数据…

  7. ios – Realm:无法使用类型'(Object.Type)’的参数列表调用’对象’

    所以我在Realm中有一个非常简单的Book模型而我正在尝试在帮助程序类中检索所有书籍:这一行:抛出标题中的错误.我疯了还是这不是Realm文档告诉我们要做的?解决方法realm.objects()不会返回[Book]但会返回结果?.所以你必须改变userBookLibrary的类型:

  8. ios – Swift 2.0中的动态可选属性

    我已经看过这篇文章OptionaldynamicpropertiesinSwift,但我不想在NSObject中包装该类.这只是关于Realm数据库我没有nil属性,但我认为这是一个很好的方式来建模我的数据库.在可以在https://realm.io/docs/swift/latest/中找到的Realm文档中,它表示支持选项.这是我的码这是我的错误我知道这是与上面的帖子相同的代码和错误,但我很好

  9. ios – 在后台线程中写入Realm后,主线程看不到更新的数据

    >清除数据库.>进行API调用以获取新数据.>将从API检索到的数据写入后台线程中的数据库中.>从主线程上的数据库中读取数据并渲染UI.在步骤4中,数据应该是最新数据,但我们没有看到任何数据.解决方法具有runloops的线程上的Realm实例,例如主线程,updatetothelatestversionofthedataintheRealmfile,因为通知被发布到其线程的runloop.在后台

  10. Ionic – Splash Screen适用于iOS,但不适用于Android

    我有一个离子应用程序,其中使用CLI命令离子资源生成的启动画面和图标iOS版本与正在渲染的启动画面完美配合,但在Android版本中,只有在加载应用程序时才会显示白屏.我检查了config.xml文件,所有路径看起来都是正确的,生成的图像出现在相应的文件夹中.(我使用了splash.psd模板来生成它们.我错过了什么?这是config.xml文件供参考,我觉得我在这里做错了–解决方法在config.xml中添加以下键:它对我有用!

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部