-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
206 lines (206 loc) · 58.2 KB
/
search.xml
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[Android EditText光标问题]]></title>
<url>%2F2020%2F03%2F31%2FAndroid-EditText%E5%85%89%E6%A0%87%E9%97%AE%E9%A2%98%2F</url>
<content type="text"><![CDATA[以前一直没有注意过 EditText 光标的问题,今天有人提了优化用户体验建议。自己就着手优化了下,不是什么大问题,但是还是有一些小坑,以此记录,避免下次在踩坑。 全局修改光标颜色全局光标颜色修改很容易,找到 AndroidManifest文件,查看 "android:theme="@style/AppTheme",查看 AppTheme的属性,其中 <item name="colorAccent">@color/colorAccent</item>就是设置全局的获取焦点后的光标颜色,可以修改这里变成我们需求的色值。XML设置的代码,跟往常一样即可。 PS:这个是全局修改,修改了这个属性的颜色值,项目中用到此颜色值的相关组件颜色都会产生变化,比如状态栏。建议慎重。 修改单个EditText光标颜色在 Android3.2 或者更高版本上面,EditText 有一个属性:android:textCursorDrawable,可以按照如下的方式进行设置。 创建光标颜色的 drawable 资源文件需要创建光标颜色的 drawable 资源文件。举例如下: 123456<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <size android:width="1dp" /> <solid android:color="#33a0ff" /></shape> 使用android:textCursorDrawable=""属性。XML 布局中,使用android:textCursorDrawable="@drawable/color_cursor",这个属性是用来控制光标颜色的。完整代码: 12345678910<EditText android:id="@+id/minutes" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/dp_15" android:background="@null" android:cursorVisible="true" android:textCursorDrawable="@drawable/color_cursor" android:focusableInTouchMode="true" /> 设置光标颜色与文本颜色一致很简单,将android:textCursorDrawable的值设置为"@null" ,"@null" 作用是让光标颜色和文本颜色保持一致。 光标显示与隐藏设置android:cursorVisible即可 123android:cursorVisible="true" 显示光标android:cursorVisible="false" 隐藏光标 设置光标位置EditText 如果有默认输入,光标获取焦点后,默认插入光标是在第一个位置的。用户体验不是很好,为了方便用户使用,需要把光标移动到最后位置,可以使用 setSelection 方法完成。如下例子: 1234EditText et = ... String text = "text"; et.setText(text); et.setSelection(text.length()); 取消EditText下划线可以通过背景属性设置,取消下划线。android:background="@null",这样操作会使的下划线消失的同时,默认边距也不存在。需要重新处理边距问题。 自定义style样式修改下划线光标颜色使用android:theme="@style/MyEditText"属性设置自定义主题。如下,需要先创建自己的style样式,然后使用属性设置。 123456<!--colorControlNormal 为没有获取焦点时候下划线的颜色--><!--colorControlActivated 为获取焦点时候光标与下划线的颜色--><style name="MyEditText" parent="Theme.AppCompat.Light"> <item name="colorControlNormal">@color/colorPrimary</item> <item name="colorControlActivated">@android:color/holo_orange_dark</item></style> 参考博客]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>EditText</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android 动态权限]]></title>
<url>%2F2020%2F03%2F02%2FAndroid-%E5%8A%A8%E6%80%81%E6%9D%83%E9%99%90%2F</url>
<content type="text"><![CDATA[从 Android 6 (API < 23)开始,Android 系统提供动态权限申请机制,对于一些敏感的权限,决定权交还给了用户,不再是强制申请了。App 在使用危险权限的时,需用户授权才可以进一步操作。旧的权限申请方式是静态的,只要 App 在 AndroidManifest.xml 中注册了权限,安装APP后默认就获取了这些权限。这种授权方式安全性较低,容易被垃圾 App 窃取用户信息。 随着系统的升级,Google 也意识到静态权限申请的弊端,所以在 Android6.0 中,对权限进行了重新梳理,将权限分为普通权限和危险权限: 普通权限 不影响用户隐私的权限,AndroidManifest.xml 中注册即可获取 危险权限 可以访问用户隐私数据的权限,必须获取用户的同意才可获得授权。如下图: 在 Android 中应该尽量使用隔离式动态权限申请,什么是隔离式呢,就是动态申请权限的时候,用户没有授权时,屏蔽相关功能即可,而不是打开App不授权的话,直接退出App,不让用户使用,这种权限使用方式用户体验太差。常见于华为手机的各种自带App,不给权限,直接退出。 动态权限申请过程检查权限Activity 继承 AppCompatActivity,首先检查是否已经赋予权限,如果没有授权,可以使用 checkSelfPermission(@NonNull Context context, @NonNull String permission)方法,通过返回值来判断。具体代码如下: 123456if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) { //已经授权,走正常逻辑操作,比如打电话,打开相册 } else { //没授权,去申请权限 } 申请权限上个步骤中,没有授权的话,需要去申请动态权限,可以通过requestPermissions(final @NonNull Activity activity,final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)来进行申请。需要定义一个静态变量作为requestCode。 1234private static final int REQUEST_CALL_PHONE = 100;//这行代码即为上面检查权限else里面的逻辑ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, REQUEST_CALL_PHONE); 于是在手机界面上会弹出权限提示框,为系统样式,不可修改。拒绝或者同意都会走到接下来的流程。 处理结果在onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)方法中处理接收到拒绝还是允许的结果消息。 12345678910111213141516@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case REQUEST_CALL_PHONE: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { //走正常逻辑操作,比如打电话,打开相册 } else { //弹框提示 } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } 如果用户选择同意,就可以调用拨打电话的按钮,同时这个对话框之后都不会出现了。 如果用户拒绝了,那就无法调用拨打电话的代码了。为了用户体验,可以弹出一个对话框,告知用户我需要这个权限,没有这个权限程序无法正常运行。 如果用户勾选了不再询问或者 禁止后不再询问,意味着用户永远地拒绝了相关的权限,同时这个对话框不会再弹出来了。为了挽救一下,我们可以弹框提示用户去设置里面手动开启权限。可以使用Android 提供的shouldShowRequestPermissionRationale(@NonNull Activity activity,@NonNull String permission)方法来判断用户是否选择了不再提示相关选项。 处理结果消息的代码,可以修改为:123456789101112131415161718@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case REQUEST_CALL_PHONE: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { callPhone(); } else { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)) { showTipDialog(); } else { goToSetting(); } } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } 以上就是动态权限申请的全部过程了。完整代码,见下面链接。 完整代码]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>动态权限</tag>
</tags>
</entry>
<entry>
<title><![CDATA[MAC上VSCode配置Flutter开发环境]]></title>
<url>%2F2019%2F12%2F12%2FMAC%E4%B8%8AVSCode%E9%85%8D%E7%BD%AEFlutter%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%2F</url>
<content type="text"><![CDATA[作为移动端开发者,虽然算不上是前端开发者,但是大前端是趋势,也有必要去了解一些跨平台框架,为未来做一点技术储备。Flutter 是 Google 推出的跨平台框架,之前在 Android Studio 上创建过新项目,比较方便,下载 Flutter & Dart 插件,下载 Flutter SDK,没有遇到太大的环境搭建上的问题。想学习一下 VSCode 上 Flutter 如何开发,加之是 MAC 电脑,配置环境变量搞了大半天。写篇笔记,做个记录。 Flutter SDK国内下载 Flutter SDK 需要科学上网,这点困难大家自己克服,如果不能科学上网,国内镜像应该也可以下载到。下载后,新建目录,解压 SDK,这个目录地址,是后面配置需要的,大家需要记住。 还需要下载代码编辑器 VSCode,因为我的电脑之前已经下载了 VSCode,这部分就省略了。 安装 Flutter 插件打开 VSCode,点击左边类似俄罗斯方块的图标,搜索 Flutter,点击安装,这个插件会直接安装 Flutter,Dart 开发环境。为了能在 VSCode 里面使用命令行,我们需要配置环境变量,之前在 Android Studio 中,创建 Flutter 应用只需要下载配置 Flutter SDK,安装 Flutter & Dart 插件即可,不需要配置环境变量。在 VSCode 配置全局环境变量时,浪费了很多时间,网上很多文章也没有写到点,特此记录。 配置环境变量1234567//打开配置文件vim ~/.bash_profile//‘pwd’指的是自己本地安装Flutter SDK 的路径export PATH=${PATH}:`pwd`/flutter/bin我的配置:export PATH=${PATH}:/Users/liangxiao/Documents/flutter/flutter/bin 可以直接使用上面的命令去配置,如果觉得不直观,也可以使用文本编辑器来配置,步骤如下:配置完记的保存。 12open ~/.bash_profileexport PATH=${PATH}:`pwd`/flutter/bin 配置完上面的这两个步骤,我以为就 OK 了,然后使用 flutter -h 命令去检查,直接打脸 bash: flutter: command not found才发现自己少了一个步骤,命令如下:1source ~/.bash_profile 执行完这个命令后,再次使用 flutter -h 命令去检查,终于显示 Flutter 命令帮助,配置成功了。 检查环境执行命令:1flutter doctor 可以看到图片上有对勾,有叉号,有感叹号,分别代表什么意思呢?首先有[!] ✗ 标志,表示本行检测不通过,需要做一些设置或者安装一些软件。 比如:12[!] Android toolchain - develop for Android devices (Android SDK 29.0.1)! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licens 执行提示命令: 1flutter doctor --android-licenses 然后无脑一路输入 y 就 OK 了。再次输入 flutter doctor检查,之前[!]的第二项,现在是对勾了。可以进行 Android 开发了。]]></content>
<categories>
<category>Flutter</category>
</categories>
<tags>
<tag>Flutter</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android隐式Intent记录]]></title>
<url>%2F2019%2F12%2F10%2FAndroid%E9%9A%90%E5%BC%8FIntent%E8%AE%B0%E5%BD%95%2F</url>
<content type="text"><![CDATA[最近研究 Android 原生分享,深入了解了一下隐式 Intent,平常 App 内跳转,常用的是显示 Intent,隐式 Intent 常见的就是 App 启动页设置,下面的代码相信大家都很熟悉,只是没想到习以为常的背后隐藏着小小的知识点。 1234567<activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> 隐式 Intent官方介绍: 创建隐式 Intent 时,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件中声明的 Intent-Filter 进行比较,从而找到要启动的相应组件。 如果 Intent 与 Intent-Filter 匹配,则系统将启动该组件,并向其传递 Intent 对象。 如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。 隐式 Intent 既可以启动当前应用的组件,也可以启动其他应用的组件。 启动其他应用组件 目标 activity 配置(其他应用) 12345678<activity android:name=".IntentActivity" android:label="IntentActivity"> <intent-filter> <action android:name="com.example.IntentDemo.action.a" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter></activity> Intent 代码:(当前应用) 1234567891011// 启动其他应用的ActivityIntent intent = new Intent();//actionintent.setAction("com.example.IntentDemo.action.a");//Category可以不设置,因为一般在AndroidManifest.xml会设置Default,startActivity方法中也会默认添加Default。if (intent.resolveActivity(getPackageManager()) != null) { LogUtils.e("match success"); startActivity(intent);} else { LogUtils.e("match failure");} IntentFilter 匹配规则隐式 Intent 调用分为两部分,一部分是 AndroidManifest 中组件的配置,一部分是Intent 对象的构建。当构建的 Intent 对象符合目标组件的配置的时候,才能成功启动目标组件。过滤信息有三种,分别是: action category data IntentFilter 中的 action、category 和 data 可以有多个,只有一个 Intent 同时匹配 action、category、data 才算完全匹配,只有完全匹配才能成功启动 Activity。 另外一点,一个activity中可以有多个 Intent-filter,一个 Intent 只要能匹配任何一组 Intent-filter 即可成功启动对应的activity。 隐式Intent解析]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Intent</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Glide知识记录]]></title>
<url>%2F2019%2F12%2F04%2FGlide%E7%9F%A5%E8%AF%86%E8%AE%B0%E5%BD%95%2F</url>
<content type="text"><![CDATA[Android 开发免不了加载图片,图片加载库也比较多,鉴于 Glide 是 Google 的亲儿子,做Android 开发,掌握 Glide 绝对不会吃亏,使用非常简单。 Glide 基本用法配置 Gradle配置 Gradle 依赖项,按照介绍配置依赖项,可能会有变化。 1234dependencies { implementation 'com.github.bumptech.glide:glide:4.10.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'} 配置 Permission根据项目情况,可能会需要以下这些权限,最主要的还是网络权限。123456789101112<!--添加网络权限--><uses-permission android:name="android.permission.INTERNET" /><!--允许访问网络状态--><uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE" /><!--读取外部存储权限--><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!--写入外部存储权限--><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> Glide 使用一行代码搞定图片下载与展示。如下所示:千万不要小瞧这一行代码。可以做到加载网络上的图片、加载手机本地的图片、加载应用资源中的图片等等。123456789Glide.with(this).load(URL).into(imageView);// 加载本地图片File file = new File(getExternalCacheDir() + "/image.jpg");Glide.with(this).load(file).into(imageView);// 加载应用资源int resource = R.drawable.image;Glide.with(this).load(resource).into(imageView); Glide 扩展使用Glide 还有很多扩展内容,常用的扩展内容大概是占位符,指定格式图片,例如 Gif,Error 图片等,还有指定图片大小等扩展功能。 123456789101112131415Glide.with(this) .load(url) .asGif() //.asBitmap() 设置静态图片 //.asFile() 文件格式,用于下载 //.asDrawable() // Drawable格式,显示图片 .placeholder(R.drawable.loading) 占位图 .error(R.drawable.error) 异常占位图 .override(100, 100) 指定图片大小 .apply(RequestOptions.circleCropTransform()) 加载圆形图片 .transition(DrawableTransitionOptions.withCrossFade()) 淡入淡出效果 .thumbnail( 0.1f ) 缩略图 0.1f会显示原始图像的10%的大小 //.centerCrop() 图像裁剪 图像可能不会完整显示 //.fitCenter() 图像将会完全显示 可能不会填满控件 .into(imageView); 缓存类型Gldie 默认是通过内存缓存与磁盘缓存来避免不必要的网络请求。如果有网络加载需求,可以自己设置跳过内存缓存或者跳过磁盘缓存。 内存缓存下面的代码可以跳过内存缓存,但是不会跳过磁盘缓存。1.skipMemoryCache( true ) 跳过内存缓存,默认是false PS:注意一个事实,对于相同的 URL ,如果你的初始请求没调用 .skipMemoryCache(true) 方法,你后来又调用了 .skipMemoryCache(true) 这个方法,这个资源将会在内存中获取缓存。当你想要去调整缓存行为时,确保对同一个资源调用的一致性。 磁盘缓存上面关闭了内存缓存,Glide 还是会用磁盘缓存,如何跳过磁盘缓存呢,如下面代码所示:只禁止磁盘缓存,不影响内存缓存,如果需要两个都禁止,可以同时设置。、 1.diskCacheStrategy(DiskCacheStrategy.NONE) 跳过磁盘缓存 磁盘缓存类型Glide 有多个选项去配置磁盘缓存行为,Glide 的磁盘缓存是相当复杂,Picasso 仅仅缓存了全尺寸的图像。然而 Glide 缓存了原始图像,全分辨率图像和另外小版本的图像。 12345DiskCacheStrategy.NONE 不缓存DiskCacheStrategy.RESOURCE 缓存转换后的版本DiskCacheStrategy.DATA 只缓存原来的全分辨率的版本DiskCacheStrategy.ALL 缓存所有版本DiskCacheStrategy.AUTOMATIC 默认选项,Glide 自己选择适合的缓存策略 Glide 常用操作如上,一些不常用的扩展操作,比如截取视频,下载图片等,想了解的同学可以自己去查查自己了解下。 Picasso 和 Glide 对比Glide 中文站 Glide]]></content>
<categories>
<category>Glide</category>
</categories>
<tags>
<tag>图片加载</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android中xml的tools属性]]></title>
<url>%2F2019%2F12%2F04%2FAndroid%E4%B8%ADxml%E7%9A%84tools%E5%B1%9E%E6%80%A7%2F</url>
<content type="text"><![CDATA[Android 开发过程中,布局文件是可以直接在 IDE 中看到效果的,有时候有些布局的效果是根据网络请求的结果来展示,我们在写布局的时候,为了查看布局的美观,就直接写固定值了。 比如这种情况:TextView 在 xml 中没有设置任何字符,而是在 activity 中设置了 text。因此为了在 IDE 中预览效果,你必须在 xml 中为 TextView 控件设置 android:text 属性。12345<TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World" /> 有些布局界面可能是需要固定值,但是根据网络请求来显示的话,如果我们这样写忘记删除的话,就会导致一些问题,明明不应该显示的地方,确显示了,还得花时间去定位问题,即使没有显示问题,最终的产品中一直都有这种代码。 tools 属性上面的情况,我们是有方法避免的,可以使用tools的命名空间和属性来解决这个问题。 12345678910xmlns:tools="http://schemas.android.com/tools"...<TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" tools:text="Hello World" /> ... tools 属性可以告诉Android Studio ,这些属性在运行时是被忽略的,只在设计布局的时候有效。比如上面的例子,Hello World 只在设计布局的时候展示,运行后的界面是不会显示Hello World 的。 tools 可以覆盖 xml 布局中 android 的所有标准属性,将 android: 换成 tools: 即可。同时在运行的时候就连tools:本身都是被忽略的,不会被带进apk中。 tools 属性种类tools 属性分为两种,一种是关于 xml 布局设计的,一种是影响 Lint 提示的,上面介绍的是 tools 最基本的用法,在 UI 设计的时候覆盖标准的 android 属性。下面介绍 Lint 相关属性。 Lint 相关属性123tools:ignore ignore属性是告诉Lint忽略xml中的某些警告。tools:targetApi tools:locale Lint会提示 ImageView 缺少 android:contentDescription 属性。我们可以使用 tools:ignore 来忽略这个警告 假设minSdkLevel 15,而你使用了api21中的控件比如RippleDrawable,则Lint会提示警告。为了不显示这个警告,可以使用 tools:targetApi=”LOLLIPOP”。 默认情况下 res/values/strings.xml 中的字符串会执行拼写检查,如果不是英语,会提示拼写错误,通过 tools:locale=”it” 来告诉studio本地语言不是英语,就不会有提示了。 PS: 关于忽略Lint 的属性,了解就好,一般不常用,也不影响编译。 参考文档]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>xml</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android知识点日常记录(五)]]></title>
<url>%2F2019%2F11%2F06%2FAndroid%E7%9F%A5%E8%AF%86%E7%82%B9%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95-%E4%BA%94%2F</url>
<content type="text"><![CDATA[日常复用代码踩坑记录。 RecyclerView: No layout manager attached; skipping layout因为需求变更,需要优化代码,然后自己偷懒,复用了几个界面,一个不留神,就给自己埋了一个坑,还搞的自己心情都不好了(🤦♂️)具体的错误如标题。一个很低级的错误 RecycleView忘记设置LayoutManager,自己的写代码习惯是在布局里面设置,同事是在代码里面设置。调试过程中,数据一直不展示,抓布局定位高度是否正确,adapter设置是否正确,与RecycleView是否绑定等,都没有怀疑到自己没设置LayoutManager,看了下log,报了如题的错误。 解决方案:1234LinearLayoutManager classifyDataManager = new LinearLayoutManager(this);//配置布局,默认为vertical(垂直布局)classifyDataManager.setOrientation(LinearLayoutManager.VERTICAL);recyclerTaskType.setLayoutManager(classifyDataManager); PS:记录下排查问题思路1234抓布局,查看RecycleView的高度是否正确RecycleView是否正确绑定AdapterAdapter设置是否正确(onBindViewHolder)RecycleView是否正确设置了LayoutManager Intent隐式跳转原生分享主要用的知识点就是Intent隐式跳转。显示跳转,一般我们都很熟悉,项目中最长用到的。下面的示例很熟悉: 12Intent intent=new Intent(MainActivity.this, SecondActivity.class); startActivity(intent); 隐式跳转在项目中一般使用较少,也因项目而异。跳转外部应用,常用的是隐式跳转。代码如下:一目了然,隐式跳转五步走。12345Intent shareIntent = new Intent();shareIntent.setAction(Intent.ACTION_SEND);shareIntent.putExtra(Intent.EXTRA_TEXT, " Hello World");shareIntent.setType("text/plain");startActivity(Intent.createChooser(shareIntent, "share into")); com.android.builder.internal.aapt.v2.Aapt2Exception: Android resource linking failed项目换到AndroidX,自己更新代码后,项目无法运行,Google了好多方法,但是都无法解决,是Gradle版本不一致,自己帮助同事用Git解决冲突的时候,略显粗暴,直接让本地的一些代码被还原,导致Gradle文件被还原,项目运行不了。解决冲突还是需要耐心仔细。 Parcelable encountered IOException writing serializable object界面传值的时候,报如题错误,JavaBean有嵌套,内部嵌套的Bean未序列化导致。如果需要序列化JavaBean,将所有的Bean都序列化,避免此问题。]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[写在27岁]]></title>
<url>%2F2019%2F11%2F02%2F%E5%86%99%E5%9C%A827%E5%B2%81%2F</url>
<content type="text"><![CDATA[不知不觉,一年又要快结束了,因为自己的生日是阴历的十月份,所以每当自己过生日的时候,一年的时间也就只剩下尾巴了。去年的一切感觉还历历在目,转眼19年就要结束了。时间真的真的流失的太快了。 今年的心态比去年好了很多,变的平和了许多,很多事情自己着急也没用,做好自己当下的事情,不虚度光阴就是最好的。很多道理自己年轻的时候不懂,懂的时候,已经不是当初的那个年纪,懊恼后悔于事无补,尽自己最大的力量,做好自己想做的事情。 星期四公司十月份的生日,刚好在我阴历生日的前一天,跟大家一起过生日,挺热闹,吃了蛋糕。 今天早上去公司开会,下午打疫苗,国内疫苗年龄卡的很严格,只能按照规定来,除非去国外,比较麻烦,费用也比较高,还是放弃了。 年初定的计划好像也没有完成,又要遗留到下一年了。。。 其实之前迷茫的原因,还是目标不明确,因为不知道往哪里走,所以迷茫,走到现在,也变不了道了,踏踏实实工作,开开心心生活,就知足了。 该想想20年要立什么flag了,之前18年买的书,也要放到20年了,其他的流水账就放到年终总结来写吧。]]></content>
<categories>
<category>日常</category>
</categories>
<tags>
<tag>碎碎念</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android知识点日常记录(四)]]></title>
<url>%2F2019%2F09%2F10%2FAndroid%E7%9F%A5%E8%AF%86%E7%82%B9%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95-%E5%9B%9B%2F</url>
<content type="text"><![CDATA[显示不重复Notification消息通知的重点就是下面的这个方法,根据源码解释可知,我们想要通知不重复显示,就变更Id就可以。 1234567891011121314/** * Post a notification to be shown in the status bar. If a notification with * the same id has already been posted by your application and has not yet been canceled, it * will be replaced by the updated information. * * @param id An identifier for this notification unique within your * application. * @param notification A {@link Notification} object describing what to show the user. Must not * be null. */ public void notify(int id, Notification notification) { notify(null, id, notification); } 解决方案:将时间戳作为Id,传入方法中。123int notifyId = (int) System.currentTimeMillis(); // 发出通知notificationManager.notify(notifyId, builder.build()); 神奇的supersuper.onBackPressed()项目中需要在Back键返回的时候,传值给上一个界面,重写了onBackPressed()方法,正常传值。代码运行与想象不一致,然后就在想是什么问题,试着把super.onBackPressed();父类调用放在最后,编译运行代码,符合预期。 直接调用父类的super.onBackPressed();不会走子类的传值,页面已经finish()掉,所以需要此类场景的传值,需要将父类调用放在最后。 1234567@Override public void onBackPressed() { Intent intent = new Intent(); intent.putExtra("picture", selImageList); setResult(RESULT_OK, intent); super.onBackPressed(); } super.onBindViewHolder(viewHolder, position)RecyclerView的Adapter没有每个item点击事件,需要自己去写接口监听,写了一个BaseAdapter,点击事件监听Ok,处理加载更多,不小心删掉了super.onBindViewHolder(viewHolder, position),点击事件失效。添加父类调用,点击事件Ok。 经过这两个日常问题的处理,更加深刻的理解了super的重要性。 Parcel: unable to marshal value在两个Activity直接传递List<XXInfo>时,出现Parcel: unable to marshal value异常。必须强制类型转换为ArrayList<XXInfo>。 在OneActivity页面(OneActivity页面向NextActivity页面传递一个List<XXInfo>):123Intent intent = new Intent(this, NextActivity.class);intent.putExtra("list", list);startActivity(intent); 解决方案:XXInfo要implements Serializable或者继承Parcelable,list必须是ArrayList(若是List会提示错误)。 12MainActivity中,intent.putExtra("list", Arraylist实例)。NextActivity中,List<xxInfo> infoList = (ArrayList) getIntent().getSerializableExtra("list")]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[EventBus学习]]></title>
<url>%2F2019%2F09%2F04%2FEventBus%E5%AD%A6%E4%B9%A0%2F</url>
<content type="text"><![CDATA[EventBus 使用很早之前就听过 EventBus 这个神器了,因为参与了新项目,维护同事的代码,全部用的是 EventBus,有必要学习一下。Android 原生的广播,实际项目中使用的确实是比较少,除非是一些 ROM 开发。我们是实用主义者,所以就先记录如何使用,然后等会用后再去研究原理。 确保EventBus 已添加到项目依赖。 1. 定义EventEvent 没有特殊要求,就是普通的 Java 对象。例如下面的代码,如果不需要传值,可以只写一个空类。123456public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; }} 2. Subscriber订阅者Subscriber 实现 Event 处理,实现的方法在事件被发布的时调用。Subscriber 方法使用 @subscribe 注解定义。 1234567891011// This method will be called when a MessageEvent is posted (in the UI thread for Toast)@Subscribe(threadMode = ThreadMode.MAIN)public void onMessageEvent(MessageEvent event) { Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();} // This method will be called when a SomeOtherEvent is posted@Subscribepublic void handleSomethingElse(SomeOtherEvent event) { doSomethingWith(event);} PS: 对于 EventBus 3,方法名可以自由选择(没有 EventBus 2 中的命名约定) 2.1 注册EventBusSubscriber 只有在注册后才可以接收到事件。对于 Android ,在 Activity 和 Fragment 中通常应该根据生命周期注册。对于大多数情况,分别在 onStart 和 onStop 注册和反注册就可以,如下代码,也可以根据情况,在 onCreate,或者 onDestroy 中注册和反注册。1234567891011@Overridepublic void onStart() { super.onStart(); EventBus.getDefault().register(this);} @Overridepublic void onStop() { EventBus.getDefault().unregister(this); super.onStop();} 3. 发布Event代码中的任意部分都可以发布事件。所有已注册并且匹配该类型的 Subscriber(订阅者)都会收到该事件.1EventBus.getDefault().post(new MessageEvent("Hello everyone!")); ThreadModeEventBus不仅可以处理传递信息,还可以处理线程切换问题。事件可以发布到与发布线程不同的线程中。 对于 Android,UI 改变必须发生在 UI(main)线程中。另一方面,网络请求或其他任何耗时的任务不得在主线程上运行。EventBus 可以处理这些问题,并与 UI 线程保持协调。 主要有以下四种线程模式12345ThreadMode:POSTING(默认)ThreadMode:MAINThreadMode:MAIN_ORDEREDThreadMode:BACKGROUNDThreadMode:ASYNC 查看了官方的英文文档,MAIN 与 MAIN_ORDERED 模式,Subscriber 都是运行在主线程的,区别是 MAIN_ORDERED 保证了事件处理有一个更严格一致的顺序。 比如,在 MAIN 模式下,处理事件的时候发布另一个事件,则第二个事件将先于第一个事件被处理完成(此处为同步调用,可与方法调用类比)。而对于 MAIN_ORDERED,第一个事件将先被完成处理,然后第二个事件在稍后的时间点(一旦主线程有处理能力时)被处理。 BACKGROUND 事件回调将在后台线程中被调用。如果发布事件的线程不是主线程,事件回调将直接在发布线程被调用。否则,EventBus 使用一个后台线程(单例)来按序调用每个回调 ASYNC 事件回调方法总是在单独的线程被调用。这些线程不会是发布事件的线程,也不会是主线程。 官方文档参考文档]]></content>
<categories>
<category>EventBus</category>
</categories>
<tags>
<tag>工具</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android知识点日常记录(三)]]></title>
<url>%2F2019%2F09%2F02%2FAndroid%E7%9F%A5%E8%AF%86%E7%82%B9%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95-%E4%B8%89%2F</url>
<content type="text"><![CDATA[ScrollView嵌套RecyclerView数据显示不全解决方案查看代码,布局中没有给RecycleView设置layoutManager,发现是代码中动态设置的。12345678LinearLayoutManager classifyDataManager = new LinearLayoutManager(this) { @Override public boolean canScrollVertically() { return false; } }; //配置布局,默认为vertical(垂直布局) classifyDataManager.setOrientation(LinearLayoutManager.VERTICAL); 字面意思理解,canScrollVertically()方法return false,可能是数据显示不全的原因,试着改为return true,测试了下,数据显示正常了,RecycleView的数据必须通过滑动来查看,跟ScrollView滑动响应不一致,导致用户体验不好。 优化方案查找资料,发现了一个NestedScrollView可以替换ScrollView,NestedScrollView的名字中其实就可以看出他的作用了,Nested是嵌套的意思。12最终解决方案ScrollView换为<android.support.v4.widget.NestedScrollView>问题解决了 系统通知,点击消息未消失项目中推送消息,使用MQTT协议来实现,拿到消息后,显示一个Notification,点击后,Notification未消失。增加如下两个属性。setContentIntent()与setAutoCancel()。1234Notification.Builder builder = new Notification.Builder(this);builder.setContentIntent(contentIntent).setAutoCancel(true); OkHttp上传图片服务器无法获取的问题测试在现场提出一个问题,发布任务带图片,就发送失败,客户端网络请求走到了onFailure(),但是用PostMan测试,又能正常上传,Google发现,在OkHttp请求的时候,setType()设置的MultipartBody.FORM,未指定编码,导致服务器无法解析此请求,导致请求失败。12345错误请求设置:MultipartBody.Builder builder=new MultipartBody.Builder() .setType(MultipartBody.FORM);正确请求设置: MultipartBody.Builder builder = new MultipartBody.Builder().setType(MediaType.parse("multipart/form-data;charset=utf-8")); 相见恨晚的CountDownTimer一般项目中注册发送验证码都会有一个倒计时的功能,以前的实现方式就是使用Handler+Thread方式,既然有了CountDownTimer,就不用那么复杂了,直接使用如下:12345678910new CountDownTimer(30000, 1000) { public void onTick(long millisUntilFinished) { mTextField.setText(millisUntilFinished / 1000) + "秒后可重发"); } public void onFinish() { mTextField.setText("done!"); } }.start(); CountDownTimer每隔1秒调用一次onTick(long millisUntilFinished)方法, 倒计时结束时调用onFinish()方法. CountDownTimer是运行在主线程,可以直接更新UI]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[WebView使用踩坑记录]]></title>
<url>%2F2019%2F08%2F26%2FWebView%E4%BD%BF%E7%94%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95%2F</url>
<content type="text"><![CDATA[大前端是趋势,最近有两个项目涉及到原生跟H5嵌套以及交互,那WebView必不可少,以为会很顺利,结果这中间还是踩了不少坑。 H5调用相机无反应H5集成进来之后,测试发现,点击调起相机,无反应,然后IOS是正常的,我….好吧,Android就是这么独特。 Google了一番,发现,高版本的Android系统,WebView出于安全性考虑,限制H5访问本地文件。需要重写 WebviewChromeClient中的 openFileChooser()和onShowFileChooser()方法响应H5的<input type="file">,使用原生代码来调用本地相机和相册,然后在onActiivtyResult把选择的图片 URI 回传给 WebviewChromeClient。 1PS:注意Fragment与Activity的onStartActivityForResult区别,开了混淆的话,不要混淆onShowFileChooser()方法。 具体使用方式,网络有很多,这里有不详细介绍了,只记录下解题思路。参考博客 百度地图定位偏差项目中因为客户要求定位必须使用百度地图,所以,就出现了定位偏差的问题,IOS继续正常,Android定位偏差,继续填坑。H5通过IP定位,精度不好,有好几种解决方案。1234H5先用高德地图定位,然后显示在百度地图上降低targetSdkVersion版本到23升级Http到Https使用原生定位方法,将位置信息传给H5 方案1 任务量是H5的,无能为力方案2 试了一下,没效果方案3 Https升级要Money,So,忽略方案4 使用WebView的JavascriptInterface开接口给JS。 缓存问题同事写了一个加载WebView的模板,就无脑用了,如果出现网络异常,页面空白,网络正常后,还是空白页面,然后清除掉缓存就好了。额。。。然后就发现了如下这个配置:12345678如下设置项://关闭webView中的缓存webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);LOAD_CACHE_ELSE_NETWORK:只要本地有缓存,就从缓存中读取数据。LOAD_DEFAULT:根据 Http 协议,决定是否从网络获取数据。LOAD_NO_CACHE:不使用缓存,只从网络获取数据。LOAD_CACHE_ONLY:不使用网络,只读本地缓存。 显示过小,缩放WebView加载H5,显示很小,必须手势放大才可以,隐藏掉如下配置:自动适配屏幕大小12345678910111213 //设置自适应屏幕,两者合用// webSettings.setUseWideViewPort(true);//将图片调整到合适webview的大小// webSettings.setLoadWithOverviewMode(true);//缩放至屏幕的大小// webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); //支持缩放,默认为true,是下面的前提// webSettings.setSupportZoom(true); //设置内置的缩放控件,若上面是false,则该webview不可缩放,这个不管设置什么都不能缩放// webSettings.setBuiltInZoomControls(true);// webSettings.setDefaultZoom(WebSettings.ZoomDensity.FAR); //隐藏原生的缩放控件// webSettings.setDisplayZoomControls(false); H5页面跳转,隐藏底部toolBar底部toolBar的某一个操作项集成了H5,进入H5之后,底部的toolBar仍然存在,需要隐藏掉toolBar,重写WebViewClient的shouldOverrideUrlLoading()方法,URL给出标志,判断URL是否包含隐藏toolBar标志,如果包含,toolBar隐藏掉不显示。]]></content>
<categories>
<category>WebView</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android知识点日常记录(二)]]></title>
<url>%2F2019%2F06%2F16%2FAndroid%E7%9F%A5%E8%AF%86%E7%82%B9%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95-%E4%BA%8C%2F</url>
<content type="text"><![CDATA[好记性不如烂笔头,知识点又来了。最近工作相当充实,体验了一把互联网公司的 996,累到只想睡觉。晚上抽空把知识点整理一下。 TextView Hint使用坑点一般APP会设计提示语,有输入内容的时候提示语消失,没有输入内容的话,就显示提示语,一般会使用控件的Hint属性,分分钟解决设计。但是最近我在项目中,使用这个Hint发现了一个问题,输入内容少于Hint内容,界面会显示异常,界面显示包含了Hint的长度。如果输入内容大于Hint内容,显示不会出现异常。很神奇的现象。 解决方案一种很简单粗暴的解决方案:设置文本内容显示在控件的右边。因为默认文本显示是居左,修改文本显示后,宽度以Hint宽度为基准,导致显示异常,出现空白。1android:gravity="right" 网络请求 Token之前一直没有机会去调试接口,最近却被调接口虐到,有一个接口,Postman访问,接口请求正常,返回数据正常,但是自己就是拿不到数据。因为是维护别人的代码,就没仔细看,大致看了下,感觉没错。后台怀疑没传token,可是代码里面传了token,最后才发现,token传错了位置,传到了body里面。这低级错误,简直…… 修改网络请求,header中传入token,接口访问正常。 Fresco 框架 wrap_contentAndroid图片加载库很多,最近使用Facebook的一款图片加载库,很简单,使用之后,发现图片显示不了。查看官方文档,不支持Wrap_content,What ?文档链接如下: 为什么不支持wrap_content 解决方案原因官方已经解释的很清楚了,我们可以参照StackOverflow上的解决方案,也可以设置宽高比来解决图片不显示的问题。宽高比方案代码如下:1234<com.facebook.drawee.view.SimpleDraweeView android:layout_width="wrap_content" fresco:viewAspectRatio="1" android:layout_height="100dp" /> PS:宽高比方案,必须固定一边高度,另一边设置wrap_content与fresco:viewAspectRatio属性。]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[.gitignore 通用配置]]></title>
<url>%2F2019%2F06%2F08%2Fgitignore%E9%80%9A%E7%94%A8%E9%85%8D%E7%BD%AE%2F</url>
<content type="text"><![CDATA[Git是非常流行的版本控制工具,相信程序员这个群体没有不知道Git的,熟练掌握并使用非常有必要。在工作中,多人协作,经常会出现项目冲突,导致自己本地项目跑不起来,主要是一些个人配置被提交到了代码库,导致此问题。,每次git status都会显示Untracked files ...,逼死强迫症。如何解决呢?好在Git替我们想到了,在项目根目录下面,创建一个.gitignore文件,填入需要忽略的文件路径,Git就会自动忽略这些文件,相当方便。我们不需要从头编写.gitignore文件,Github上有一个gitignore开源项目,为我们准备了各种项目所需的.gitignore文件,我们只需要组合使用即可。项目地址 .gitignore 忽略原则拿Android项目举例来说: 忽略操作系统自动生成的文件,比如:.DS_Store文件 忽略项目自动生成的文件,比如:.idea文件 忽略项目编译生成的文件,比如:build文件 忽略本地带有敏感信息的配置文件,比如:存放口令与密码的配置文件 Android .gitignore文件这是 gitignore 项目中,给出的 Android 项目 .gitignore 配置文件。可做参考。12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182# Built application files*.apk*.ap_*.aab# Files for the ART/Dalvik VM*.dex# Java class files*.class# Generated filesbin/gen/out/release/# Gradle files.gradle/build/# Local configuration file (sdk path, etc)local.properties# Proguard folder generated by Eclipseproguard/# Log Files*.log# Android Studio Navigation editor temp files.navigation/# Android Studio captures foldercaptures/# IntelliJ*.iml.idea/workspace.xml.idea/tasks.xml.idea/gradle.xml.idea/assetWizardSettings.xml.idea/dictionaries.idea/libraries# Android Studio 3 in .gitignore file..idea/caches.idea/modules.xml# Comment next line if keeping position of elements in Navigation Editor is relevant for you.idea/navEditor.xml# Keystore files# Uncomment the following lines if you do not want to check your keystore files in.#*.jks#*.keystore# External native build folder generated in Android Studio 2.2 and later.externalNativeBuild# Google Services (e.g. APIs or Firebase)# google-services.json# Freelinefreeline.pyfreeline/freeline_project_description.json# fastlanefastlane/report.xmlfastlane/Preview.htmlfastlane/screenshotsfastlane/test_outputfastlane/readme.md# Version controlvcs.xml# lintlint/intermediates/lint/generated/lint/outputs/lint/tmp/# lint/reports/ .gitignore 常用匹配语法常见的忽略匹配语法:1234567891011"#" 开头的文件表示注释,会被git忽略"/" 表示文件目录 "/"结束的模式只匹配文件夹以及在该文件夹路径下的内容,但是不匹配该文件; "/"开始的模式匹配项目跟目录"*" 通配多个字符"**" 匹配任意中间目录"!" 表示否定,不忽略此文件 举例说明: 12345678910111213*.apk 表示忽略所有 .apk 结尾的文件!lib.b 忽略文件,但是lib.b除外build/ 忽略整个build文件夹/build 忽略整个项目下build文件与build文件夹*/foo: 表示忽略/foo,a/foo,a/b/foo等a/**/b: 表示忽略a/b, a/x/b,a/x/y/b等doc/*.txt 表示会忽略doc/notes.txt但不包括 doc/server/arch.txt 已被忽略的如何加入Git可以使用如下命令123git add -f "file name" 强制添加到gitgit rm --cached "file" 被忽略的文件误添加,可以使用rm命令将其从中移除 或者怀疑可能是.gitignore文件写的不对,需要查看是哪里写错了,可以使用git check-ignore。我们可以知道是哪个规则导致忽略了文件,从而修改规则。 1git check-ignore -v "file name" 总结:.gitignore要首先添加到版本控制中,如果在创建.gitignore之前已经push了项目,即使你在.gitignore文件中写入新的过滤规则,这些规则也不会起作用,Git仍然会对所有文件进行版本管理。 如果你已经把不想上传的文件上传到了Git仓库,那么你必须先从远程仓库删了它,我们可以从远程仓库直接删除然后pull代码到本地仓库这些文件就会本删除,或者从本地删除这些文件并且在.gitignore文件中添加这些你想忽略的文件,然后再push到远程仓库。 为了避免这种麻烦的操作,必须养成项目开始就创建编写.gitignore文件,好习惯,事半功倍。]]></content>
<categories>
<category>Git</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android 知识点 日常记录(一)]]></title>
<url>%2F2019%2F06%2F07%2FAndroid%E7%9F%A5%E8%AF%86%E7%82%B9%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95(%E4%B8%80)%2F</url>
<content type="text"><![CDATA[常识性的知识,自己是知道的,但是又不确定是否准确,经常会出现这种状况。So,为了避免这种尴尬的情况出现,工作中一些小的知识点,整理记录下来。 View控件INVISIBLE,GONE的区别查看项目代码,很多布局是复用一个xml文件,导致有大量的逻辑去处理控件是否显示,VISIBLE不用多说,正常显示控件,一般不可见控件,我会选择GONE属性,但是还存在一种INVISIBLE属性,也是不可见,区别是什么呢? 源码探究查看ViewGroup源码,如下方法,12345678910protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) { final int size = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < size; ++i) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } } 123456789101112131415161718192021222324@Overrideprotected void dispatchDraw(Canvas canvas) { ...for (int i = 0; i < childrenCount; i++) { while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) { final View transientChild = mTransientViews.get(transientIndex); if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) { more |= drawChild(canvas, transientChild, drawingTime); } transientIndex++; if (transientIndex >= transientCount) { transientIndex = -1; } } final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { more |= drawChild(canvas, child, drawingTime); } } ...} 由上面两个源码方法可知,控件设置GONE属性,没有走measureChild(child, widthMeasureSpec, heightMeasureSpec);方法。 查看dispatchDraw(Canvas canvas);方法,可知,只有设置VISIBLE属性,才会执行drawChild(canvas, child, drawingTime); INVISIBLE与GONE均不执行此方法。 由View绘制流程可知,GONE属性未执行onMeasure()方法,所以不会占用界面空间。INVISIBLE执行了onMeasure()方法,但是没有执行onDraw()方法,所以会占用界面空间,但是不显示。 结论123INVISIBLE:不可见,保留了控件在界面的空间,相当于仍然占着坑GONE:不可见,不保留控件在界面的空间,未占坑 ScrollView只能有一个子节点ScrollView经常被使用在布局中以实现滑动效果,可以显示比实际界面的多的内容。在使用过程中,没注意,项目运行后,出现了ScrollView can host only one direct child异常: 查看官方文档,描述如下12345678public class ScrollView extends FrameLayout java.lang.Object ↳ android.view.View ↳ android.view.ViewGroup ↳ android.widget.FrameLayout ↳ android.widget.ScrollView A view group that allows the view hierarchy placed within it to be scrolled. Scroll view may have only one direct child placed within it. To add multiple views within the scroll view, make the direct child you add a view group, for example LinearLayout, and place additional views within that LinearLayout. 解决方案如官方文档描述,子控件外部嵌套一层LinearLayout,因为ScrollView是继承FrameLayout,FrameLayout的特点是所有控件均重叠防止在左上角,如果有多个子控件在ScrollView,无法实现滑动效果。 代码动态addView动态加载View,根据后台返回的数量来显示,for循环遍历,赋值,出现下图错误。The specified child already has a parent,You must call removeView() on the child's parent first.修改方案在错误中有提示。要防止一个View被add多次。 Resources not find123android.content.res.Resources$NotFoundException: String resource ID #0x1 at android.content.res.Resources.getText(Resources.java:339) at android.widget.TextView.setText(TextView.java:5496) View的setText()方法传int值被当成了ResourceID,导致此错误。 解决方案可以拼接一个空子串,或者String.valueOf();12textView.setText(getNum + "");textView.setText(String.valueOf(getNum)); 总结很不起眼的小细节,出现错误,会浪费大量的时间,精力去分析,定位。做好记录,加深记忆。争取下次犯高级错误。]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hexo 搭建 Blog 踩坑记录]]></title>
<url>%2F2019%2F06%2F02%2FHexo-%E6%90%AD%E5%BB%BABlog-%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95%2F</url>
<content type="text"><![CDATA[字数显示undefined如下图: 安装好插件hexo-symbols-count-time后,查看界面,字数显示undefined,可能是因为第一次安装导致,执行如下命令:1hexo clean 然后再次查看,显示正常。 访客量显示在NexT主题的配置文件中,修改busuanzi_count配置项,将enable改为true。 这样显示的样式是鼠标点击图标时,才显示标题,可以修改NexT主题下layout/_third_party/analytics/busuanzi-counter.swig文件,如下:12345<span class="site-pv" title="{{ __('footer.total_views') }}"> {{ __('footer.total_views') }} <span class="busuanzi-value" id="busuanzi_value_site_pv"> </span></span> 对比源文件,增加了1{{ __('footer.total_views') }} 配置项。 常用命令记录123456789hexo init 初始化项目hexo s 运行项目hexo g -d 发布项目hexo new page "tags" 新增Itemhexo new “file name” 新建文章 大括号陷阱如下新增配置项,我在 Markdown 格式下,使用 ` 标签,导致配置项被当成JS代码运行,导致错误。 1{{ __('footer.total_views') }} 建议涉及到代码部分,均使用 Markdown 代码块来表示,防止出现上述描述错误。 报错 YAMLException1YAMLException: can not read a block mapping entry; a multiline key may not be an implicit key at line 5, column 1: 查看代码,标签后面少了一个空格,导致报此错误。1234也就是说每一个 标签:后需要一个空格。Example :categories: [技术]tags:[hexo] #这里缺少一个空格,添加空格,不会报错]]></content>
<categories>
<category>Hexo</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[GitLab + Docker 私有化部署]]></title>
<url>%2F2019%2F05%2F30%2FGitlab-Docker-%E7%A7%81%E6%9C%89%E5%8C%96%E9%83%A8%E7%BD%B2%2F</url>
<content type="text"><![CDATA[为什么使用Gitlab遇到了一个很重视信息安全的Boss,代码都放在本地用SVN管理,对于没有怎么用过SVN的我来说,简直无从下手。为了方便,高效的管理项目,并跟踪项目中的问题,了解到了Gitlab这个神奇的存在,相比Github的私有仓库收费,且可能存在信息安全方面的风险,Gitlab支持私有化部署,而且免费,社区版本基本满足git项目管理需求,权限管理,项目分支版本管理,以及CI/CD功能等,相当小而精。下面介绍如果部署私有化Gitlab。 安装DockerGitlab有两种安装方式。 第一种是自己下载Gitlab安装包,自己配置相关运行环境,相当麻烦,更换机器,就得重新配置,让我想起了当年在服务器上部署MySql,Tomcat,Nginx,Kafka等组件的恐惧,多的时候有七八个组件,部署环境搞大半天,还要分布式部署,那个头大。 第二种方式是用现在非常流行的Docker来部署,Docker是一个虚拟化运行工具,将软件和整个环境打包起来,我们可以不需要任何配置,快速的部署环境来运行软件,提升效率。 下载安装Docker,执行如下命令:1brew cask install docker 配置镜像加速器鉴于国内网络原因,拉取Docker镜像十分缓慢,非常有必要配置一个加速器来解决速度问题。 在任务栏点击 Docker for mac 应用图标-> Perferences... -> Daemon -> Registry mirrors在列表中填写加速器地址即可。修改完成之后,点击Apply & Restart按钮,Docker 就会重启并应用配置的镜像地址了。地址如下:1http://f1361db2.m.daocloud.io 编写docker-compose.yml配置文件新建docker-compose.yml文件,写入如下内容。端口可以使用默认端口,也可以自己配置端口。 image 代表着最新的gitlab版本镜像 hostname代表域名,本地可以直接使用localhost或者局域网ip Volumes 本机映射文件路径可自己配置 12345678910111213141516web: image: 'gitlab/gitlab-ce:latest' restart: always hostname: 'gitlab.example.com' environment: GITLAB_OMNIBUS_CONFIG: | external_url 'https://gitlab.example.com' # Add any other gitlab.rb configuration here, each on its own line ports: - '80:80' - '443:443' - '22:22' volumes: - '/srv/gitlab/config:/etc/gitlab' - '/srv/gitlab/logs:/var/log/gitlab' - '/srv/gitlab/data:/var/opt/gitlab' 在当前目录下执行如下命令:1docker-compose up -d 等待片刻,浏览器网址输入打开localhost,就可以看到一个部署成功,运行起来的Gitlab,如下图: 因为我docker-compose.yml文件中images配置了汉化镜像:1image: 'twang2218/gitlab-ce-zh:11.1.4' 分分钟,一个本地私有化的Gitlab就部署好了。]]></content>
<categories>
<category>GitLab</category>
</categories>
<tags>
<tag>技术</tag>
</tags>
</entry>
<entry>
<title><![CDATA[第一篇 Blog]]></title>
<url>%2F2019%2F05%2F28%2F%E7%AC%AC%E4%B8%80%E7%AF%87Blog%2F</url>
<content type="text"><![CDATA[一直想着搭建自己的博客,拥有自己的一个小天地。最近终于行动了,博客搭建过程中,并没有想象中的那么难,畏难心态在以后的人生路中需要全力克服。 毕业这几年,感觉都不是很顺,但是也收获成长了许多,接下来就是对自己狠一点,逼自己尽快成长。下周就是新的开始了,希望自己能抗下压力,挑战成功,逆风翻盘。 自己焦虑的点是什么,就去做它,一直做到自己不焦虑为止。加油。]]></content>
<categories>
<category>日常</category>
</categories>
<tags>
<tag>碎碎念</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hello World]]></title>
<url>%2F2019%2F05%2F28%2Fhello-world%2F</url>
<content type="text"><![CDATA[Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new "My New Post" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment]]></content>
</entry>
</search>