看了那么多书,真心发现一个道理:看懂了并不表示会说会用。

怎样改变 int 的第二个字节;

答:一种是采用位运算。
还可以通过将 int 转换成二进制的字符串,针对字符串进行操作。
(可我当时是什么情况呢,我忘了 int 有几个字节了)
面试题-2021-08-23-14-18-06

Java 怎么实现乘以 2 的操作;

答:通过移位操作的左移运算;(这个也要忘掉?)

介绍下二叉树

答: 每个节点最多有 2 个子树的树结构。
使用场景:常被用于实现二叉查找树和二元堆积。
存储表示:通过数组和链接串列来存储。
访问二叉树的方法:前序遍历,中序遍历,后序遍历。
参考资料: 二叉树-维基百科
(还是将数据结构和算法恶补下吧,基础太薄弱了)

view 中的draw()onDraw()区别

答:

  • onDraw()draw()方法的一部分;
  • 自定义 View 时只需要重写onDraw()方法;
    (通过源码public void draw(Canvas canvas) ,
    发现在draw()方法中,对onDraw进行了调用)
1
2
3
4
5
6
7
8
9
10
11
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/

When implementing a view, implement onDraw instead of draw(Canvas)

参考资料:

冒泡排序

两两比较,较小的往上冒,较大的往下沉。(对相邻的两个元素依次比较和调整)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class Test {
public static void main(String[] args) {
printArray(arr);
bubbleSort(arr);
printArray(arr);
}

private static final int arr[] = { 3, 8, 7, 2, 1, 5, 6, 9, 0 };

public static void bubbleSort(int[] arr) {
int len = arr.length;
if (len <= 1) {
return;
}

for (int i = 0; i < len - 1; i++) {
// 之所以 len-1-i, 是因为len-1-i之后的元素已经排序完成
// (每循环一次,就能将一个最大值沉底)
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
}
}
}

public static void swap(int[] arr, int i, int j) {
if (i < 0 || j < 0) {
return;
}

int len = arr.length;
if (i == j || i >= len || j >= len) {
return;
}

int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}

public static void printArray(int[] arr) {
StringBuilder sb = new StringBuilder();
for (int a : arr) {
sb.append(a).append(",");
}
String result = sb.substring(0, sb.length() - 1).toString();
System.out.println(result);
}

} /* Output:
3,8,7,2,1,5,6,9,0
0,1,2,3,5,6,7,8,9
*/// ~


参考资料

问题:
小明一家要过桥,夜晚要用灯,小明 1 秒,弟弟 3 秒,爸爸 6 秒,妈妈 8 秒,爷爷 12 秒,他们只有 30 秒,如何过桥?

解题关键:
要想到,并不是每次都让小明参与过河(虽然小明的速度最快),这样最低得 33s。
可以让小明和弟弟一起先过去,小明回来,再让妈妈和爷爷一起过去,弟弟拿灯回来,小明和爸爸过去,小明回来,小明和弟弟一起过去

参考答案

小明和弟弟过去,3 秒
小明回来,1 秒
小明和爸爸过去,6 秒
小弟弟回来,3 秒
妈妈和爷爷过去,12 秒
小明回来,1 秒
小明和弟弟过去,3 秒
3+1+6+3+12+1+3=29 秒
30 秒都用不了

参考资料

拼接字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 语法:CONCAT(str1,str2,…)
-- 返回结果为连接参数产生的字符串。
select concat('a','b');
-- 如有任何一个参数为NULL ,则返回值为 NULL。
select concat('a',null,'b');



-- 语法:CONCAT_WS(separator,str1,str2,…)
-- CONCAT_WS,表示 CONCAT With Separator
-- 如果分隔符为 NULL,则结果为 NULL。
SELECT CONCAT_WS(null,1,2);
-- 函数会忽略任何分隔符参数后的 NULL 值。这是和MySQL中concat函数不同的地方、concat_ws函数在执行的时候,不会因为NULL值而返回NULL。(这点很重要)
SELECT CONCAT_WS(',','First name',NULL,'Last Name');

GROUP_CONCAT 只有一列时如何拼接

完整的语法如下:group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator ‘分隔符’])(分隔符默认逗号)

示例
sql常见操作-2021-08-25-10-49-37

1
2
SELECT 1, GROUP_CONCAT(id SEPARATOR ',') ids FROM `user` GROUP BY 1;
SELECT 1, GROUP_CONCAT(id ORDER BY id desc SEPARATOR ',')ids FROM `user` GROUP BY 1;

sql常见操作-2021-08-25-10-50-11

1
2
3
-- 获取某列的组合
SELECT GROUP_CONCAT(id ORDER BY id desc SEPARATOR ',')ids FROM `user` GROUP BY '';
SELECT GROUP_CONCAT(DISTINCT nickname ORDER BY nickname desc SEPARATOR ',')nickname FROM `user` GROUP BY '';

sql常见操作-2021-08-25-10-56-01
sql常见操作-2021-08-25-10-58-34

字符串拆分

1
2
3
4
5
6
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX('7654,7698,7782,7788',',',help_topic_id+1),',',-1) AS num
FROM
mysql.help_topic
WHERE
help_topic_id < LENGTH('7654,7698,7782,7788')-LENGTH(REPLACE('7654,7698,7782,7788',',',''))+1

mysql 字符串拆分实现 split 功能
MySQL——字符串拆分(含分隔符的字符串截取)_逗比的小博客-CSDN 博客_mysql 字符串分割

查询某个字段的值出现多于 1 次的

1
SELECT id,flow_id, COUNT(flow_id) FROM orders GROUP BY flow_id HAVING count(flow_id)>1;

是否为空

1
select * from product where weight is null

获取最大值/最小值

1
2
3
4
5
6
7
8
9
10
11
12
13
# 最小值
select min(column_name) from table_name;
select num from table_name order by num;

# 最大值
select max(column_name) from table_name;
select num from table_name order by num desc;

# 获取最大值所在行
SELECT *
FROM orders
WHERE final_amount = (SELECT MAX(final_amount)
FROM orders);

参考资料

判断记录是否存在,不存在则插入存在则更新的场景

创建表

1
2
3
4
5
6
CREATE TABLE `clients2` (
`client_id` int(8) NOT NULL AUTO_INCREMENT,
`client_name` varchar(25) DEFAULT NULL,
`client_type` int(8) DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

不存在则插入存在则更新的场景

1
2
# 如果表中不存在则插入指定值,如果存在则给`client_type`增加1
INSERT INTO clients (clients.`client_id`, clients.`client_name`, clients.`client_type`) VALUES (1, "Lou12", 3) ON DUPLICATE KEY UPDATE clients.`client_type`=clients.`client_type`+1;

https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html

插入或更新时的 NULL 字段处理

想法来自【小白】

1
2
3
4
5
6
7
8
9
# 如果待插入的数据不为NULL,则改变原来的为新值
SET @title = '新标题234';
INSERT INTO goods (goods_id,title) VALUES (9934,IFNULL(@title,'')) ON DUPLICATE KEY UPDATE title=IF(VALUES(title)='',title,VALUES(title));
SELECT * FROM goods WHERE goods_id =9934;

# 如果待插入的数据为NULL,则不改变原来的
SET @title = NULL;
INSERT INTO goods (goods_id,title) VALUES (9934,IFNULL(@title,'')) ON DUPLICATE KEY UPDATE title=IF(VALUES(title)='',title,VALUES(title));
SELECT * FROM goods WHERE goods_id =9934;

和 0 做比较避免出现负值

https://bbs.csdn.net/topics/392371054

1
2
3
4
-- 和0做比较避免出现负值
update products set stocks=greatest(stocks-10,0) where product_id=55635

UPDATE goods AS g SET stock = greatest((SELECT SUM(stocks) FROM products AS p WHERE p.`goods_id` = g.`goods_id`), 0) WHERE goods_id=1234

没有时插入或存在时忽略

1
INSERT IGNORE INTO task_link (user_id, task_id) VALUES (20021413, 50000)

duplicate entry for key

1
2
SELECT GROUP_CONCAT(id),user_id,task_id,count(1) as cnt FROM task_link group by user_id,task_id having cnt > 1;
delete from task_link where id in (100,137,131,138,136,125,124);

依据两个字段来更新或插入表的其他字段

  1. 要先为这两个字段添加一个组合的唯一索引;

  2. 使用语句来更新或插入

1
2
insert into task_bonus_user (user_id,task_id,task_bonus_id) values (?,?,?)
on duplicate key update task_bonus_id = values(task_bonus_id)

去除小数点和后面的 0

MySQL 去掉字符串前后或中间的某一字符串_strggle_bin 的博客-CSDN 博客_mysql 去掉前两个字符

1
UPDATE cc_brief_video_author SET user_id = TRIM(TRAILING '.0' from user_id)

删除重复的关键词

1
2
3
4
5
6
7
DELETE from cc_brief_keyword_v2 WHERE id not in (
SELECT min(id) FROM cc_brief_keyword_v2 GROUP BY keyword HAVING count(keyword) > 1
)
and
keyword in (
SELECT keyword FROM cc_brief_keyword_v2 GROUP BY keyword HAVING count(keyword) > 1
)

数据库备份

如果是记录表,且不对外提供查询操作可以这样处理。

快速备份的方案,具体操作如下:

  1. 创建一个和 order_info 一样的新表(表结构、索引)。
    – 执行 DDL 语句
    create table order_info_new like order_info;

  2. 修改 order_info 的表名为 order_info_20220101,用日期做后缀方便以后查询
    – 执行 DDL 语句
    alter table order_info rename to order_info_20220101;

  3. 修改 order_info_new 为 order_info。
    – 执行 DDL 语句
    alter table order_info_new rename to order_info;

获取表结构

mysql 获取所有的表结构及备注_阳水平的博客-CSDN 博客_mysql 获取表备注

1
2
3
4
5
6
7
-- 获取所有表信息
SELECT
*
FROM
information_schema.`TABLES`
WHERE
TABLE_SCHEMA = (select database())
1
2
3
4
5
6
7
8
-- 获取所有表名和备注
SELECT
TABLE_NAME 表名,
TABLE_COMMENT 备注
FROM
information_schema.`TABLES`
WHERE
TABLE_SCHEMA = (select database())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 获取所有的表结构及备注
SELECT
TABLE_SCHEMA AS '库名',
TABLE_NAME AS '表名',
COLUMN_NAME AS '列名',
ORDINAL_POSITION AS '列的排列顺序',
COLUMN_DEFAULT AS '默认值',
IS_NULLABLE AS '是否为空',
DATA_TYPE AS '数据类型',
CHARACTER_MAXIMUM_LENGTH AS '字符最大长度',
NUMERIC_PRECISION AS '数值精度(最大位数)',
NUMERIC_SCALE AS '小数精度',
COLUMN_TYPE AS '列类型',
COLUMN_KEY 'KEY',
EXTRA AS '额外说明',
COLUMN_COMMENT AS '注释'
FROM
information_schema.`COLUMNS`
WHERE
TABLE_SCHEMA = (select database())
ORDER BY
TABLE_NAME,
ORDINAL_POSITION;

一直觉得自己的Java基础还可以,真的在面试的时候才发现,还是太肤浅了(我根本没法表达清楚)。

存储单位

  • 位(bit),计算机存储信息的最小单位,二进制的一个“0”或者“1”表示一位。
  • 字节(Byte),计算机存储容量基本单位是字节,8个二进制位表示一个字节。
  • (字符,是一种标记符号(像a,b,A),同以上的存储单位不是一回事。)

    计算机内存和硬盘等存储空间的管理都是以字节为基本单位,每个字节都有自己的编号,而“字符-Char”是
    人们用作标记的符号,如’A’, ‘-‘等,每个字符都有约定的抽象含义。

基础类型

在Java中有8种基本数据类型 —— 4种整型,2种浮点类型,1种表示Unicode编码的字符单元的字符类型,
1种表示真值的boolean类型。(一个字节8位)

  1. 整型

    1
    2
    3
    4
    5
    类型          存储需求            bit数            取值范围            备注
    int 4字节 4*8
    short 2字节 2*8 -32768~32767
    long 8字节 8*8
    byte 1字节 1*8 -128~127
  2. 浮点型

    1
    2
    3
    类型          存储需求            bit数            取值范围            备注
    float 4字节 4*8 (区别于double,有后缀`F`)
    double 8字节 8*8
  3. char类型

    1
    2
    类型          存储需求            bit数            取值范围            备注
    char 2字节 2*8
  4. boolean类型

    1
    2
    类型          存储需求            bit数            取值范围            备注
    boolean 1字节 1*8 false/true

(对于范围很大的数,用BigDecimal, BigInteger来表示。)

参考资料

Android 屏幕尺寸对应文件夹

1
2
3
4
5
6
HVGA  : mdpi
WVGA : hdpi
FWVGA : hdpi
QHD : hdpi
720P : xhdpi
1080P : xxhdpi

icon

1
2
3
4
5
: 48x48
: 72x72
: 96x96
: 144x144
: 192x192

https://stackoverflow.com/questions/13639263/whats-the-correct-size-icon-for-drawable-xxhdpi

更新您的应用以充分利用新款 Android 旗舰设备上更大的纵横比

icon

名称 尺寸 位置
MDPI 48x48 mipmap-mdpi/ic_launcher.png
HDPI 72x72 mipmap-hdpi/ic_launcher.png
XHDPI 96x96 mipmap-xhdpi/ic_launcher.png
XXHDPI 144x144 mipmap-xxhdpi/ic_launcher.png
XXXHDPI 192x192 mipmap-xxxhdpi/ic_launcher.png
1
2
3
mkdir res && cd res
mkdir mipmap-mdpi mipmap-hdpi mipmap-xhdpi mipmap-xxhdpi mipmap-xxxhdpi
ic_launcher.png

Manifest 中注册以内部类形式存在的 Activity

问题

  • 在《Android 编程权威指南》P127 中,作者建议我们坚持 AUF(Always Use Fragments)原则,即“总是使用 fragment”;
    另外作者封装了一个很好用的SingleFragmentActivity类,但是这个类通常只有一句话,。
    个人觉得,为每一个 Activity 都建立一个文件有点浪费。
    可是使用 Activity(四大组件之一),必须在 Manifest 中注册。
    那么能不能将所有这类 Activity 放在一个类中进行管理呢?
    通过搜索关键字:android manifest innerclass 找到了方法;

解答

  1. As someone pointed out, in AndroidManifest, use the $ sign, like:
    <activity android:name=".A$B">
  2. Declare class B as static:
    public static class B

例如

【Activity 管理类】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//: .../activity/ActivityMgr.java
public class ActivityMgr {

public static void start(Activity context, Class clazz){
Intent intent = new Intent(context, clazz);
context.startActivity(intent);
}

public static class LoginActivity extends SingleFragmentActivity {
@Override
public Fragment createFragment() {
return new LoginFragment();
}
}


public static class ForgetPasswordActivity extends SingleFragmentActivity {
@Override
public Fragment createFragment() {
return new ForgetPasswordFragment();
}
}

public static class RegisterActivity extends SingleFragmentActivity {
@Override
public Fragment createFragment() {
return new RegisterFragment();
}
}

public static class AddDeviceActivity extends SingleFragmentActivity {
@Override
public Fragment createFragment() {
return new AddDeviceFragment();
}
}
}

【Activity 注册】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<activity
android:name=".activity.ActivityMgr$LoginActivity"
android:clearTaskOnLaunch="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

<activity
android:name=".activity.ActivityMgr$RegisterActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".activity.ActivityMgr$ForgetPasswordActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".activity.ActivityMgr$AddDeviceActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
</activity>

【启动对应 Activity】

1
2
3
4
5
// 启动忘记密码Activity
ActivityMgr.start(mContext, ActivityMgr.ForgetPasswordActivity.class);

// 启动注册Activity
ActivityMgr.start(mContext, ActivityMgr.RegisterActivity.class);

扩展

  • 同样的方式也可以用于 Receiver 的注册;

参考资料

Android Material and appcompat Manifest merger failed - Stack Overflow

1
2
3
4
<!-- In my case, this is working perfectly.. I have added below two line codes inside manifest file -->
<application
tools:replace="android:appComponentFactory"
android:appComponentFactory="whateverString">

Fragment中监听返回键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//主界面获取焦点,用来监听返回键
private void getFocus() {
View view = getView();
if (view == null) {
return;
}

view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
// 监听到返回按钮点击事件
if (mCbControlSelectAll.getVisibility() == View.VISIBLE) {
sync(false);
return true;
}
}
return false;
}
});
}

通过调用 fragment 的 isAdded() 方法,来判断当前的 fragment 是否阵亡。

  • 具体用法参考:com.example.android.architecture.blueprints.todoapp.tasks.TasksContract.isActive();
  • isAdded()文档:Return true if the fragment is currently added to its activity.

How to implement onBackPressed() in Fragments?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface OnBackPressedListener {
public void doBack();
}

// create method to set listener in CustomActivity
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}

// in override onBackPressed implement something like that
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}

// in your fragment in onCreateView you should add our listener
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = getActivity();
((CustomActivity)activity).setOnBackPressedListener(new OnBackPressedListener(){
@override
public void doBack(){
// do your logic
}
});
return view;
}

Android 7.0 webview 不自动刷新

当 webview 所在的 activity 采用了以下主题时,Android7.0 设备将无法正常运行:

1
2
3
4
5
6
<style name="WelcomeBg" parent="@android:style/Theme.DeviceDefault.NoActionBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowBackground">@null</item>
</style>

之所以有这样的改变,目的是想要提升启动 Activity 的性能,哪里知道 7.0 之后会遇到无法正常渲染 WebView 的问题。

解决办法是:
直接使用默认主题,而不再对其包装:

1
@android:style/Theme.DeviceDefault.NoActionBar

获取 WebView 的点击元素

可以通过搜索关键字:HitTestResult getHitTestResult来知道更多内容;

注意:X5WebView,来源于腾讯 TBS 系统,是另外一个继承体系(可以通过打印view.getClass()的方式查看其继承体系)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private void setLongClick(final View view) {
//长按点击事件
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//响应长按事件(如果webview继承自安卓原生系统)
if (view instanceof WebView) {
WebView.HitTestResult result = ((WebView) view).getHitTestResult();
if (result != null) {
int type = result.getType();
//判断点击类型如果是图片
if (type == WebView.HitTestResult.IMAGE_TYPE || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
//弹出对话框
showDialog(result.getExtra());
}
}
} else if (view instanceof X5WebView) {
//响应长按事件(如果webview继承自腾讯的TBS系统)
Log.i(TAG, "onLongClick: x5");
com.tencent.smtt.sdk.WebView.HitTestResult hitTestResult = ((X5WebView) view).getHitTestResult();
if (hitTestResult != null) {
int type = hitTestResult.getType();
if (type == X5WebView.HitTestResult.IMAGE_TYPE || type == X5WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
showDialog(hitTestResult.getExtra());
}
}
}
return false;
}
});
}

参考资料

需要登录网页授权的页面处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
webSettings.setUseWideViewPort(true);
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setLoadWithOverviewMode(true);
webview.setWebViewClient(getWebViewClient());

private WebViewClient getWebViewClient() {
return new WebViewClient() {
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
// [Android-WebView's onReceivedHttpAuthRequest() not called again - Stack Overflow](https://stackoverflow.com/questions/20399339/android-webviews-onreceivedhttpauthrequest-not-called-again)
final EditText usernameInput = new EditText(mContext);
usernameInput.setHint("Username");

final EditText passwordInput = new EditText(mContext);
passwordInput.setHint("Password");
passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);

LinearLayout ll = new LinearLayout(mContext);
ll.setOrientation(LinearLayout.VERTICAL);
ll.addView(usernameInput);
ll.addView(passwordInput);

AlertDialog.Builder authDialog = new AlertDialog
.Builder(mContext)
.setTitle("Authentication")
.setView(ll)
.setCancelable(false)
.setPositiveButton("OK", (dialog, whichButton) -> {
String username = usernameInput.getText().toString();
String password = passwordInput.getText().toString();
handler.proceed(username, password);
Toast.makeText(mContext, username + ":" + password, Toast.LENGTH_LONG).show();
dialog.dismiss();
})
.setNegativeButton("Cancel", (dialog, whichButton) -> {
dialog.dismiss();
view.stopLoading();
});

authDialog.show();
}
};
}
0%