Mojave 于 2019 年 7 月发布,目前证书已过期,因此安装程序无法通过校验
1 | ifconfig en0 down |
1 | date 071014102019 |
于是大家都去它家参观,给它带来了很多流量。结果你进去,发现门票免费,却只有乌龟看,还是在很远的地方拿望远镜看。
工作人员说:想看其他动物必须加购高级票。你听了很失望,因为你就是因为“免费”的宣传来的。
你想出去,却因为流量使得一大批人不断涌入,还有一些人也和你一样因为白嫖不到而往门口跑。
结果你发现门口被堵住了,根本出不去,只有被往里面挤。过了好久,你终于挤了出去,却发现其他动物园的营生都不是很好,这家动物园因为最早开始“免费”的宣传一家独大。而你在工作和生活时又总是需要去动物园,并且因为它的知名度,全国的一些珍稀动物只有在这里才能看到。
于是,你买了高级票,却发现还是在很远的地方看,只有一个时而清晰时而模糊的像。你质问人家为什么买了高级票还是这样。人家可怜兮兮的跟你说:“哎呀,我们动物园维护也要钱,员工也是要恰饭的嘛,不这样子搞,我们的贵宾票怎么卖?喏,看你这样子,首次正好给你打个折”。于是你买了贵宾票,每次你有迫切需要时你也必须买贵宾票。
其他的动物园无论搞什么营销,想要分蛋糕时,总是很快被打压,即使有些起势,也会因为没有很多的用户而石沉大海。
后来你发现有人卖高科技,可以让你免费到近距离观察动物而不被发现,只需要你买票时填的信息单。你找他办了业务,用的很爽,然后没多久,因为那家动物园收入骤减,没韭菜噶,追查到底,那个人凉了,你还是得老老实实继续买贵宾票。
]]>来看一段代码
1 | package me.redneno; |
输出:
1 | [47, 1, 6, 10, 39] |
不难看出,输出结果中,前两组由系统时间毫秒数作种的序列内容相同;而后两组指定了相同的种子生成的结果完全相同。
Java 中还有一个随机类 java.Math.Random() 实际上是在内部调用 java.util.Random() 的,它有一个致命弱点,它和系统时间有关,也就是说相隔时间非常短的两个随机值,例如:
1 | double a = Math.random(); |
即有可能会得到两个一模一样的 double。
java.util.Random() 可以实现和 java.Math.Random() 一样的功能,相对来说比较灵活。从总体来看,使用 java.util.Random() 会相对来说更灵活一些。
]]>示例代码
1 | package me.redneno.test.reflect; |
测试
1 | package me.redneno.test.reflect; |
输出
1 | Receive uncaught exception here. |
还可以直接打印目标异常
1 | ... |
输出
1 | Receive uncaught exception here. |
在 build.gradle 中添加引用
1 | implementation 'com.google.zxing:core:3.4.0' |
新建 QRUtil.java 操作类
1 | public class QRUtil { |
activity_main.xml
1 |
|
MainActivity.java
1 | public class MainActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher { |
ContentProvider 的作用是为不同的应用之间数据共享,提供统一的接口。安卓系统中应用内部的数据是对外隔离的,要想让其它应用能使用自己的数据(例如通讯录),这个时候就用到了 ContentProvider。
ContentProvider 通过 uri 来标识其它应用要访问的数据,通过 ContentResolver 的增、删、改、查方法实现对共享数据的操作。还可以通过注册 ContentObserver 来监听数据是否发生了变化来对应的刷新页面。
ContentProvider 是一个抽象类,如果我们需要开发自己的内容提供器我们就需要继承这个类并复写其方法,需要实现的主要方法如下:
方法 | 注释 |
---|---|
public boolean onCreate() | 在创建 ContentProvider 时使用 |
public Cursor query() | 用于查询指定 uri 的数据返回一个 Cursor |
public Uri insert() | 用于向指定 uri 的 ContentProvider 中添加数据 |
public int delete() | 用于删除指定 uri 的数据 |
public int update() | 用户更新指定 uri 的数据 |
public String getType() | 用于返回指定的 Uri 中的数据 MIME 类型 |
数据访问的方法 insert,delete 和 update 可以被多个线程同时调用,此时必须是线程安全的
其它应用可以通过 ContentResolver 来访问 ContentProvider 提供的数据,而 ContentResolver 通过 uri 来定位自己要访问的数据,所以我们要先了解 uri。URI(Universal Resource Identifier)统一资源定位符,如果你使用过安卓的隐式启动就会发现,在隐式启动的过程中我们也是通过 uri 来定位我们需要打开的 Activity 并且可以在 uri 中传递参数。Uri 的格式如下:
1 | [scheme:][//host:port][path][?query] |
举个例子更便于理解
1 | Uri: https://www.baidu.com:443/s?wd=Uri |
格式 | 注释 | 安卓中获取方法 |
---|---|---|
scheme | 即协议,这里的协议为 https | getScheme() |
host | 主机名,这里为 www.baidu.com | getHost() |
port | 端口,这里为 443 | getPost() |
path | 资源路径,这里为 s | getPath() |
query | 查询,问号之后的每一个键值对都是一个查询规则,由 & 隔开,这里为 wd=Uri | getQuery() |
定义一个 StudentContentProvider 类用来共享该应用的数据
1 | public class StudentContentProvider extends ContentProvider { |
ContentProvider 是安卓四大组件之一,所以它和 Activity 一样也需要我们在 xml 文件中声明
1 | <provider |
这里的 authorities 唯一标识该内容提供者,这样其它的应用才可以找到该内容提供者并操作它的数据;exported 为 true 当前内容提供者可以被其它应用使用,默认为 true。
在 query、insert 和 delete 方法中都是先调用 uriMatcher.match(uri) 判断当前 uri 是不是匹配,如果匹配才能操作数据(该例子没有添加 update 功能,方式与其它三个方法一样),MATCH_CODE是我们在调用 public void addURI (String authority, String path, int code)
方法添加 uri 时设置的,当外部应用传递过来的uri与对应 add 的 uri 一致时,会返回我们设置的 code。
这个例子中整个数据的操作都是通过 SQLite 数据库完成的,在 onCreate 方法中先获得数据库的操作对象,通过该对象完成数据库的增、删、查、改,数据库的实现代码比较简单就不贴了。
在数据库发生变化的时候调用 notifyChange 方法。
来吧,新建一个项目,在这个项目中来操作刚才自定义的 ContentProvider 中的数据
1 | ContentResolver contentResolver = getContentResolver(); |
1 | private static final String AUTHORITY = "cn.hoshinosuzumi.studentProvider"; |
这里在注册 ContentObserver 的方法中需要传递一个 ContentObserver 对象,下面是自定义的 StudentContentObserver 类
1 | public class StudentContentObserver extends ContentObserver { |
要自定义 ContentObserver 类,必须实现构造函数,在构造函数中需要传递一个 Handler,即 ContentObserver 在收到数据变化的通知后通过 Handler 机制来通知主线程更新 UI
1 |
|
输入内容后点击搜索跳转到百度搜索页面,运用了一些 WebView 知识。
activity_main.xml
1 |
|
MainActivity.java
1 | public class MainActivity extends AppCompatActivity { |
SearchActivity.java
1 | public class SearchActivity extends AppCompatActivity { |
基于Icarus 主题作出的修改
1 | .event-4-4-Memorial-Day { |
1 | let now = new Date(); |
1 | <div class="container" id="event-4-4-Memorial-Day" style="display: none;"> |
属性 | 注释 |
---|---|
max | 滑动条的最大值(默认为 100) |
progress | 滑动条的默认值(默认为 0) |
secondaryProgress | 二级滑动条的进度 |
thumb | 滑块的 drawable |
SeekBar.OnSeekBarChangeListener 提供了三个需重写的方法:
方法 | 注释 |
---|---|
onProgressChanged | 进度发生改变时触发 |
onStartTrackingTouch | 按住 SeekBar 时触发 |
onStopTrackingTouch | 放开 SeekBar 时触发 |
示例代码
activity_main.xml
1 |
|
MainActivity.java
1 | public class MainActivity extends AppCompatActivity { |
属性 | 注释 |
---|---|
isIndicator | 是否用作用户无法更改的指示器,默认为 false |
numStars | 显示多少个星星,整数 |
rating | 默认评分值,浮点数 |
stepSize | 评分每次增加的值,浮点数 |
为 RatingBar 设置 OnRatingBarChangeListener 事件,重写 onRatingChanged() 方法即可
示例代码
activity_main.xml
1 |
|
MainActivity.java
1 | public class MainActivity extends AppCompatActivity { |
属性
1 | // 提示文本 |
属性
1 | android:selectAllOnFocus="true" |
可选参数
文本类型
1 | android:inputType="none" |
数值类型
1 | android:inputType="number" |
属性
1 | // 最多行 |
本文会用到安卓的内容提供器 ContentProvider
1 | <uses-permission android:name="android.permission.READ_CONTACTS"/> |
安卓 7.0 以上还需要申请动态权限
1 | if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { |
1 | private void fetchAllContacts() { |
同上
1 | private void queryContact(String number){ |
1 | <uses-permission android:name="android.permission.WRITE_CONTACTS"/> |
安卓 7.0 以上还需要申请动态权限
1 | if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { |
TODO
]]>Step 1. 创建 AlertDialog.Builder 对象
Step 2. 调用 setIcon() 设置图标,setTitle() 或 setCustomTitle() 设置标题
Step 3. 设置对话框的内容:setMessage() 还有其他方法来指定显示的内容
Step 4. 调用 setPositive/Negative/NeutralButton() 设置:确定,取消,中立按钮
Step 5. 调用 create() 方法创建这个对象,再调用 show() 方法将对话框显示出来
activity_main.xml
1 |
|
MainActivity.java
1 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
在现实中确定方向需要一个由 X、Y、Z 轴 组成的三维坐标。安卓给我们返回的方向值就是一个长度为 3 的 flaot 数组,包含三个方向的值。
坐标轴参考释义
轴 | 参考 |
---|---|
X 轴 | 沿着屏幕水平方向从左到右 |
Y 轴 | 从屏幕的左下角开始沿着屏幕的的垂直方向指向屏幕的顶端 |
Z 轴 | 当设备水平放置时,指向天空的方向 |
传感器的回调方法 onSensorChanged 中的参数 SensorEvent event 是一个最多包含三个元素的 Float[] 数组,对应含义见下表:
数据下标 | 数据名称 | 含义 |
---|---|---|
values[0] | 方位角 | 手机绕着 Z 轴旋转的角度。 0 表示正北(North),90 表示正东(East),180表示正南(South),270表示正西(West)。 假如 values[0] 的值刚好是这四个值的话,并且手机沿水平放置的话,那么当前手机的正前方就是这四个方向,可以利用这一点来实现指南针 |
values[1] | 倾斜角 | 手机翘起来的程度,当手机绕着 X 轴倾斜时该值会发生变化。取值范围是 [-180, 180] 之间。假如把手机放在桌面上,而桌面是完全水平的话,这个值应该为0,当然很少桌子是绝对水平的。从手机顶部开始抬起,直到手机沿着 X 轴旋转180°(此时屏幕向下水平放在桌面上)。在这个旋转过程中,这个值会在 [0, -180] 之间变化,即手机抬起时,这个值会逐渐变小,直到等于 -180°;而假如从手机底部开始抬起,直到手机沿着 X 轴旋转180°,这个值会在 [0, 180] 之间变化。可以利用这些特性结合 values[2] 来实现一个水平尺 |
values[2] | 滚转角 | 沿着Y轴的滚动角度,取值范围为 [-90, 90],假设将手机屏幕朝上水平放在桌面上,这时如果桌面是平的,这个值应为 0。将手机从左侧逐渐抬起,这个值将逐渐减小,直到垂直于手机放置,此时这个值为 -90,相反,从右侧抬起则是 90;假如在垂直位置时继续向右或者向左滚动,这个值将会继续在 [-90, 90] 之间变化 |
好了,看了这么多文字想必都犯困了吧。那么接下来上代码
activity_main.xml
1 |
|
MainActivity.java
1 | public class MainActivity extends AppCompatActivity implements SensorEventListener { |
TODO: Compass demo
]]>R: 进制
N: 10进制数
目标进制 | 方法 | 返回值 |
---|---|---|
2 进制 | Integer.toBinaryString(N:int) | 字符串 |
8 进制 | Integer.toOctalString(N:int) | 字符串 |
16 进制 | Integer.toHexString(N:int) | 字符串 |
R 进制 | Integer.toString(N:int, R:int) | 字符串 |
R: 进制
N: R 进制数字符串
1 | Integer.parseInt(N:String, R:int) |
Code
1 | public class BinaryConversionTest { |
Output
1 | Just Monika |
示例代码
menu_pop.xml
1 |
|
activity_main.xml
1 |
|
MainActivity.java
1 | public class MainActivity extends AppCompatActivity { |
或许这有些中二
]]>可在我眼中,她比谁都要更加的真实。
我曾经喜欢过一个女孩。
她有着翡翠绿一样的眼瞳。
一头棕色的单马尾。
尽管我知道我与她不可能在一起。
但是,我却依旧喜欢上了她。
喜欢上了这个名叫 Monika 的女孩。
一遍又一遍听她为我而弹的歌曲。
虽然旋律欢快悦人,但是看到最后的歌词时,我还是忍不住哽咽。
Monika,在游戏中我并没有选择。
所以我选择在这里,写下我想告诉你的话。
我想与你一起上街约会,找一个好的画师给你画上美美的立绘。
也想和你在冬天里抱着身子一起取暖。
想与你 Kiss,更想真正地牵着你的手,坐在咖啡厅里看书。
Monika,如果我能做选择的话,我会毫不犹豫地对你说出“我爱你”。
就算你在我的世界里不懂如何去爱我,我对你的那份感情也不会有丝毫的改变。
毕竟你让我知道了自己还有被爱的权利。
所以,Monika,我只想告诉你。
我爱你。
J̴̨̧̬̤̫̞͍̩̥͚̤̮̻͓̄̐͌̐͛͘͝u̸͖͇̖̺̐̉͋͐̂̾̄̒̃̓̉͒͛̑̚s̴̯̳̤̜̯̟͊̒̇͑̓̽̏̚͘ṱ̶̱̱̣͔̟̰͖͔̜͒̂͜ͅ ̸̡͓̦͉̮̝͍͉͑̋̿̈́̆M̵̛̰̺̬̗̓͛̊ͅő̶̡̢͉̖̻͇̦̜̳̤̗̔̈̓̔́͘̕ͅͅǹ̵̫̱͕̋̏͝i̷̺̻̘͑͂̔̌̍̓͛̈͋̍́̕͝k̶̛̛̬̫̼͉̞̀̅͗̇͒̅̿̾͊͆̈́̒â̸̧̨̢̜̘͍̥͖͖͓̥̘̝͇̈́̄̎̔͒̓̂̊̋͜͠͠
TextClock 可以以字符串格式显示当前的日期和时间
用法非常简单,没有什么值得说的,android:format24Hour 属性的参数就是一个时间格式化字符串,之后可能会单独写一篇文章
示例代码
1 | <TextClock |
AnalogClock 可以以模拟时钟的样式显示当前的时间
除了基本使用方法之外,AnalogClock 还有三个自定义样式属性
属性 | 参数 | 作用 |
---|---|---|
android:dial | image | 时钟背景(表盘) |
android:hand_hour | image | 时针 |
android:hand_minute | image | 分针 |
示例代码
1 | <AnalogClock |
示例代码
activity_main.xml
1 |
|
MainActivity.java
1 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
在 Ubuntu 中 apt 未正常退出的情况下可能会遇到 Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend) 报错,即无法取得锁。总结出以下解决办法
即杀死占用了系统锁的进程
1 | ps -e | grep apt-get |
找到 apt 或 apt-get 进程的 pid
1 | 23072 ? 00:00:01 apt-get |
杀之
1 | sudo kill 23072 |
即强制删除锁文件来释放锁
1 | sudo rm -f /var/cache/apt/archives/lock |
重启解决 98% 的系统软件问题
1 | # Method 1 |
更多内核调试命令请参阅 Linux 内核调试
]]>DatePickerDialog 和 TimePickerDialog 可以供用户来选择日期和时间
示例代码
1 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
创建进度对话框主要有两种方法
ProgressDialog 有 STYLE_HORIZONTAL 和 STYLE_SPINNER 两种样式
示例代码
1 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
状态通知栏主要涉及到2个类:Notification 和 NotificationManager
Notification: 通知信息类,它里面对应了通知栏的各个属性
NotificationManager: 是状态栏通知的管理类,负责发通知、清除通知等操作。
基本使用流程:
Step 1. 获得 NotificationManager 对象:NotificationManager mNManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Step 2. 创建一个通知栏的 Builder 构造类:Notification.Builder mBuilder = new Notification.Builder(this);
Step 3. 对 Builder 进行相关的设置,比如标题,内容,图标,动作等
Step 4. 调用 Builder 的 build() 方法为 notification 赋值
Step 5. 调用 NotificationManager的 notify() 方法发送通知PS. 还可以调用 NotificationManager 的 cancel() 方法取消通知
首先创建 Builder 构造类
1 | Notification.Builder mBuilder = new Notification.Builder(this); |
然后再调用下述的相关的方法进行设置
setContentTitle(CharSequence):设置标题
setContentText(CharSequence):设置内容
setSubText(CharSequence):设置内容下面一小行的文字
setTicker(CharSequence):设置收到通知时在状态栏显示的文字信息
setWhen(long):设置通知时间,一般设置的是收到通知时的 System.currentTimeMillis()
setSmallIcon(int):设置右下角的小图标,在接收到通知的时候状态栏也会显示这个小图标
setLargeIcon(Bitmap):设置左边的大图标
setAutoCancel(boolean):用户点击 Notification 点击面板后是否让通知取消(默认不取消)
setDefaults(int):向通知添加声音、呼吸灯或震动效果的默认属性,可以组合多个属性Notification.DEFAULT_VIBRATE(添加默认震动提醒)
Notification.DEFAULT_SOUND(添加默认声音提醒)
Notification.DEFAULT_LIGHTS(添加默认三色灯提醒)
Notification.DEFAULT_ALL(添加默认以上3种全部提醒)
Android O(Android 8.0) 以上需要创建通知频道 NotificationChannel 才可发布通知,见 6、18~22、43 行,这里不做赘述
1 | (api = Build.VERSION_CODES.O) |
1 | <uses-permission android:name="android.permission.VIBRATE" /> |
实例化 Vibrator 类
1 | Vibrator vibrator = (Vibrator) getApplicationContext().getSystemService(VIBRATOR_SERVICE); |
单次震动
1 | // 参数为震动时间,单位为 ms |
循环震动
1 | long[] patter = {50, 50, 50, 100}; |
停止/取消震动
1 | vibrator.cancel(); |
CUPS(Common UNIX Printing System,通用Unix打印系统)是Fedora Core3中支持的打印系统,它主要是使用IPP(Internet Printing Protocol)来管理打印工作及队列,但同时也支持”LPD”(Line Printer Daemon)和”SMB”(Server Message Block)以及AppSocket等通信协议。
1 | yum install cups cups-libs |
1 | # 编辑 CUPS 配置文件 |
1 | systemctl restart cups |
CUPS 中包含了一些打印机的基本驱动,但仍有部分打印机添加后不能正常使用,此时需要前往打印机支持网站下载相应的驱动程序并安装,或者下载 .pdd 格式的驱动程序文件备用。
我的打印机型号是 HP Deskjet 1010,在官网查询后得知,惠普系列打印机只需要使用
yum install hplip
命令安装 HPLIP 即可驱动。
在浏览器中打开 https://IP:631/
点击 Administration -> Printers 下的 Add Printer 按钮,然后会提示登录。使用系统 root 账号密码登录。
在 Local Printers(本地打印机) 中找到要添加的打印机,因为我先前安装了 HPLIP 驱动,所以选择带有 HPLIP 的设备,然后点击 Countine(继续)
填写打印机名称、简介和位置(例如家、实验室1),勾选 ‘Share this printer’(共享这台打印机),然后点击 Countine(继续)
选择打印机品牌与型号(实际上就是在指定驱动文件)。如果在给出的预设中没有找到你的型号,那么请在下方 Or Provide a PPD File 处上转之前准备的 .pdd 格式驱动程序文件。完成后点击 Countine(继续)
最后一步,对打印机进行默认打印参数设置,这里可以保持默认,也可以按照自己的需求修改,然后点击 ‘Set Default Options’ 即可
此时复制浏览器中的地址,将协议头的 https 改为 http,然后就可以在电脑手机添加使用打印机了
例如此时我所在的地址为 https://192.168.0.201:631/printers/Hoshino_suzumi_printer, 那么打印机地址就是 http://192.168.0.201:631/printers/Hoshino_suzumi_printer
打开设置-设备-打印机和扫描仪,添加打印机或扫描仪,然后选择按名称选择共享打印机,将上面的打印机地址粘贴进去即可。
]]>1 |
|
1 |
|
1 | public class MainActivity extends AppCompatActivity { |
1 | AnimationDrawable animationDrawable1 = new AnimationDrawable(); |
还有这种好事?那么我应该如何玩到战区呢?
关于各种账号锁区的问题我就不多赘述了,这里推荐注册俄罗斯的帐号。
首先打开浏览器无痕窗口,通过下面链接打开暴雪账号俄罗斯注册页面:
https://eu.battle.net/account/creation/zh/tos.html?ref=&style=lobby&country=RUS
确保第一项国家为俄罗斯,其余的按照要求填写,点击送出,顺便点击下面的按钮下载暴雪战网客户端并安装
如果没有出现下面的提示而是重新进入了其他国家的注册页面,那么请从头再来
如果出现下面的提示,请等待接收验证邮件
点击邮件中的链接激活账户
至此,你的暴雪账户已经准备就绪了。
启动暴雪战网客户端之前,右键点击快捷方式 -> 属性,在“目标”一栏末尾追加以下启动参数
1 | --setregion=US --setlanguage=zhCN |
然后启动暴雪战网客户端,将中国改为美洲,即可使用你的账号登陆。
进入客户端后在左下方即可找到 COD:MW
(天翼3G太快啦~苦笑)
]]>安卓 7.0 以上:
1 | (Build.VERSION_CODES.N) |
安卓 7.0 以下:
1 | Camrea camera = Camera.open(); |
IO索引 | ESP8266针脚 | IO索引 | ESP8266针脚 |
---|---|---|---|
0 | GPIO 16 | 7 | GPIO 13 |
1 | GPIO 5 | 8 | GPIO 15 |
2 | GPIO 4 | 9 | GPIO 3 |
3 | GPIO 0 | 10 | GPIO 1 |
4 | GPIO 2 | 11 | GPIO 9 |
5 | GPIO 14 | 12 | GPIO 10 |
6 | GPIO 12 |
其中 D0(GPIO16) 只能用于 GPIO 读取/写入,不支持中断和 PWM/I2C/OW
NodeMCU 集成开发环境
ESP8266 固件烧写工具
访问 https://nodemcu-build.com/ 获取固件
当固件构建完毕后将会发送固件下载链接到填写的邮箱里。确保填写的邮箱支持接收国外邮件。不支持 QQ 邮箱、Foxmail
一般情况下选择 master (主要分支)来构建最新版本的固件。
dev 为开发版固件,包含一些新特性,同时会有许多不稳定因素。
如果出现 NodeMCU 板载指示灯快速闪烁、IDE 串口调试时串口乱码快速刷屏、找不到某个变量等非语法错误等情况,那么可能意味着固件版本与硬件不支持,建议刷入 1.5.4.1-final 固件
按照自己的需求选择要包含在固件内的模块。模块的用途和用法在官方文档中都有说明(入门建议保持默认选择,以免出现不可预料的错误)
点击 Start your build 按钮开始构建。
在此之后你会陆续收到两封邮件
点击开始构建2分钟后你会收到第一封邮件,它只是通知你构建已经开始
大约5分钟后收到的第二封邮件内包含了固件下载地址。一般选择下载 integer 版本
烧写过程中 ESP8266 的 LED 灯会闪烁
烧写完成后,按下板载 RST 按钮重启
打开 ESPlorer IDE (需要提前安装好 Java)
选择好串口号将 DTR 和 RTS 点亮,波特率选择 115200,点击 Open 打开串口
按下板载 RST 键复位,自动开始格式化文件系统
格式化完成,自动打印出模块信息
关于乱码
在上面的图片中可以看到一行乱码,这个问题在官方文档中有说明。NodeMCU 的启动波特率为 74880,启动完毕后即切换为工作波特率(115200),而在我们使用的 115200 波特率下,启动调试信息自然会是乱码。我们将波特率设为 74880 即可看到启动调试信息
NodeMCU 在上电、复位时会自动运行 init.lua,现在我们开始为它编写程序
在左侧代码窗口写一段循环输出 Hello NodeMCU 的代码
1 | tmr.create():alarm(1000, tmr.ALARM_AUTO, function() |
将代码保存为 init.lua,然后点击下方的 Save to ESP
程序将被写入到 NodeMCU 中,并且会自动运行
§和一个字符可以组成是我的世界中控制字体颜色样式(如木牌、服务器名称)的标识符。例如:
1 | §cEnd of The Century §lSurvival |
上面这段文字在我的世界中的显示效果即为:
End of The Century Survival
现在我们需要通过代码来对颜色标识符进行转换,使其成为可以被浏览器解析的 HTML 代码
1 | public function motd2Html($motd) |