Android小知识点记录
对viewpager页面进行更新,如果想更换fragment对象
在重新赋值对象前使用viewPager.removeAllViewsInLayout();
通过文件名拿取drawable文件夹下的资源文件id(一般用来组合文件名拿取资源)
第一个参数文件名
mContext.getResources().getIdentifier("science_" + i
, "drawable"
, mContext.getApplicationInfo().packageName)
drawable资源文件最新获取方法
//使用contextCompat拿取drawble或color。context.getDrawable已被舍弃
val drawable = ContextCompat.getDrawable(requireContext(), R.drawable.shape_small_radiu_et_bg)
//setBounds一定要有,否则drawable不显示
drawable!!.setBounds(0, 0, drawable.minimumWidth, drawable.minimumHeight)
ly_input_invite_code.background = drawable
Calender.getActualMaximum(calendar.DAY_OF_MONTH)的陷阱
在使用calendar.getActualMaximum(calendar.DAY_OF_MONTH)获取每月最后一天时,发现在2月出现了问题,获取到的时间是20170303,而其他月份获取的最后一天都是正确的。
而且之前获取2月最后一天是28号,也每月问题。代码也没动过。后来才发现昨天是28号取的2月最后一天,29-31号取2月最后一天都会有问题。
原因是Calendar类在set的时候,并不会立即生效,只有在get的时候才会生效
解决方法是在实例化Calendar类之后,要先调用clear()方法清空缓存。
Calendar calendar=Calendar.getInstance();
calendar.clear();
EditText回车监听
android:imeOptions属性
链接:https://blog.csdn.net/a253664942/article/details/45585795
查看apk中权限
使用aapt工具
命令:aapt dump badging xxx.apk
aapt工具地址可执行文件aapt.exe一般默认路径C:\Users\你的用户名\AppData\Local\Android\android-sdk\platform-tools 。shift+右键打开控制台
示例
//xxx.apk是安装包路径
aapt dump badging xxx.apk
//或
.\aapt dump badging xxx.apk
日期格式转换格式化字符的含义![日期格式转换格式化字符的含义](https://i-blog.csdnimg.cn/blog_migrate/3cc1d8d0f4aaa262d96432ee30608c5c.jpeg#pic_center)
创建签名
Toast问题
AndroidUtilCode第三方工具包中的ToastUtils未了解原理,调用showShort展示吐司时需要获取通知权限才能成功弹出吐司(测试机型IQOO Z1 Android11,华为某机型 Android8),替换为原生Toast.makeText().show()不需要获取通知权限
代码控制ConstraintLayout内部元素相对位置
子控件设置了相对位置后调用两个bias属性可以控制当前位置所占比例,下面是在xml中的代码样式
//水平方向
app:layout_constraintHorizontal_bias="0"
//垂直方向
app:layout_constraintVertical_bias="0"
我们怎么通过代码来实时控制当前控件的相对位置呢,比如需要百分比分割显示在一个进度条当中
例如
上图中的145以及那根线条都需要根据进度来不同的显示在下方图层的相对位置上面,这个时候我们可以这样实现
//vwSplit是该线条控件
var layoutParams = vwSplit?.layoutParams
if (layoutParams == null)
layoutParams = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT)
else
layoutParams as ConstraintLayout.LayoutParams
//这里是当前分数与总分的比例,bias值在0-1之间,如果0.5表示处在居中位置
layoutParams.horizontalBias = (nowScore - scoreMin) / (scoreMax - scoreMin).toFloat()
同理可以通过上图方式实现其他布局的属性设置
recycleView实现流式布局,自动换行
利用FlexbozLayoutManager实现
var layoutManager = FlexboxLayoutManager(this)
//flexDirection 属性决定主轴的方向(即项目的排列方向)。
//类似 LinearLayout 的 vertical 和 horizontal。
layoutManager.flexDirection = FlexDirection.ROW//主轴为水平方向,起点在左端。
//flexWrap 默认情况下 Flex 跟 LinearLayout 一样,都是不带换行排列的
//但是flexWrap属性可以支持换行排列。
layoutManager.flexWrap = FlexWrap.WRAP//按正常方向换行
//justifyContent 属性定义了项目在主轴上的对齐方式。
layoutManager.justifyContent = JustifyContent.FLEX_START//交叉轴的起点对齐。
recycleLable.layoutManager = layoutManager
禁用跟随系统设置字体大小
代码可直接使用,在Application中重写getResource方法。
@Override
public Resources getResources() {//禁止app字体大小跟随系统字体大小调节
Resources resources = super.getResources();
if (resources != null && resources.getConfiguration().fontScale != 1.0f) {
android.content.res.Configuration configuration = resources.getConfiguration();
configuration.fontScale = 1.0f;
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
}
return resources;
}
安卓8.0以上需要在activity中也重写这一方法,代码同上。可以在项目的BaseActivity中实现。
这里还有另一种方法来实现字体不跟随系统,那就是原代码中是字体大小单位sp全部更换为dp
Mob的ShareSdk分享url到微博时提示待分享损坏等
分享url到微信需要满足配套的图片可用,而sharesdk对图片的要求如下
所以当我们设置网络图片时需要使用setImageUrl而不是setImagePath。更换之后可以正常分享
Edittext在页面初始后自动获取焦点弹出软键盘的问题
解决办法1,在edittext的父布局中添加如下代码:
android:focusable="true"
android:focusableInTouchMode="true"
不清楚什么原因,我使用上面的方法还是会弹出软键盘,这里还有一个解决办法。在activity或其他地方输入下方代码
//禁止输入框自动获取焦点弹出软键盘
getWindows().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
mysql字段携带emoji字符串的配置
获取本地视频对应时长帧图
/**
* 获取本地视频第一帧
*/
fun getLocalVideoFirstImg(context: Context, uri: Uri): Bitmap? {
val media = MediaMetadataRetriever()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
media.setDataSource(context, uri);// videoPath 本地视频的路径,7.0以后使用这个方法
} else {
media.setDataSource(uri.path);// videoPath 本地视频的路径
}
media.setDataSource(context, uri);// videoPath 本地视频的路径
return media.getFrameAtTime(1, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)//第一个参数为获取的视频帧图,时间点
}
获取签名文件签名MD5
jre的bin目录下命令行输入:
keytool -list -v -keystore 签名文件路径
例如:
keytool -list -v -keystore D:\NewestCode\yingcaibao\XUHAO\qbcf\key\sign.jks
获取当前包签名的密钥散列(接入facebook的事件管理需要用到)
/**
* 生成当前密钥散列
*/
fun keyStoreHash(context: Context): String {
var hash = ""
try {
val info = context.packageManager.getPackageInfo(
context.packageName,
PackageManager.GET_SIGNATURES
)
for (sign in info.signatures) {
val md = MessageDigest.getInstance("SHA-1")
md.update(sign.toByteArray())
hash = Base64.encodeToString(md.digest(), Base64.DEFAULT)
}
} catch (e: Exception) {
e.printStackTrace()
}
return hash
}
获取当前网络下的连接设备情况,如ip、mac、设备名等
要实现这个功能需要分情况判断
在高版本android设备(>=Android11)上面需要通过集成第三方服务sdk来获取,如Fing sdk,接入方法查询官网文档。
在低版本的Android设备(<Android11)上面就可以通过读取ARP表的方式来获取当前网络下的设备信息
下面是ARP表读取代码
//获取本机所在的局域网地址
val hostIP = NetworkUtils.getIpAddressByWifi()
LogUtils.e("Scanner ", "本机ip:$hostIP")
val lastIndexOf = hostIP.lastIndexOf(".")
val substring = hostIP.substring(0, lastIndexOf + 1)
Thread {
val dp = DatagramPacket(ByteArray(0), 0, 0)
var socket: DatagramSocket
try {
socket = DatagramSocket()
var position = 1
while (position < 255) {
LogUtils.e("Scanner ", "run: udp-$substring$position")
dp.address = InetAddress.getByName(substring + position.toString())
socket.send(dp)
position++
if (position == 125) {
//分两段掉包,一次性发的话,达到236左右,会耗时3秒左右再往下发
socket.close()
socket = DatagramSocket()
}
}
socket.close()
readArp()
} catch (e: SocketException) {
e.printStackTrace()
showError("Something wrong, Please try again.")
scanComplete()
} catch (e: UnknownHostException) {
e.printStackTrace()
showError("Something wrong, Please try again.")
scanComplete()
} catch (e: IOException) {
e.printStackTrace()
showError("Something wrong, Please try again.")
scanComplete()
}
}.start()
/**
* 读取/proc/net/arp并且解析出来ip,mac,flag
* flag 为0x00说明目前不在局域网内,曾经在过.0x02代表在局域网内
* 读取占进度的20%,根据mac地址扫描品牌占最后的20%
*/
private fun readArp() {
Thread {
try {
val br: BufferedReader =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {//Android10-Android11的arp文件读取方式是不一样的。
val runtime = Runtime.getRuntime()
val proc = runtime.exec("ip neigh show")
proc.waitFor()
BufferedReader(InputStreamReader(proc.inputStream))
} else {//Android 10之前的获取方式
BufferedReader(FileReader("/proc/net/arp"))
}
var tmpLine: String? = ""
var line = ""
var ip = ""
//flag 为0x00说明目前不在局域网内,曾经在过.0x02代表在局域网内
var flag = ""
var mac = ""
var deviceType = ""
if (br.readLine() == null) {
LogUtils.e("scanner", "readArp: null")
}
deviceList.clear()
while (br.readLine().also { tmpLine = it } != null) {
tmpLine?.let {
line = it
}
line = line.trim { it <= ' ' }
if (line.length < 63) continue
if (line.toUpperCase(Locale.US).contains("IP")) continue
ip = line.substring(0, 17).trim { it <= ' ' }
flag = line.substring(29, 32).trim { it <= ' ' }
mac = line.substring(41, 63).trim { it <= ' ' }
// deviceType = getType(ip)
if (mac.contains("00:00:00:00:00:00")) continue
LogUtils.e(
"scanner",
"readArp: mac= $mac ; ip= $ip ;flag= $flag ;deviceType:$deviceType"
)
val deviceInfo = DeviceInfo()
deviceInfo.state = "up"
deviceInfo.mac_address = mac
deviceInfo.ip_addresses = mutableListOf(ip)
deviceInfo.best_type = deviceType
if (ip == nowIpHost) {
deviceInfo.best_name = DeviceUtils.getModel()
}
deviceList.add(deviceInfo)
//deviceList就是获取到的全部设备信息
}
br.close()
} catch (ignored: Exception) {
ignored.printStackTrace()
showError("Something wrong, Please try again.")
scanComplete()
}
}.start()
}