Kernel panic – not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

这是一个非常经典的 Linux 启动错误。根据截图中的关键信息:

核心错误信息: Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

分析原因: 这个错误表明 Linux 内核已经成功加载,但是它无法挂载根文件系统(Root Filesystem)。简单来说,内核启动了,但找不到真正的操作系统文件在哪里。

unknown-block(0,0) 这个特定的代码通常指向以下几个最常见的原因:

  1. initramfs/initrd 损坏或丢失(最常见)
    • Linux 启动需要一个临时的文件系统(initramfs)来加载加载根分区所需的驱动程序。
    • 如果在上次系统更新(例如 apt upgrade)过程中,initrd.img 文件生成失败(可能因为 /boot 分区满了,或者中途断电),内核就无法识别硬盘或文件系统,从而报错。
  2. GRUB 配置错误
    • 引导加载程序(GRUB)传递给内核的 root= 参数指向了一个不存在的设备,或者 UUID 发生了变化。
  3. VMware 虚拟化特定的驱动问题
    • 截图显示你在使用 VMware Virtual Platform
    • 如果你最近更改了虚拟机的硬盘控制器类型(例如从 LSI Logic 改为 PVSCSI),而 initramfs 里没有包含新的驱动,也会导致内核找不到硬盘。
  4. 内核版本不匹配
    • 你正在尝试启动的内核版本 5.15.0-164-generic 可能有问题,或者与其配套的 initrd 文件不匹配。

如何修复(建议步骤):

方法 1:尝试启动旧内核(最简单)

  1. 重启虚拟机。
  2. 在启动过程中,按住 Shift 键(或 Esc 键)进入 GRUB 菜单
  3. 选择 “Advanced options for Ubuntu”(Ubuntu 高级选项)。
  4. 列表中会有多个内核版本。选择一个带有版本号较旧的内核(不要选带有 recovery mode 的,除非普通模式也不行)。
  5. 如果旧内核能成功进入系统,说明是新内核的 initramfs 坏了。
  6. 进入系统后,运行以下命令修复:
    • sudo dpkg --configure -a
    • sudo update-initramfs -u -k all
    • sudo update-grub
  7. 注意:如果你的 /boot 分区满了,你需要先清理旧内核释放空间。

方法 2:使用 Live CD/ISO 修复 如果方法 1 无效,你需要:

  1. 加载 Ubuntu 安装镜像(ISO)启动虚拟机,选择 “Try Ubuntu”。
  2. 挂载原来的系统磁盘,并使用 chroot 进入环境重新生成 initramfs(这个过程比较复杂,建议先试方法 1)。

总结: 这大概率是一次系统更新导致 initramfs 生成不完整引起的。尝试通过 GRUB 菜单引导旧内核通常能解决问题。

java.lang.ClassCastException: android.view.AbsSavedState$1 cannot be cast to androidx.appcompat.widget.AppCompatSpinner$SavedState

今天遇到一个返回上一个Fragment闪退的问题,下面是大致代码:

// xxx_layout.xml
<layout>
    <include layout="@layout/view_edit_spinner" />
    <include layout="@layout/view_edit_textview" />
</layout>

// view_edit_spinner.xml
<LinearLayout>

    <androidx.appcompat.widget.AppCompatSpinner
            android:id="@+id/edit_value"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
</LinearLayout>

// view_edit_textview.xml
<LinearLayout>
    <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/edit_value"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
</LinearLayout>

第一次进入页面正常,当跳转到下一个页面,再返回当前页面时,会报错闪退,而且是系统平台级的,经过排查,是由于引用其他布局文件,不同控件的resId 一样,导致系统尝试恢复原来状态时类型转换错误。

解决方法:android:id=”@+id/edit_value” 中的id不同控件改成不一样的即可

RecyclerView显示所有元素,不需要包含在NestedScrollView中

import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.RecyclerView

class DynamicHeightRecyclerView(context: Context, attrs: AttributeSet) :
    RecyclerView(context, attrs) {

    override fun onMeasure(widthSpec: Int, heightSpec: Int) {
        super.onMeasure(
            widthSpec,
            MeasureSpec.makeMeasureSpec(Int.MAX_VALUE shr 2, MeasureSpec.AT_MOST)
        )
    }
}

Android Adapter调用notifyDataSetChanged()列表不更新的问题

目前发现一个Adapter调用notifyDataSetChanged()列表不更新的问题,代码如下:
mChannelList = channelListBean.getList();
huodaoInfoAdapter.notifyDataSetChanged();

原因:channelListBean.getList()和mChannelList是两个不同的变量,内存地址不同,赋值语句将新的内存地址赋给mChannelList,而Adapter中保留的list还是原来的内存地址。

解决方法:

if (!mChannelList.isEmpty()) {
  mChannelList.clear();
}
mChannelList.addAll(channelListBean.getList());

huodaoInfoAdapter.notifyDataSetChanged();

小米手机MIUI抓取蓝牙日志

1.打开开发者选项,打开蓝牙调试日志和蓝牙数据包日志开关

2.在拨号盘输入一次  *#*#5959#*#*  即开始抓蓝牙日志

3.操作APP,进行蓝牙通信

4.再拨号盘输入一次  *#*#5959#*#*

5.等待大概半分钟,在文件管理器中 /sdcard/MIUI/debug_log下会生成蓝牙日志文件

6.使用wireshark打开蓝牙日志文件

javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate

MqttException (0) – javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate not valid until Fri Feb 28 09:25:13 GMT+08:00 2020 (compared to Mon Jan 21 17:46:42 GMT+08:00 2013)

SSL连接报错,原因是Android终端时间不对,和当前时间相差太大

记录一下Fragment连续跳转2次返回首页时第三个页面还显示的问题

有个需求是 “ A页面 ”跳转“ B页面 ”然后跳转“ C页面 ”。

在使用Fragment进行页面跳转的时候,第一次跳转(A->B)加.addToBackStack(null) ,第二次跳转(B->C)不加,然后点击返回按钮

期望状态是B、C消失,A出现

可是最终效果是返回到了A页面同时C页面还在,并没有被destroy,当进入另一个界面返回到A,这时候C会重新生成

原因:点击返回键只回滚了第一次跳转(A->B)加.addToBackStack(null) ,C页面没有影响,也不会重新生成。A重新跳转到其他页面变成(A、C->B) 加.addToBackStack(null) ,返回的时候会回滚A、C两个页面的状态

解决方案:B->C)加.addToBackStack(null)

阿拉伯数字转中文汉字

在使用某些语音合成引擎的时候,遇到一些问题,比如三位数的数字110,语音合成播放是幺幺零,但是我想让她合成一百一十,怎么做呢?

所以我打算把阿拉伯数字转换成中文汉字就可以正常合成了,代码如下:

public class NumberHanFormat {
    public static final String ZERO = "零";
    public static final String NEGATIVE = "负";
    public static final String SPACE = " ";
    public static final String MILLION = "百万";
    public static final String THOUSAND = "千";
    public static final String HUNDRED = "百";
    public static final String[] INDNUM = {"零", "一", "二", "三", "四", "五", "六",
            "七", "八", "九", "十", "十一", "十二", "十三",
            "十四", "十五", "十六", "十七", "十八", "十九"};
    public static final String[] DECNUM = {"零","一十","二十", "三十", "四十", "五十", "六十",
            "七十", "八十", "九十"};

    //数字转换汉字
    public String format(int i) {

        StringBuilder sb = new StringBuilder();

        if(i == 0) {
            return ZERO;
        }

        if(i < 0) {
            sb.append(NEGATIVE);
            i *= -1;
        }


        if(i >= 1000000) {
            sb.append(numFormat(i / 1000000)).append(MILLION);
            i %= 1000000;

        }

        if(i >= 1000) {
            sb.append(numFormat(i / 1000)).append(THOUSAND);

            i %= 1000;
        }

        if(i < 1000){
            sb.append(numFormat(i));
        }

        return sb.toString();
    }

    // 3位数转汉字
    public String numFormat(int i) {

        StringBuilder sb = new StringBuilder();

        if(i >= 100) {
            sb.append(INDNUM[i / 100]).append(HUNDRED);
        }

        int j = i%100;

        if(j != 0) {
            if(j >= 20) {
                sb.append(DECNUM[j / 10]);
                if(j % 10 != 0) {
                    sb.append(INDNUM[j % 10]);
                }
            } else {
                if(i>100) {
                    if(j<10) {
                        sb.append(DECNUM[j / 10]).append(INDNUM[j % 10]);
                    } else {
                        sb.append(DECNUM[1]).append(INDNUM[j % 10]);
                    }
                } else {
                    sb.append(INDNUM[j]);
                }
            }
        }

        return sb.toString();
    }
}

调用方法:

public static NumberWordFormat mNumberWordFormat;
mNumberWordFormat = new NumberWordFormat();
mNumberWordFormat.format(power1)

网站黑白css

将此段css放到<header>标签内即可

<style type=”text/css”>
html{ filter: grayscale(100%); -webkit-filter: grayscale(100%); -moz-filter: grayscale(100%); -ms-filter:
grayscale(100%); -o-filter: grayscale(100%); filter: url(“data:image/svg+xml;utf8,<svg xmlns=\’
http://www.w3.org/2000/svg\’><filter id=\’grayscale\’><feColorMatrix type=\’matrix\’ values=\’0.3333
0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1
0\’/></filter></svg>#grayscale”); filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); –
webkit-filter: grayscale(1);}
</style>