1、framework调试入门及相关资源
2、Android原生深色模式理解
- 内容:
- 单独处理某个应用深色模式的方法:
- 在主题中添加
<item name="android:forceDarkAllowed">true</item>。 - 设置整个应用进入深色模式:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);。 - 设置某个Activity进入深色模式:
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);。
- 在主题中添加
- 单独处理某个应用深色模式的方法:
3、屏蔽WebView的文本控件长按事件
- 解决方案:通过设置WebView的长按监听并返回true来屏蔽长按事件。
webView.setLongClickable(true); webView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { webView.setHapticFeedbackEnabled(false); // 屏蔽长按振感 return true; // 屏蔽长按操作 } });
4、封装自定义View的兼容性
- 内容:封装自定义View时,除了开放指定接口外,也应兼容原生接口,如Dialog的
isShowing、dismiss、setOnDismissListener等。
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class CustomDialog extends Dialog {
private Button closeButton;
public CustomDialog(Context context) {
super(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_custom); // 设置布局文件
closeButton = findViewById(R.id.close_button);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss(); // 使用原生的dismiss方法关闭对话框
}
});
}
// 兼容原生的isShowing方法
@Override
public boolean isShowing() {
return super.isShowing();
}
// 兼容原生的dismiss方法
@Override
public void dismiss() {
super.dismiss();
}
// 兼容原生的setOnDismissListener方法
@Override
public void setOnDismissListener(OnDismissListener listener) {
super.setOnDismissListener(listener);
}
// 可以根据需要开放额外的接口
public void setTitleText(String title) {
// 假设你有一个标题TextView
TextView titleView = findViewById(R.id.title_text_view);
if (titleView != null) {
titleView.setText(title);
}
}
}
5、判断页面是WebView还是原生APP
- 方法:
- 使用Android Studio的Layout Inspector。
- 打开手机开发者模式,开启布局边界显示,观察边界框数量。
- 通过抓包、查看日志或缓存来判断。
6、配置资源更新
- 内容:在Android开发中,需要注意及时更新configuration,特别是在需要保持应用字体不随系统变化时。
@Override public Resources getResources() { Resources resources = super.getResources(); if (resources.getConfiguration().fontScale != 1) { Configuration configuration = new Configuration(); configuration.setToDefaults(); resources.updateConfiguration(configuration, resources.getDisplayMetrics()); } return resources; }
7、adb安装命令
- 内容:
adb install -r:强制覆盖安装。adb install -t:允许测试包安装。adb install -d:允许低版本系统安装。
8、获取带声调的拼音字符串
- 内容:
```java
import java.util.Arrays;
import java.util.Locale;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import android.text.TextUtils;
import android.util.Log;
public class PinyinHelper {
private static final String TAG = "PinyinHelper";
/**
* 获取汉字拼音,这里获取到的是带有声调的拼音字符串,比如强袭:qiang1 xi1
*
* @param chinese 汉字字符串
* @param caseType 大小写类型
* @return 拼音字符串
*/
public static String toPinyin(String chinese, int caseType) {
if (TextUtils.isEmpty(chinese)) {
return "";
}
char[] strChar = chinese.toCharArray();
HanyuPinyinOutputFormat hanYuPinOutputFormat = new HanyuPinyinOutputFormat();
// 输出设置,大小写,音标方式等
if (1 == caseType) {
hanYuPinOutputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
} else {
hanYuPinOutputFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);
}
hanYuPinOutputFormat.setToneType(HanyuPinyinToneType.WITH_TONE_NUMBER);
hanYuPinOutputFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
StringBuffer pyStringBuffer = new StringBuffer();
String[] pinyinArray;
try {
for (int i = 0; i < strChar.length; i++) {
if (Character.toString(strChar[i]).matches("[\\u4E00-\\u9FA5]+")) {
// 如果是汉字字符,将汉字的几种全拼都存到pinyinArray数组中
pinyinArray = PinyinHelper.toHanyuPinyinStringArray(strChar[i], hanYuPinOutputFormat);
// 取出汉字全拼的第一种读音并连接到字符串pyStringBuffer后
if (pinyinArray != null && pinyinArray.length > 0) {
// 特殊处理“长”字
if (strChar[i] == '长') {
pyStringBuffer.append("chang ").append(" ");
} else {
pyStringBuffer.append(pinyinArray[0]).append(" ");
}
} else {
pyStringBuffer.append(strChar[i]);
}
} else {
// 如果不是汉字字符,直接取出字符并连接到字符串pyStringBuffer
pyStringBuffer.append(strChar[i]);
}
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
Log.e(TAG, "toPinyin: BadHanyuPinyinOutputFormatCombination e = " + e);
}
return pyStringBuffer.toString().trim(); // 去除末尾多余的空格
}
}
关键点解释:
- 特殊处理“长”字:在处理每个字符时,检查是否为“长”字。如果是“长”字,则直接追加 "chang " 到
pyStringBuffer中。 - 其他字符处理:对于其他字符,继续使用
PinyinHelper库获取其拼音,并追加到pyStringBuffer中。 - 去除末尾多余空格:在返回结果之前,使用
trim()方法去除末尾的多余空格。
使用示例:
String chinese = "长河落日圆";
String pinyin = PinyinHelper.toPinyin(chinese, 1); // 1 表示小写
System.out.println(pinyin); // 输出: chang he2 luo4 ri4 yuan2
9、哈希字符串得到唯一值
在Android中,如果你需要将一串字符串转换为一个独一无二的数字,可以考虑使用哈希函数。虽然像MD5、SHA-1、SHA-256等哈希算法通常返回的是字符串(通常是十六进制表示),但你可以将这些字符串进一步转换为数字。以下是一些常见的方法和算法,可以帮助你生成一个独一无二的数字:
### 1. 使用哈希算法生成数字
你可以使用哈希算法生成一个哈希值,然后将这个哈希值转换为一个数字。以下是一些常见的哈希算法:
- **MD5**
- **SHA-1**
- **SHA-256**
- **SHA-512**
### 示例代码
以下是一个使用MD5哈希算法生成一个独一无二的数字的示例:
```java
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class UniqueNumberGenerator {
// 计算哈希值
public static long generateUniqueNumber(String input, String algorithm) {
try {
// 获取指定算法的MessageDigest实例
MessageDigest digest = MessageDigest.getInstance(algorithm);
// 计算哈希值
byte[] hashBytes = digest.digest(input.getBytes());
// 将字节数组转换为长整型数字
long uniqueNumber = bytesToLong(hashBytes);
return uniqueNumber;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Algorithm not found: " + algorithm, e);
}
}
// 将字节数组转换为长整型数字
public static long bytesToLong(byte[] bytes) {
long result = 0;
for (int i = 0; i < ˜; i++) {
result = (result << 8) | (bytes[i] & 0xFF);
}
return result;
}
public static void main(String[] args) {
String input = "Hello, World!";
String hashAlgorithm = "MD5";
// 生成独一无二的数字
long uniqueNumber = generateUniqueNumber(input, hashAlgorithm);
System.out.println("Input: " + input);
System.out.println("Unique Number (MD5): " + uniqueNumber);
}
}
代码解释
-
generateUniqueNumber 方法:
- 接受一个输入字符串和一个哈希算法名称(如 "MD5")。
- 使用
MessageDigest类来计算哈希值。 - 调用
bytesToLong方法将字节数组转换为长整型数字并返回。
-
bytesToLong 方法:
- 接受一个字节数组。
- 将字节数组转换为长整型数字。这里我们只取前8个字节(64位)来组成一个长整型数字。如果你需要更大的数字范围,可以考虑使用
BigInteger。
-
main 方法:
- 定义输入字符串和哈希算法(这里是 "MD5")。
- 生成并打印独一无二的数字。
输出示例
当你运行这个程序时,输出将类似于:
Input: Hello, World!
Unique Number (MD5): 18684752,
注意事项
- 哈希碰撞:虽然哈希算法(如MD5)生成的哈希值通常是唯一的,但理论上存在哈希碰撞的可能性。也就是说,不同的输入可能会生成相同的哈希值。
- 数字范围:长整型(
long)在Java中是64位,范围是-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807。如果你需要更大的数字范围,可以考虑使用BigInteger。 - 性能:哈希算法的计算通常很快,但对于大量数据或高并发场景,仍需考虑性能问题。
其他方法
除了哈希算法,还有一些其他方法可以生成独一无二的数字,例如:
- UUID:UUID(Universally Unique Identifier)可以生成一个128位的唯一标识符,可以将其转换为数字。
- 自定义算法:根据具体需求,可以设计自定义算法来生成独一无二的数字,例如结合时间戳、随机数等。
总之,使用哈希算法是一种常见且有效的方法,可以根据你的具体需求选择合适的算法和转换方式。
10、设置应用字体不跟随系统变化
@Override
public Resources getResources() {
//设置应用字体不跟随系统变化
Resources resources = super.getResources();
if (resources.getConfiguration().fontScale != 1) {
Configuration configuration = new Configuration();
configuration.setToDefaults();
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
}
return resources;
}
11、定时管理器
```java
import android.os.Handler;
import android.os.Looper;
public class TimerManager {
private static volatile TimerManager INSTANCE;
private final Handler mHandler;
private Runnable mTimeoutRunnable;
private OnTimeoutListener mListener;
private static final int DEFAULT_TIMEOUT = 10000;
private boolean isCancelled = false;
private TimerManager() {
mHandler = new Handler(Looper.getMainLooper());
}
public static TimerManager getInstance() {
if (INSTANCE == null) {
synchronized (TimerManager.class) {
if (INSTANCE == null) {
INSTANCE = new TimerManager();
}
}
}
return INSTANCE;
}
public void start(OnTimeoutListener listener) {
this.start(DEFAULT_TIMEOUT, listener);
}
public void start(int delayMillis, OnTimeoutListener listener) {
this.mListener = listener;
mTimeoutRunnable = new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onTimeout();
}
}
};
mHandler.postDelayed(mTimeoutRunnable, delayMillis);
isCancelled = false; // 重置取消标志
}
public void cancel() {
if (!isCancelled && mHandler != null && mTimeoutRunnable != null) {
mHandler.removeCallbacks(mTimeoutRunnable);
isCancelled = true; // 设置取消标志
}
}
public interface OnTimeoutListener {
void onTimeout();
}
}
关键点解释:
- 取消标志
isCancelled:引入了一个布尔变量isCancelled,用于标记cancel方法是否已经被调用过。 - 重置取消标志:在
start方法中,每次重新启动计时器时,重置isCancelled标志为false。 - 检查取消标志:在
cancel方法中,首先检查isCancelled标志。如果已经取消过,则不再执行removeCallbacks方法,否则执行并设置isCancelled为true。
使用示例:
TimerManager timerManager = TimerManager.getInstance();
timerManager.start(new TimerManager.OnTimeoutListener() {
@Override
public void onTimeout() {
// 处理超时事件
System.out.println("Timeout occurred!");
}
});
// 模拟外部多次调用 cancel 方法
timerManager.cancel();
timerManager.cancel();
timerManager.cancel();
这样,即使外部多次调用 cancel 方法,removeCallbacks 方法也只会被执行一次,从而避免了不必要的操作。