使用 ViewModel 管理布局上的数据

如果不进行处理的话,布局上的临时数据可能会因为屏幕反转,切换系统语言等而消失,但是处理过程略微繁琐,较为麻烦,但是谷歌为我们提供了一种更加简洁的方式来管理界面数据,那就是 ViewModel。 构建自己的 ViewModel 类 新建 Java 类,继承至ViewModel,名字自定义,这里以MyViewModel为例。 package com.aimerneige.viewmoudeltest; import androidx.lifecycle.ViewModel; public class MyViewMoude extends ViewModel { } 新建好类之后,直接将需要用到的数据填写在内部,可以直接使用 public 的数据类型(不推荐),或者使用 private 数据加 get 方法。 package com.aimerneige.viewmoudletest; import androidx.lifecycle.ViewModel; public class MyViewMoude extends ViewModel { public int number = 0; public String test = "Test for 100"; private int age = 0; public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 然后把ViewModel当成一个智能地存储数据的结构体使用即可。 在 Activity 中使用 ViewModel 在MainActivity内构建MyViewMoude的引用 MyViewMoude myViewMoude; 在 onCreate 方法内获得 MyViewMoude 的实体 ...

2020年2月20日 · Aimer Neige

ToolBar

MaterialDesign 依赖库 implementation 'com.google.android.material:material:1.1.0' 在布局文件中加入 TooBar <androidx.appcompat.widget.Toolbar android:id="@+id/toolBar" android:layout_width="match_parent" android:layout_height="wrap_content" <!--其他属性设置--> /> 关于旧版的说明 旧版需要使用兼容包 compile 'com.android.support:appcompat-v7:23.1.1' 使用以下布局方法 <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="标题" android:textSize="20sp"/> </android.support.v7.widget.Toolbar> 很多文章都是这么写的,此处代码也是拷贝的,但是在开发中出了一些问题,博主是没有成功运行,仅供参考,挂了请自行查阅资料,不做解释。这里主要介绍新版 ToolBar 的使用 在 MainActivity 中引用 Toolbar Toolbar toolbar = findViewById(R.id.toolBar); 使用 ToolBar 作为界面布局 toolbar.setTitle("AppBarLayoutTest"); setSupportActionBar(toolbar); 导包的时候导这个,不要导错了,否则会报错 import androidx.appcompat.widget.Toolbar; 添加自定义属性 按需添加自定义属性,可以修改的内容包括标题的文字、图标、颜色等。不详细介绍,官方文档里很详细。 官方文档:https://developer.android.com/reference/android/widget/Toolbar 添加菜单 构建菜单的布局文件 这里添加的 item 会按顺序显示在 ToolBar 上面。 showAsAction 属性: always:总是显示 ifRoom:空间足够时显示 never:永不显示(收纳在右侧的三条横线那个更多按钮里) <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/toolbar_setting" android:icon="@drawable/ic_setting" android:title="@string/toolbar_setting" app:showAsAction="always" /> <item android:id="@+id/toolbar_about" android:title="@string/toolbar_about" app:showAsAction="never" /> <item android:id="@+id/toolbar_exit" android:title="@string/toolbar_exit" app:showAsAction="never" /> </menu> 在主菜单中引用菜单的布局文件 @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.toolbar, menu); return true; } 设置菜单点击事件 @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case android.R.id.home: drawerLayout.openDrawer(GravityCompat.START); break; case R.id.toolbar_setting: Toast.makeText(MainActivity.this, "Waiting for coding for setting", Toast.LENGTH_SHORT).show(); break; case R.id.toolbar_about: Toast.makeText(MainActivity.this, "Waiting for coding for about", Toast.LENGTH_SHORT).show(); break; case R.id.toolbar_exit: Toast.makeText(MainActivity.this, "Waiting for coding for exit", Toast.LENGTH_SHORT).show(); break; default: break; } return true; } AppBarLayout 使用 AppBarLayout 可以给 ToolBar 定义更多的内容,并且 TabLayout 一般也是嵌套在其内部。 ...

2020年2月18日 · Aimer Neige

使用 Gson 解析 Json 数据

新建项目 导入 Gson 依赖 implementation 'com.google.code.gson:gson:2.8.5' 设计布局 这里设计俩个 TextView 和一个 Button,点击 Button 后发送 Http 请求获取 Json 数据,并且通过 Gson 进行解析,将解析结果显示在 TextView 上,以此验证解析成功。 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="nodata"/> <TextView android:id="@+id/text2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="nodata"/> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test"/> </LinearLayout> 代码很简单就不多解释了。另外 在 Activity 中注册控件 的内容也省略。 发送 Http 请求并获取数据 操作同一般的 HTML 源码获取,这里不多解释。由于保存在网络上的 Json 数据其源码就是合法的 Json 字符串,因此通过解析网页源码的方法获取的内容就是 Json 数据。这里有一个网页保存了 Json 数据,可用于测试。 https://user.moecraft.net:8443/API/Mc/authlib/ 获取源码之后将其保存在一个字符串内即可继续进行下一步操作。此处命名为 jsonData。 ...

2020年2月17日 · Aimer Neige

Ubuntu 19.10 配置 Kotlin 开发环境

Ubuntu 19.10 配置 Kotlin 开发环境 使用工具 VSCode 安装 Kotlin 编译器 sudo snap install kotlin --classic 如果出现错误,执行以下命令: sudo apt install snap 这条指令执行后,系统安装的内容有: kotlinc kotlinc-jvm kotlinc-js kotlin-dce-js 可以通过以下指令查看版本,如果有输出证明安装成功。 俩条指令都可以,建议使用上面的。 kotlin -version kotlinc -version 安装插件 这俩个貌似安装一个就可以了,也可以都安装。 Kotlin Kotlin Language 安装下面这个插件后在 文件 -> 首选项 -> 设置 -> 扩展 -> Run Code Configuration 中找到并勾选 Run In Terminal Code Runner 测试 建立新文件 HelloWorld.kt fun main(args: Array<String>) { println("Hello, World!") } 通过点击右上角三角形(由 Code Runner 提供的快捷方式)来编译运行,查看输出。 如果看到终端输出 Hello, World! 的内容,说明开发环境搭建成功。 ...

2020年2月16日 · Aimer Neige

设置网络图片

通过网络连接获取图片信息,并将其设为软件的 ImageView 图片属性 介绍: 与获取 HTML 类似,首先需要建立网络连接并获取数据,只是这次不通过 String 获取保存数据,而是使用 Bitmap 保存。 与获取 HTML 数据类似,联网操作同样需要新建线程,要注意的是在子线程不能操作 UI,需要通过外部函数设置图片或者在函数返回 Bitmap 对象使用。 核心代码: 建立网络连接,这里使用 HttpURLConnection URL url = new URL("https://www.example.com.img") HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); // ...... // 诸如超时时间等的设置 处理返回数据 InputStream is = connection.getInputStream(); Bitmap bitmap = BitmapFactory.decodeStream(is); 设置控件,注意该操作不能在子线程中进行 imageView.setImageBitmap(bitmap); 完整代码 代码很烂,有很多可以优化的地方 //设置网络图片 public void setUrlImage(final int ImageViewId, final String address) { //开启一个线程用于联网 new Thread(new Runnable() { @Override public void run() { try { //把传过来的路径转成URL URL url = new URL(address); //获取连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //使用GET方法访问网络 connection.setRequestMethod("GET"); //超时时间为10秒 connection.setConnectTimeout(10000); //获取返回码 int code = connection.getResponseCode(); if (code == 200) { InputStream inputStream = connection.getInputStream(); //使用工厂把网络的输入流生产Bitmap Bitmap bitmap = BitmapFactory.decodeStream(inputStream); //子线程不能操作UI,通过外部函数设置图片 setImage(ImageViewId, bitmap); inputStream.close(); } else { //服务启发生错误,显示提示信息 Toast.makeText(HttpImage.this, "Can't get the image from Internet.", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { e.printStackTrace(); } } }).start(); } public void setImage(int ImageViewId, Bitmap bitmap) { ImageView imageView = findViewById(ImageViewId); imageView.setImageBitmap(bitmap); } 一些废话 实际上和处理 HTML 是类似的,只不过不再使用 String 处理服务器返回的数据。

2020年2月16日 · Aimer Neige

使用 GsonFormat 插件快速构建 Json 映射对象

插件安装 File Settings Plugins Marketplace 在搜索框输入 GsonFormat 搜索 安装相应插件 根据提示重启 IDE 使用方法 新建实体类 ALT + Insert 或者 右键->Generate 选择 GsonFormat 将待解析 Json 字符串输入弹出的对话框 OK

2020年2月16日 · Aimer Neige

Swiperefreshlayout

GoogleDoc GoogleGithub 声明依赖项 直接复制官方文档,不多解释了(懒 在应用或模块的 build.gradle 文件中添加所需工件的依赖项: dependencies { implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" } 如需详细了解依赖项,请参阅添加编译依赖项。 添加布局 在 xml 布局文件中添加 SwipeRefreshLayout,并将 WebView 内嵌在 SwipeRefreshLayout 中。 布局这里拷贝了别人的代码,结果软件闪退,搞了半天找不到原因,重开了一个项目,根据代码提示写了一份居然可以运行,分明代码一样的,好迷啊。。。。。 <?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=".MainActivity"> <androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh" android:layout_width="match_parent" android:layout_height="match_parent"> <WebView android:id="@+id/web_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </LinearLayout> SwipeRefreshLayout 类似 ScrollView,内部只能有一个部件,但是你可以这样玩、(手动滑稽 <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test_scroll" android:textSize="16sp" /> </LinearLayout> </ScrollView> 编写代码部分 先放一个完整的源码,看不懂直接跳过,下面介绍关于 Swiperefreshlayout 的核心代码 ...

2020年2月1日 · Aimer Neige

如何安装 Ubuntu

前言 之前由于感兴趣而涉足 Linux 领域,在虚拟机内尝试了 Ubuntu,可惜虚拟机内性能有限,于是以双系统的形式安装了 Ubuntu18.04。 经过一段时间的使用后,感觉 Ubuntu 完全可以作为日常系统使用,于是放弃了 bug 不断的 Windows 系统,做好备份后直接全盘安装了 Ubuntu 系统,Windows 下的软件找不到替代品就转向虚拟机使用。 个人感觉 Ubuntu 是完全可以替代 Windows 日常使用的,以下是 Ubuntu 相比于 Windows 的一些优点和不足 优点 更加稳定 更加安全 不会整天提醒你更新系统 配置开发环境仅需几行终端指令 忘记恼人的弹窗广告和流氓软件吧 不足 很多软件不支持 Linux,只能在 Windows 上运行 几乎 90% 的游戏都不支持 Linux 需要学习命令行 界面丑 对策: Windows 下的软件可以直接在虚拟机下运行,不想挂个虚拟机的话也可以考虑使用 Wine 游戏还是不要玩了,装个 Ubuntu 学 Linux 顺带还能帮你戒游戏,实在需要玩游戏的可以使用双系统 命令行也不是特别难,遇到问题谷歌一下就行了 至于界面丑,我指的是 Ubuntu18.04 及 之前的版本,这些问题可以通过安装主题和图标包来解决,而最新的 Ubuntu19.10 界面还是十分惊艳的 Ubuntu 的安装 访问 Ubuntu 官网下载最新的镜像文件 使用 Etcher 写入 U 盘作为启动盘 通过 U 盘启动系统 ...

2020年1月24日 · Aimer Neige

面向小白的 C 语言随机数详解

// 生成一系列0~9之间的随机整数 #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { srand( time(NULL) ); int ret; for (int i = 0; i < 20; i++) { ret = rand() % 10; // ret是一个0~9之间的随机整数 printf("%d ", ret); } return 0; } 输出结果 7 6 6 1 6 9 2 7 1 8 2 0 5 9 2 5 4 0 0 0 这是啥啊?看不懂啊。 不要着急,我来慢慢讲 首先是一个最简单的随机数: #include <stdio.h> #include <stdlib.h> int main() { int ret = rand(); printf("%d", ret); return 0; } 输出结果 41 这里用到了rand()这个函数,使用这个函数需要引入stdlib.h这个头文件,函数返回一个随机数,生成的随机数都是整数,所以我们把它交给一个int的变量。然后使用printf函数输出即可看到结果。当然,由于我们使用了printf函数,我们还需要引入stdio.h 这个头文件。 但是我们如果多次运行,发现结果始终是 41,这是怎么回事呢? 这里要了解 C 语言随机数的生成机制: 在 C 语言中,rand()函数可以用来产生随机数,但是这不是真真意义上的随机数,是一个伪随机数,是根据一个数,我们可以称它为种子,为基准以某个递推公式推算出来的一系数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,当计算机正常开机后,这个种子的值是定了的,除非你破坏了系统,为了改变这个种子的值,C 提供了 srand()函数,它的原形是 void srand( int a)。 ...

2020年1月24日 · Aimer Neige