琐碎知识点
CopyOnWriteArrayList¶
CopyOnWriteArrayList支持并发读写。
RemoteCallbackList¶
RemoteCallbackList支持跨进程删除listener,原理是ArrayMap<IBinder, Callback>
。IPC时Parcelable对象会序列化、反序列化,因此不会是同一个对象,但底层IBinder不会变。 它同时具有以下特点: 1. 客户端进程终止后,能够自动移除客户端注册的listener 2. RemoteCallbackList内部自动实现了线程同步功能,所以使用它来进行注册、取消注册时不需要做额外的线程同步工作。
android:windowSoftInputMode¶
EditText禁止进入时弹出键盘:
键盘弹出时禁止顶动View:常用Intent¶
跳转拨号盘
直接拨打电话 发送短信Collections.sort¶
Java Bean实体进行排序
Collections.sort(mRowsBeanList, new Number2zComparator());
private class Number2zComparator implements Comparator<T> {
@Override
public int compare(T o1, T o2) {
boolean o1IsHot = o1.getHotFlag() == 1;
boolean o2IsHot = o2.getHotFlag() == 1;
String o1Letter = PinyinUtils.ccs2Pinyin(o1.getPlatformName());
String o2Letter = PinyinUtils.ccs2Pinyin(o2.getPlatformName());
if (o1IsHot && o2IsHot) {
return o1Letter.compareToIgnoreCase(o2Letter);
} else if (o1IsHot) {
return -1;
} else if (o2IsHot) {
return 1;
}
return o1Letter.compareToIgnoreCase(o2Letter);
}
}
如果两者相等,返回0;
如果o1排在o2后面,返回1。
Gif加载¶
Gif加载
在尝试Glide加载(不卡,但是图片错乱了)、帧动画实现(超级耗内存,30帧,每帧8k原图,耗内存大约20M)、android-gif-drawable库(Android O上非常卡顿,耗内存大约10M)加载失败之后,找到了一种新奇的思路:每隔一段时间调用setBackgroundResource
,内存消耗基本不计。
代码设置drawable¶
setCompoundDrawablesWithIntrinsicBounds
response.body().string()只能调用一次¶
OkHttp访问网络成功的回调中,Response response
的response.body().string()
只能调用一次,否则
E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
Process: yorek.demoandtest, PID: 24671
java.lang.IllegalStateException: closed
因为这是一个流,使用过后就被关闭了:
public final String string() throws IOException {
BufferedSource source = source();
try {
Charset charset = Util.bomAwareCharset(source, charset());
return source.readString(charset);
} finally {
Util.closeQuietly(source);
}
}
Glide加载圆形图片¶
Glide.with(mContext)
.load(item.platformLogo)
.bitmapTransform(CropCircleTransformation(mContext))
.into(iv_logo)
其中,.bitmapTransform(CropCircleTransformation(mContext))
是其中的重点, CropCircleTransformation
使用了jp.wasabeef:glide-transformations:2.0.2
这个lib
Glide v4已经内置了圆形、圆角等常用的Trasform了。上面是Glide v3时的做法。
好人好信Tab3下拉冲突问题¶
SwipeRefreshLayout
与CollapsingToolbarLayout
和充满RecyclerView
的ViewPager
联用出现的滑动冲突问题
解决办法是自定义SwipeRefreshLayout
,在AppBarLayout
元素没有到顶时允许child向上滑,到顶后不允许滑动,这样就触发了下拉刷新。
public class CreditFragmentSwipeRefreshLayout extends SwipeRefreshLayout {
private AppBarLayout targetView;
public CreditFragmentSwipeRefreshLayout(Context context) {
super(context);
}
public CreditFragmentSwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
targetView = (AppBarLayout) findViewById(R.id.abl);
}
@Override
public boolean canChildScrollUp() {
if (targetView != null) {
return targetView.getTop() != 0;
} else {
return super.canChildScrollUp();
}
}
}
Android中字体的加载¶
在app/src/main/assets
下面放置字体文件,然后使用下面的代码加载
class KTypeface {
companion object {
val DIN_PRO_MIDIUM =
Typeface.createFromAsset(MyApp.getInstance().assets, "DINPro-Medium.otf")
val ROBOTO_MIDIUM =
Typeface.createFromAsset(MyApp.getInstance().assets, "Roboto-Medium.ttf")
}
}
这么使用:
Android中字体最好加载一次之后缓存起来,因为每次加载需要消耗时间。
判断应用通知权限是否打开¶
/**
* 只能检查KITKAT及以上的系统,以下会返回true
*/
public static boolean isNotificationEnabled(Context context) {
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
return notificationManagerCompat.areNotificationsEnabled();
}
ViewPager实现画廊效果¶
实现原理很简单
ViewPager
的父布局需要设置clipChildren = false
,同时最好设置背景色(pageMargin的部分需要背景色填充)ViewPager
也需要设置clipChildren = false
ViewPager
宽度为MATCH_PARENT
,但需要为其设置leftMargin
和rightMargin
,这样才有画廊的效果- 两张卡片之间的间距由
ViewPager
的pageMargin
控制
ViewPager
里面的子元素距离边框最好不要有padding
以及margin
,这样不利于控制效果
全面屏Splash以及广告页适配指北¶
SplashActivity
适配
- 新建
drawable-xxhdpi-2016x1080
文件夹,里面放入为全面屏准备的开屏页(一般是1080x2160) - 在
SplashActivity
的主题中加入<item name="android:windowBackground">@drawable/img_splash</item>
(所谓程序秒开主要指这个)
上述直接放图片的方式不太适用了,因为手机高宽比越来越大,这样总会被拉长的。如果图片底部是纯色的话,可以使用layer-list包裹一下图片,其他位置用纯色就好了。
广告页适配(我家广告页就是与SplashActivity
style一样的第二屏)
这个位置麻烦的地方就是需要显示从网络下载的图片,而且有多种尺寸,所以为了在全面屏上显示更好,我们需要加载一张1080x2160大小的图片然后显示。
所以,我们会先判断是不是全面屏,如果是就下载1080x2160大小的图片,否则一律下载1080x1920大小的图片。
// 下载图片的判断逻辑
String screenType = "1080x1920";
Point point = HRScreenUtils.Companion.getScreenSize(this);
if (HRScreenUtils.Companion.isFullScreen(point.x, point.y)) {
screenType = "1080x2160";
}
Call<FestivalImgRes> call = HttpHelper.getApiService().getFestivalHead("android", screenType);
// ------------------------------
// HRScreenUtils.kt
class HRScreenUtils {
companion object {
fun isFullScreen(width: Int, height: Int) : Boolean = (1.0f * height / width) >= 1.86f
fun getScreenSize(context: Context): Point {
val point = Point()
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
windowManager.defaultDisplay.getRealSize(point)
} else {
windowManager.defaultDisplay.getSize(point)
}
return point
}
}
}
同样,这里需要考虑一下手机高宽比越来越大的情况。
震动反馈¶
不调用Vibrator
实现震动反馈的两种方式 - 在View
的OnLongClickListener
中返回true
- 调用View#performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
方法
震动反馈能否发生还取决与系统的震动反馈设置,通过
performHapticFeedback
重载方法实现震动反馈可以忽略系统设置。
Android 5.0 平台共享元素动画¶
- 为两个
Activity
中需要进行动画的View
取上相同的transitionName
,若需要同时进行多个元素的动画,每个元素的transitionName
都要不同 - 跳转
Activity
时, - 若只有一个元素,可以调用
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, tv_right, getString(R.string.transition_name)).toBundle())
- 若多个元素,如下
ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(getActivity(), new Pair<>(view.findViewById(R.id.iv_folder_icon), getContext().getString(R.string.transition_task_icon)), new Pair<>(view.findViewById(R.id.tv_folder_progress_value), getContext().getString(R.string.transition_task_progress_value)), new Pair<>(view.findViewById(R.id.pb_folder_progress), getContext().getString(R.string.transition_task_progress)), new Pair<>(view.findViewById(R.id.tv_folder_count), getContext().getString(R.string.transition_task_count))); Intent intent = new Intent(getContext(), TodoFolderActivity.class); getContext().startActivity(intent, activityOptions.toBundle());
由B返回A时,一般情况都也会默认进行共享元素动画返回,特殊情况下可以调用
finishAfterTransition()
进行共享元素动画返回
共享元素动画执行的过程也有监听方法,SharedElementCallback
里面方法比较多,具体可以看源码注释
- Activity#setEnterSharedElementCallback(SharedElementCallback)
- Activity#setExitSharedElementCallback(SharedElementCallback)
- Fragment#setEnterSharedElementCallback(SharedElementCallback)
- Fragment#setExitSharedElementCallback(SharedElementCallback)
- SharedElementCallback
- onSharedElementStart
- onSharedElementEnd
- onRejectSharedElements
- onMapSharedElements
- onSharedElementsArrived
向WebView注入本地JS并调用¶
1.定义本地JS文件(test.js),放到assets目录下
'use strict';
function test() {
$(".fake-box input").val('1');
angular.element(document.getElementById('pwd-input')).scope().$apply('verify_code = "123458"');
}
2.定义webview注入本地js文件的方法
private void injectScriptFile(WebView view, String scriptFile) {
InputStream input;
try {
input = getAssets().open(scriptFile);
byte[] buffer = new byte[input.available()];
input.read(buffer);
input.close();
// String-ify the script byte-array using BASE64 encoding !!!
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
view.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
// Tell the browser to BASE64-decode the string into your script !!!
"script.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(script)" +
"})()");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3.注入并调用
injectScriptFile(webView, "test.js"); // 注入
webView.loadUrl("javascript:setTimeout(test(), 500)"); // 调用
NavigationView菜单分割线¶
给NavigationView
中的菜单添加分割线,只要给每个group添加id即可。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group
android:id="@+id/group_all"
android:checkableBehavior="single">
<item
android:id="@+id/nav_all"
android:icon="@drawable/ic_menu_lightbulb"
android:title="@string/nav_menu_all"
android:checked="true"/>
</group>
<item android:title="@string/nav_menu_labels">
<menu>
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_new_label11"
android:icon="@drawable/ic_menu_lightbulb"
android:title="测试1"/>
<item
android:id="@+id/nav_new_label"
android:icon="@drawable/ic_menu_lightbulb"
android:title="@string/nav_menu_create_new_label" />
</group>
</menu>
</item>
<group
android:id="@+id/group_collection"
android:checkableBehavior="single">
<item
android:id="@+id/nav_archive"
android:icon="@drawable/ic_menu_lightbulb"
android:title="@string/nav_menu_archive" />
<item
android:id="@+id/nav_trash"
android:icon="@drawable/ic_menu_lightbulb"
android:title="@string/nav_menu_trash" />
</group>
<group
android:id="@+id/group_settings"
android:checkableBehavior="single">
<item
android:id="@+id/nav_settings"
android:icon="@drawable/ic_menu_lightbulb"
android:title="@string/nav_menu_settings" />
<item
android:id="@+id/nav_help"
android:icon="@drawable/ic_menu_lightbulb"
android:title="@string/nav_menu_help_and_feedback" />
</group>
</menu>
CardView背景色¶
给CardView
添加背景色要使用app:cardBackgroundColor
,不然会导致app:cardCornerRadius
不生效
从attr中提取资源id¶
从attr中提取资源id,可以使用TypedValue
val typedValue = TypedValue()
theme.resolveAttribute(android.R.attr.colorControlNormal, typedValue, true)
val resourceId = typedValue.resourceId
跳微信扫一扫¶
try {
val intent = mActivity.packageManager.getLaunchIntentForPackage("com.tencent.mm")
intent.putExtra("LauncherUI.From.Scaner.Shortcut", true)
startActivity(intent)
} catch (e: Exception) {
ToastUtils.showLongToast("无法跳转到微信,请检查您是否安装了微信!")
}
RadioGroup互斥¶
RadioGroup里面RadioButton最好都设置id,不然给其中一个设置为默认选中后,其他的RadioButton不会互斥。
不flatDir使用aar包¶
使用aar包不用flatDir,一句代码就好
自定义资源目录¶
android {
sourceSets {
main {
java.srcDirs += 'src/main/kotlin'
res.srcDirs = [
'src/main/res',
'src/main/res_overlay'
]
}
}
}
修改gradle输出包的名字¶
// -----------------------------------------------------------------------------------------
// build script
android {
applicationVariants.all { variant ->
variant.outputs.all { output ->
def newName
def timeNow
if ("true" == IS_JENKINS) {
// Jenkins编译
newName = APP_NAME + '-' + variant.buildType.name + '-' + BUILD_TIME + '.apk'
outputFileName = new File("../../../../..", newName)
} else {
// Android Studio编译
timeNow = new Date().format("yyyyMMddHHmm")
newName = APP_NAME + "-v" + variant.versionName + '-' + variant.buildType.name + '-' + timeNow + '.apk'
outputFileName = newName
}
}
}
}
// -----------------------------------------------------------------------------------------
gradle copy函数¶
android.libraryVariants.all {
it.outputs.all {
outputFileName = "hruilib-${version}-${it.name}.aar"
}
}
project.afterEvaluate {
android.libraryVariants.each {
String variantName = it.name.capitalize()
if (variantName == 'Release') {
def assembleTask = project.tasks.getByName("assemble${variantName}")
assembleTask.doLast {
copy {
from('build/outputs/aar/')
into('../app/libs/')
include("*-release.aar")
}
}
}
}
}
ScrollView始终显示scrollbar¶
实践效果:当可以滑动的时候会显示scollbar,不能滑动的时候不会显示。
AlertDialog消息换行¶
AlertDialog中\n
不换行,调用create().show()
就可以了。
accentColor¶
基础库中UI的style最好不要加上accentColor属性,不然上层可能TextView等各种崩溃
zip/unzip¶
zip -q -r \<zip_file_name> *
unzip \<zip_file_name> -d \<path>
Mac调整Launcher行列数¶
Mac调整Launcher一屏显示多少行、多少列,比如7行10列。
defaults write com.apple.dock springboard-rows -int 7
defaults write com.apple.dock springboard-columns -int 10
defaults write com.apple.dock ResetLaunchPad -bool TRUE;killall Dock
OkHttp下载文件¶
@Suppress("DEPRECATION")
private var progressDialog: ProgressDialog? = null
private var apkFile: File? = null
private fun doDownloadApk(versionRes: VersionRes) {
apkFile = File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "${BuildConfig.APPLICATION_ID}_${versionRes.version}.apk")
// check file is exists or not
if (apkFile?.exists() == true) {
val deleted = apkFile?.delete()
Logger.dTag(TAG_APP, "[SplashActivity] [doDownloadApk] apkFile exists, delete=$deleted")
}
// check download url is illegal
val apkUrl = versionRes.channelUrl
if (apkUrl.isNullOrEmpty()) {
Logger.eTag(TAG_APP, "[SplashActivity] [doDownloadApk] apkUrl isNullOrEmpty >>>>>> ")
viewModel.checkSwitchEnable()
return
}
// show progress dialog
@Suppress("DEPRECATION")
progressDialog = ProgressDialog(this, R.style.HddAlertDialog).apply {
setMessage(getString(R.string.download_apk_title))
setProgressStyle(ProgressDialog.STYLE_HORIZONTAL)
setCancelable(false)
setCanceledOnTouchOutside(false)
show()
}
// begin download
Schedulers.newThread().createWorker().schedule {
try {
Logger.dTag(TAG_APP, "[SplashActivity] [doDownloadApk] download begin")
val request = Request.Builder()
.url(apkUrl)
.build()
val response = OkHttpClient.Builder().build().newCall(request).execute()
// check response body
val responseBody = response.body()
if (responseBody == null) {
viewModel.checkSwitchEnable()
return@schedule
}
val inputStream = responseBody.byteStream()
// get file size
val contentLength = responseBody.contentLength()
// set progress dialog max progress (shown in the bottom-right corner)
// percent will be calculated by system
progressDialog?.max = contentLength.toInt()
Logger.dTag(TAG_APP, "[SplashActivity] [doDownloadApk] contentLength=$contentLength")
// ready write files
val fileOutputStream = FileOutputStream(apkFile)
val bis = BufferedInputStream(inputStream)
val buffer = ByteArray(1024)
var length: Int
var downloaded = 0
// write files
do {
length = bis.read(buffer)
if (length != -1) {
fileOutputStream.write(buffer, 0, length)
// update progress
downloaded += length
val percent = (downloaded * 100F / contentLength).toInt()
progressDialog?.progress = downloaded
Logger.dTag(TAG_APP, "[SplashActivity] [onProgress] progress = $percent")
}
} while (length != -1)
fileOutputStream.flush()
fileOutputStream.close()
bis.close()
inputStream.close()
Logger.dTag(TAG_APP, "[SplashActivity] [doDownloadApk] download end")
// write files done
progressDialog?.dismiss()
// install apk
if (FileUtils.isFileExists(apkFile)) {
@Suppress("DEPRECATION")
AppUtils.installApp(this@SplashActivity, apkFile, Constants.FILE_PROVIDER, REQUEST_INSTALL_APP)
}
} catch (e: Exception) {
e.printStackTrace()
runOnUiThread {
YLToastUtils.showToast(
getString(R.string.download_apk_error_try_again, e.message),
duration = Toast.LENGTH_LONG
)
viewModel.checkSwitchEnable()
}
}
}
}
monkey测试:¶
adb shell monkey -p <package-name> --throttle 100 --pct-touch 50 --pct-motion 50 -v -v <count> > <file_path>
App物料尺寸¶
app icon的尺寸:
logo (3:4:6:8:12:16)
name | scale | 普通 | adaptive icon |
---|---|---|---|
ldip | 0.75 | 108 | 81 |
mdpi | 1 | 144 | 108 |
hdpi | 1.5 | 192 | 162 |
xhdpi | 2 | 256 | 216 |
xxhdpi | 3 | 384 | 324 |
xxxhdpi | 4 | 512 | 432 |
adaptive icon直接采用Android Studio中Image Asset工具进行生成即可。
两者可以共存:
- 在mipmap-*dpi中放入普通的icon,取名为ic_launcher
- 使用Image Asset工具生成adaptive icon,在Legacy选项卡中去除不需要的icon。这样会生成会在mipmap-*dpi目录下生成一套ic_launcher_foreground和一套ic_launcher_background,同时会在mipmap-anydpi-v26中生成一个ic_launcher.xml文件,里面会引用ic_launcher_foreground和ic_launcher_background资源。
引导页 - 2160×1080(适配全面屏) - 1920x1080 - 720x1280
屏幕快照 - 480x800 (vivo) - 1080x1920
StatusBar和NavigationBar完全透明¶
代码方式:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = Color.TRANSPARENT
window.navigationBarColor = Color.TRANSPARENT
}
window.setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
)
StatusBarUtil.setTransparent(this, false)
From StackOverflow
查看签名证书信息¶
然后输入密码即可。
Dynamic Permission¶
Android在6.0及后对于危险权限需要动态申请,目前(2019-06-24)动态权限有以下10组共计26个权限,表格如下:
Permission Group | Permissions |
---|---|
CALENDAR | READ_CALENDAR WRITE_CALENDAR |
CALL_LOG | READ_CALL_LOG WRITE_CALL_LOG PROCESS_OUTGOING_CALLS |
CAMERA | CAMERA |
CONTACTS | READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
LOCATION | ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION |
MICROPHONE | RECORD_AUDIO |
PHONE | READ_PHONE_STATE READ_PHONE_NUMBERS CALL_PHONE ANSWER_PHONE_CALLS ADD_VOICEMAIL USE_SIP |
SENSORS | BODY_SENSORS |
SMS | SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
STORAGE | READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE |
注:您的应用仍需要明确请求其需要的每项权限,即使用户已向应用授予该权限组中的其他权限。此外,权限分组在将来的 Android 版本中可能会发生变化。您的代码不应依赖特定权限属于或不属于相同组这种假设。
在 Android 11 上,大部分权限都被移动到了
android.permission-group.UNDEFINED
这个权限组下面;但是实际表现上来说,权限还是和上面列表中的认知一样。这就导致我们判断权限组出现了很大的问题,我们无法运行时判断出哪些权限属于哪个组。
权限组的获取可以使用下面的命令:adb shell pm list permissions -d -g
代码中可以使用packageManager.getAllPermissionGroups(PackageManager.GET_META_DATA)
获取权限组,然后根据权限组的 name 调用packageManager.queryPermissionsByGroup(groupName, PackageManager.GET_META_DATA)
去获取权限组下面的权限。 系统权限请求框对权限的归类: https://cs.android.com/android/platform/superproject/+/master:packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java;drc=master;l=148
运行时权限的处理涉及到以下四个方法:
ContextCompat.checkSelfPermission
检查权限是否已经授予ActivityCompat.shouldShowRequestPermissionRationale
在用户已经拒绝某项权限时,用来向用户解释为什么需要权限。
如果用户没有申请过、或者第二次或以上拒绝时选择了Don't ask again
选项,此方法会返回false
如果用户拒绝了权限请求,此方法会返回trueActivityCompat.requestPermissions
申请权限onRequestPermissionsResult
申请权限的回调
动态权限申请流程代码片段如下:
private fun permission() {
val thisActivity = this
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
// @@@ add by author
showRequestPermissionRationale()
// @@@
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
arrayOf(Manifest.permission.READ_CONTACTS),
MY_PERMISSIONS_REQUEST_READ_CONTACTS)
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// Permission has already been granted
}
}
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_READ_CONTACTS -> {
// If request is cancelled, the result arrays are empty.
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return
}
// Add other 'when' lines to check for other
// permissions this app might request.
else -> {
// Ignore all other requests.
}
}
}
private fun showRequestPermissionRationale() {
AlertDialog.Builder(this)
.setTitle("RequestPermissionRationale")
.setMessage("This is the message")
.setPositiveButton(android.R.string.ok) { _, _ ->
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_CONTACTS),
MY_PERMISSIONS_REQUEST_READ_CONTACTS)
}.setNegativeButton(android.R.string.cancel, null)
.create()
.show()
}
companion object {
private const val MY_PERMISSIONS_REQUEST_READ_CONTACTS = 0x1111
}
BTW,在权限请求回调的权限拒绝的分支中,此时我们再次调用
ActivityCompat.shouldShowRequestPermissionRationale
方法,如果返回true表示用户拒绝了权限;如果返回了false,表示用户拒绝了权限且勾选了不再提醒,此时我们弹框提醒用户。
可以参考PermissionDispatcher中生成的辅助代码——MainActivity.kt对应的辅助代码
Google Chrome强制禁用darkmode¶
ANR的判定¶
- Activity超过5秒无响应
- BroadcastReceiver超过10秒无响应
- Service超过20秒无响应
RecyclerView是否到顶部¶
RecyclerView.canScrollVertically(-1)
true
表示还没有到顶部false
表示到顶部了
判断程序是否运行在主进程¶
私有多进程下,pid相等的进程可能是主进程或者子进程。获取当前进程id对应的进程,判断进程名是否是包名即可。
private fun isMainProcess(context: Context) : Boolean {
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
activityManager?.runningAppProcesses?.find {
it.pid == Process.myPid()
}?.let {
return it.processName == context.packageName
}
return false
}
Drawable2Bitmap¶
通过Canvas将Drawable画到空白的Bitmap上。
private fun getBitmapFromDrawableResourceId(context: Context, @DrawableRes drawableId: Int): Bitmap {
val drawable = ContextCompat.getDrawable(context, drawableId)!!
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
drawable.draw(canvas)
return bitmap
}
Gravity的妙用¶
在一个小红点需求中,由于想封装的更完整一点,所以设计了一个包裹普通View的小红点FrameLayout,该FrameLayout监听对应的小红点事件,从而显示或隐藏小红点。这样业务上的View一般情况无需处理小红点的相关逻辑。
所以在设计BadgeFrameLayout时,需要事先设置好小红点需要显示的位置,这里参考了gravity的一些实现:
BadgeFrameLayout使用下面属性来指定小红点的位置:
<declare-styleable name="BadgeFrameLayout">
<!-- badge的方位 -->
<attr name="badgeGravity" format="flags">
<flag name="top" value="0x30" />
<flag name="bottom" value="0x50" />
<flag name="left" value="0x03" />
<flag name="right" value="0x05" />
<flag name="center_vertical" value="0x10" />
<flag name="center_horizontal" value="0x01" />
<flag name="center" value="0x11" />
</attr>
<!-- badge在X-Y方向上的偏移量,follow gravity -->
<attr name="badgeXAdj" format="dimension" />
<attr name="badgeYAdj" format="dimension" />
...
</declare-styleable>
在代码中这样来确定小红点的rect:
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
// 容器的rect
mBadgeContainer.set(0, 0, measuredWidth, measuredHeight)
// mBadgeRadius为小红点的半径,mBadgeRect就是计算出来的小红点的rect
Gravity.apply(mGravity,
mBadgeRadius shl 1,
mBadgeRadius shl 1,
mBadgeContainer,
mBadgeXAdj,
mBadgeYAdj,
mBadgeRect
)
}
Gravity.apply
方法可以避免绘制超过边界,不需要我们自己做一些麻烦的运算,还是相当方便的。方法解释见: https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/Gravity.java;l=186?q=Gravity.apply
9patch¶
长期不用还是会忘记,具体来说可以参考Google官网
左边上边的线条决定哪些区域可以被缩放,右边下边的线条决定哪个区域显示内容。
nm命令查看so里面的函数¶
~/Downloads/lib nm -D libjavacore.so
U BN_CTX_free
U BN_CTX_new
U BN_add
U BN_add_word
U BN_bin2bn
U BN_bn2bin
U BN_bn2dec
U BN_bn2hex
U BN_bn2le_padded
U BN_cmp
U BN_copy
U BN_dec2bn
U BN_div
U BN_exp
U BN_free
U BN_gcd
U BN_generate_prime_ex
U BN_get_u64
U BN_hex2bn
U BN_init
U BN_is_bit_set
U BN_is_negative
U BN_is_pow2
U BN_is_zero
U BN_le2bn
U BN_lshift
U BN_mod_exp
U BN_mod_inverse
U BN_mod_word
U BN_mul
U BN_mul_word
U BN_new
U BN_nnmod
U BN_nnmod_pow2
U BN_num_bits
U BN_num_bytes
U BN_primality_test
U BN_rshift
U BN_set_negative
U BN_set_u64
U BN_sub
U BN_zero
U ERR_clear_error
U ERR_error_string_n
U ERR_get_error
0000efb0 T JNI_OnLoad
0000f130 T JNI_OnUnload
U OPENSSL_free
U UCNV_FROM_U_CALLBACK_SKIP_60
U UCNV_FROM_U_CALLBACK_STOP_60
U UCNV_TO_U_CALLBACK_STOP_60
U XML_ErrorString
U XML_ExternalEntityParserCreate
U XML_GetCurrentColumnNumber
U XML_GetCurrentLineNumber
U XML_GetErrorCode
U XML_Parse
U XML_ParserCreate
U XML_ParserCreateNS
U XML_ParserFree
U XML_SetCdataSectionHandler
U XML_SetCharacterDataHandler
U XML_SetCommentHandler
U XML_SetDoctypeDeclHandler
U XML_SetElementHandler
U XML_SetExternalEntityRefHandler
U XML_SetNamespaceDeclHandler
U XML_SetNotationDeclHandler
U XML_SetProcessingInstructionHandler
U XML_SetReturnNSTriplet
U XML_SetUnparsedEntityDeclHandler
U XML_SetUserData
000313c0 T _Z11longValueOfP7_JNIEnvx
0000eef0 T _Z11setBlockingib
00031490 T _Z12booleanValueP7_JNIEnvP8_jobject
00015350 T _Z12lowestSetBitPy
00031220 T _Z13doubleValueOfP7_JNIEnvd
00016010 T _Z13floatExponentf
00015fe0 T _Z13floatMantissaf
000152b0 T _Z13highestSetBitPy
000212b0 W _Z13toStringArrayI13VectorCounter12VectorGetterEP13_jobjectArrayP7_JNIEnvPT_PT0_
U _Z13toStringArrayP7_JNIEnvPKPKc
00031150 T _Z14booleanValueOfP7_JNIEnvh
00015fc0 T _Z14doubleExponentd
00015f80 T _Z14doubleMantissad
000312f0 T _Z14integerValueOfP7_JNIEnvi
U _Z14newStringArrayP7_JNIEnvj
00014a20 T _Z16addHighPrecisionPyiS_i
0000f470 T _Z17toNativeZipStreamx
00015580 T _Z20compareHighPrecisionPyiS_i
0000e050 T _Z21fromStringEnumerationP7_JNIEnvR10UErrorCodePKcPN6icu_6017StringEnumerationE
0000eeb0 T _Z21inetAddressToSockaddrP7_JNIEnvP8_jobjectiR16sockaddr_storageRi
00014e00 T _Z21multiplyHighPrecisionPyiS_iS_i
0000e4c0 T _Z21sockaddrToInetAddressP7_JNIEnvRK16sockaddr_storagePi
00014b50 T _Z21subtractHighPrecisionPyiS_i
00015660 T _Z21toDoubleHighPrecisionPyi
0000e2b0 T _Z22maybeThrowIcuExceptionP7_JNIEnvPKc10UErrorCode
000149a0 T _Z22simpleAddHighPrecisionPyiy
0000e450 T _Z23jniThrowSocketExceptionP7_JNIEnvi
0000e410 T _Z24jniThrowOutOfMemoryErrorP7_JNIEnvPKc
0001ab70 T _Z24register_libcore_icu_ICUP7_JNIEnv
000310e0 T _Z24register_sun_misc_UnsafeP7_JNIEnv
000154d0 T _Z25lowestSetBitHighPrecisionPyi
00021d30 T _Z25register_libcore_io_LinuxP7_JNIEnv
000153e0 T _Z26highestSetBitHighPrecisionPyi
0000e3a0 T _Z26jniThrowExceptionWithErrnoP7_JNIEnvPKci
0002cba0 T _Z26register_libcore_io_MemoryP7_JNIEnv
0000f1e0 T _Z26throwExceptionForZlibErrorP7_JNIEnvPKciP15NativeZipStream
0001aef0 T _Z26unregister_libcore_icu_ICUP7_JNIEnv
000182b0 T _Z27register_java_math_NativeBNP7_JNIEnv
00015ac0 T _Z27timesTenToTheEHighPrecisionPyii
00015080 T _Z28simpleShiftLeftHighPrecisionPyii
0000e840 T _Z29inetAddressToSockaddrVerbatimP7_JNIEnvP8_jobjectiR16sockaddr_storageRi
00016030 T _Z31register_java_lang_StringToRealP7_JNIEnv
00019b40 T _Z32register_java_util_regex_MatcherP7_JNIEnv
0001a7e0 T _Z32register_java_util_regex_PatternP7_JNIEnv
000215f0 T _Z34register_libcore_icu_TimeZoneNamesP7_JNIEnv
0000f480 T _Z35register_android_system_OsConstantsP7_JNIEnv
00017ab0 T _Z35register_java_lang_invoke_VarHandleP7_JNIEnv
0001f620 T _Z36register_libcore_icu_NativeConverterP7_JNIEnv
00015020 T _Z37simpleAppendDecimalDigitHighPrecisionPyiy
000179f0 T _Z38register_java_lang_invoke_MethodHandleP7_JNIEnv
0002e820 T _Z43register_org_apache_harmony_xml_ExpatParserP7_JNIEnv
00021cb0 T _Z44register_libcore_io_AsynchronousCloseMonitorP7_JNIEnv
0002e7b0 T _Z46register_libcore_util_NativeAllocationRegistryP7_JNIEnv
000315f0 T _Z51register_org_apache_harmony_dalvik_NativeTestTargetP7_JNIEnv
00031540 T _Z8intValueP7_JNIEnvP8_jobject
0000e040 T _ZN11ExecStrings3getEv
0000de30 T _ZN11ExecStringsC1EP7_JNIEnvP13_jobjectArray
0000de30 T _ZN11ExecStringsC2EP7_JNIEnvP13_jobjectArray
0000df20 T _ZN11ExecStringsD1Ev
0000df20 T _ZN11ExecStringsD2Ev
U _ZN12JniConstants11doubleClassE
U _ZN12JniConstants11stringClassE
U _ZN12JniConstants12booleanClassE
U _ZN12JniConstants12integerClassE
U _ZN12JniConstants13structIfaddrsE
U _ZN12JniConstants14byteArrayClassE
U _ZN12JniConstants15charsetICUClassE
U _ZN12JniConstants15localeDataClassE
U _ZN12JniConstants15structStatClassE
U _ZN12JniConstants16inetAddressClassE
U _ZN12JniConstants16structFlockClassE
U _ZN12JniConstants16structUcredClassE
U _ZN12JniConstants17gaiExceptionClassE
U _ZN12JniConstants17inet6AddressClassE
U _ZN12JniConstants17structLingerClassE
U _ZN12JniConstants17structPasswdClassE
U _ZN12JniConstants17structPollfdClassE
U _ZN12JniConstants18structStatVfsClassE
U _ZN12JniConstants18structTimevalClassE
U _ZN12JniConstants18structUtsnameClassE
U _ZN12JniConstants19errnoExceptionClassE
U _ZN12JniConstants19fileDescriptorClassE
U _ZN12JniConstants19structAddrinfoClassE
U _ZN12JniConstants19structGroupReqClassE
U _ZN12JniConstants19structTimespecClassE
U _ZN12JniConstants22inetAddressHolderClassE
U _ZN12JniConstants22inetSocketAddressClassE
U _ZN12JniConstants22unixSocketAddressClassE
U _ZN12JniConstants23inet6AddressHolderClassE
U _ZN12JniConstants24packetSocketAddressClassE
U _ZN12JniConstants25netlinkSocketAddressClassE
U _ZN12JniConstants27patternSyntaxExceptionClassE
U _ZN12JniConstants28inetSocketAddressHolderClassE
U _ZN12JniConstants4initEP7_JNIEnv
U _ZN12JniConstants9longClassE
0000f300 T _ZN15NativeZipStream13setDictionaryEP7_JNIEnvP11_jbyteArrayiib
0000f3d0 T _ZN15NativeZipStream8setInputEP7_JNIEnvP11_jbyteArrayii
0000f250 T _ZN15NativeZipStreamC1Ev
0000f250 T _ZN15NativeZipStreamC2Ev
0000f2b0 T _ZN15NativeZipStreamD1Ev
0000f2b0 T _ZN15NativeZipStreamD2Ev
U _ZN24AsynchronousCloseMonitor20signalBlockedThreadsEi
U _ZN24AsynchronousCloseMonitor4initEv
U _ZN24AsynchronousCloseMonitorC1Ei
U _ZN24AsynchronousCloseMonitorD1Ev
U _ZN6icu_6010UnicodeSetC1Ev
U _ZN6icu_6010UnicodeSetD1Ev
U _ZN6icu_6012NumberFormat14createInstanceERKNS_6LocaleE18UNumberFormatStyleR10UErrorCode
U _ZN6icu_6012RegexMatcher18useAnchoringBoundsEa
U _ZN6icu_6012RegexMatcher20useTransparentBoundsEa
U _ZN6icu_6012RegexMatcher4findEv
U _ZN6icu_6012RegexMatcher4findExR10UErrorCode
U _ZN6icu_6012RegexMatcher5resetEP5UText
U _ZN6icu_6012RegexMatcher6regionExxR10UErrorCode
U _ZN6icu_6012RegexMatcher7matchesER10UErrorCode
U _ZN6icu_6012RegexMatcher9lookingAtER10UErrorCode
U _ZN6icu_6012RegexPattern7compileERKNS_13UnicodeStringEjR11UParseErrorR10UErrorCode
U _ZN6icu_6013BreakIterator22createSentenceInstanceERKNS_6LocaleER10UErrorCode
U _ZN6icu_6013TimeZoneNames14createInstanceERKNS_6LocaleER10UErrorCode
U _ZN6icu_6013UnicodeString10setToBogusEv
U _ZN6icu_6013UnicodeString19getTerminatedBufferEv
U _ZN6icu_6013UnicodeString5setToEaNS_14ConstChar16PtrEi
U _ZN6icu_6013UnicodeString7toLowerERKNS_6LocaleE
U _ZN6icu_6013UnicodeString7toTitleEPNS_13BreakIteratorERKNS_6LocaleEj
U _ZN6icu_6013UnicodeString7toUpperERKNS_6LocaleE
U _ZN6icu_6013UnicodeString8fromUTF8ENS_11StringPieceE
U _ZN6icu_6013UnicodeStringC1EPKciNS0_10EInvariantE
U _ZN6icu_6013UnicodeStringC1ERKS0_
U _ZN6icu_6013UnicodeStringD1Ev
U _ZN6icu_6013UnicodeStringaSERKS0_
U _ZN6icu_6017DateFormatSymbolsC1ERKNS_6LocaleER10UErrorCode
U _ZN6icu_6017DateFormatSymbolsD1Ev
U _ZN6icu_6018UStringEnumeration5snextER10UErrorCode
U _ZN6icu_6018UStringEnumerationC1EP12UEnumeration
U _ZN6icu_6018UStringEnumerationD1Ev
U _ZN6icu_6020DecimalFormatSymbolsC1ERKNS_6LocaleER10UErrorCode
U _ZN6icu_6020DecimalFormatSymbolsD1Ev
U _ZN6icu_6024DateTimePatternGenerator14createInstanceERKNS_6LocaleER10UErrorCode
U _ZN6icu_6024DateTimePatternGenerator14getBestPatternERKNS_13UnicodeStringER10UErrorCode
U _ZN6icu_606Locale10getDefaultEv
U _ZN6icu_606Locale10setDefaultERKS0_R10UErrorCode
U _ZN6icu_606Locale10setToBogusEv
U _ZN6icu_606Locale14createFromNameEPKc
U _ZN6icu_606Locale15getISOCountriesEv
U _ZN6icu_606Locale15getISOLanguagesEv
U _ZN6icu_606LocaleC1Ev
U _ZN6icu_606LocaleD1Ev
U _ZN6icu_606LocaleaSERKS0_
U _ZN6icu_607UMemorydlEPv
U _ZN6icu_608ByteSink15GetAppendBufferEiiPciPi
U _ZN6icu_608ByteSink5FlushEv
U _ZN6icu_608ByteSinkD2Ev
U _ZN6icu_608Calendar14createInstanceERKNS_6LocaleER10UErrorCode
U _ZN6icu_608Calendar6getNowEv
U _ZN6icu_608TimeZone14getCanonicalIDERKNS_13UnicodeStringERS1_R10UErrorCode
U _ZN6icu_608TimeZone16getTZDataVersionER10UErrorCode
U _ZN7android22ClearJniConstantsCacheEv
00033320 T _ZN7android4base10LogMessage6streamEv
00033bc0 T _ZN7android4base10LogMessage7LogLineEPKcjNS0_5LogIdENS0_11LogSeverityES3_
00033870 T _ZN7android4base10LogMessage7LogLineEPKcjNS0_5LogIdENS0_11LogSeverityES3_S3_
00033330 T _ZN7android4base10LogMessageC1EPKcjNS0_5LogIdENS0_11LogSeverityES3_i
00033430 T _ZN7android4base10LogMessageC1EPKcjNS0_5LogIdENS0_11LogSeverityEi
00033330 T _ZN7android4base10LogMessageC2EPKcjNS0_5LogIdENS0_11LogSeverityES3_i
00033430 T _ZN7android4base10LogMessageC2EPKcjNS0_5LogIdENS0_11LogSeverityEi
00033470 T _ZN7android4base10LogMessageD1Ev
00033470 T _ZN7android4base10LogMessageD2Ev
00032a70 T _ZN7android4base10LogdLoggerC1ENS0_5LogIdE
00032a70 T _ZN7android4base10LogdLoggerC2ENS0_5LogIdE
00032a90 T _ZN7android4base10LogdLoggerclENS0_5LogIdENS0_11LogSeverityEPKcS5_jS5_
000331c0 T _ZN7android4base10SetAborterEONSt3__18functionIFvPKcEEE
00035730 T _ZN7android4base10StartsWithERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKc
00035780 T _ZN7android4base10StartsWithERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_
00031ec0 T _ZN7android4base10WriteFullyEiPKvj
00032b10 T _ZN7android4base11InitLoggingEPPcONSt3__18functionIFvNS0_5LogIdENS0_11LogSeverityEPKcS8_jS8_EEEONS4_IFvS8_EEE
00032790 T _ZN7android4base12KernelLoggerENS0_5LogIdENS0_11LogSeverityEPKcS4_jS4_
00032960 T _ZN7android4base12StderrLoggerENS0_5LogIdENS0_11LogSeverityEPKcS4_jS4_
00034a10 T _ZN7android4base12StringPrintfEPKcz
000325e0 T _ZN7android4base13GetDefaultTagEv
000326a0 T _ZN7android4base13SetDefaultTagERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
00034a80 T _ZN7android4base13StringAppendFEPNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKcz
00034920 T _ZN7android4base13StringAppendVEPNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKcPc
00032a40 T _ZN7android4base14DefaultAborterEPKc
00031770 T _ZN7android4base14ReadFdToStringEiPNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
00031910 T _ZN7android4base15WriteStringToFdERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEi
00035a90 T _ZN7android4base16EqualsIgnoreCaseERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_
00031860 T _ZN7android4base16ReadFileToStringERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPS7_b
000321f0 T _ZN7android4base17GetExecutablePathEv
00031dc0 T _ZN7android4base17ReadFullyAtOffsetEiPvjx
00033c30 T _ZN7android4base17ScopedLogSeverityC1ENS0_11LogSeverityE
00033c30 T _ZN7android4base17ScopedLogSeverityC2ENS0_11LogSeverityE
00033c60 T _ZN7android4base17ScopedLogSeverityD1Ev
00033c60 T _ZN7android4base17ScopedLogSeverityD2Ev
00031c50 T _ZN7android4base17WriteStringToFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_b
000319a0 T _ZN7android4base17WriteStringToFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_tjjb
00035990 T _ZN7android4base18EndsWithIgnoreCaseERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKc
00035a10 T _ZN7android4base18EndsWithIgnoreCaseERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_
00031f30 T _ZN7android4base18RemoveFileIfExistsERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPS7_
000357e0 T _ZN7android4base20StartsWithIgnoreCaseERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKc
00035830 T _ZN7android4base20StartsWithIgnoreCaseERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_
00033300 T _ZN7android4base21GetMinimumLogSeverityEv
00033c00 T _ZN7android4base21SetMinimumLogSeverityENS0_11LogSeverityE
000322b0 T _ZN7android4base22GetExecutableDirectoryEv
00034f10 W _ZN7android4base4JoinINSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEERKS9_EES9_RKT_T0_
00034ae0 W _ZN7android4base4JoinINSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEEcEES9_RKT_T0_
00035170 W _ZN7android4base4JoinINSt3__16vectorIPKcNS2_9allocatorIS5_EEEERKNS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEEEESD_RKT_T0_
00034d10 W _ZN7android4base4JoinINSt3__16vectorIPKcNS2_9allocatorIS5_EEEEcEENS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEERKT_T0_
000355b0 T _ZN7android4base4TrimERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
00035390 T _ZN7android4base5SplitERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_
000323b0 T _ZN7android4base7DirnameERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
00032410 T _ZN7android4base8BasenameERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
00035890 T _ZN7android4base8EndsWithERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKc
00035910 T _ZN7android4base8EndsWithERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_
00032010 T _ZN7android4base8ReadlinkERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPS7_
00032170 T _ZN7android4base8RealpathERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPS7_
00031d40 T _ZN7android4base9ReadFullyEiPvj
00033080 T _ZN7android4base9SetLoggerEONSt3__18functionIFvNS0_5LogIdENS0_11LogSeverityEPKcS6_jS6_EEE
U _ZNK24AsynchronousCloseMonitor11wasSignaledEv
U _ZNK6icu_6010UnicodeSet11containsAllERKS0_
U _ZNK6icu_6012RegexMatcher10groupCountEv
U _ZNK6icu_6012RegexMatcher10requireEndEv
U _ZNK6icu_6012RegexMatcher3endEiR10UErrorCode
U _ZNK6icu_6012RegexMatcher5startEiR10UErrorCode
U _ZNK6icu_6012RegexMatcher6hitEndEv
U _ZNK6icu_6012RegexPattern19groupNumberFromNameERKNS_13UnicodeStringER10UErrorCode
U _ZNK6icu_6012RegexPattern7matcherER10UErrorCode
U _ZNK6icu_6013UnicodeString6toUTF8ERNS_8ByteSinkE
U _ZNK6icu_6013UnicodeString7extractENS_9Char16PtrEiR10UErrorCode
U _ZNK6icu_6013UnicodeString8doEqualsERKS0_i
U _ZNK6icu_6013UnicodeString9doCompareEiiPKDsii
U _ZNK6icu_6017DateFormatSymbols11getWeekdaysERiNS0_13DtContextTypeENS0_11DtWidthTypeE
U _ZNK6icu_6017DateFormatSymbols14getAmPmStringsERi
U _ZNK6icu_6017DateFormatSymbols7getErasERi
U _ZNK6icu_6017DateFormatSymbols9getMonthsERiNS0_13DtContextTypeENS0_11DtWidthTypeE
U _ZNK6icu_6018UStringEnumeration5countER10UErrorCode
U _ZNK6icu_606Locale11getBaseNameEv
U _ZNK6icu_606Locale14getISO3CountryEv
U _ZNK6icu_606Locale15getISO3LanguageEv
U _ZNK6icu_606Locale16getDisplayScriptERKS0_RNS_13UnicodeStringE
U _ZNK6icu_606Locale17getDisplayCountryERKS0_RNS_13UnicodeStringE
U _ZNK6icu_606Locale17getDisplayVariantERKS0_RNS_13UnicodeStringE
U _ZNK6icu_606Locale18getDisplayLanguageERKS0_RNS_13UnicodeStringE
U _ZNK6icu_608Calendar17getFirstDayOfWeekEv
U _ZNK6icu_608Calendar25getMinimalDaysInFirstWeekEv
00033d10 W _ZNKSt3__110__function6__funcIN7android4base10LogdLoggerENS_9allocatorIS4_EEFvNS3_5LogIdENS3_11LogSeverityEPKcSA_jSA_EE7__cloneEPNS0_6__baseISB_EE
00033cd0 W _ZNKSt3__110__function6__funcIN7android4base10LogdLoggerENS_9allocatorIS4_EEFvNS3_5LogIdENS3_11LogSeverityEPKcSA_jSA_EE7__cloneEv
00033e80 W _ZNKSt3__110__function6__funcIPFvPKcENS_9allocatorIS5_EES4_E7__cloneEPNS0_6__baseIS4_EE
00033e40 W _ZNKSt3__110__function6__funcIPFvPKcENS_9allocatorIS5_EES4_E7__cloneEv
U _ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4findEcj
00034680 W _ZNKSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE3strEv
U _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv
U _ZNKSt3__121__basic_string_commonILb1EE20__throw_length_errorEv
U _ZNKSt3__16locale9use_facetERNS0_2idE
U _ZNKSt3__18ios_base6getlocEv
00033d50 W _ZNSt3__110__function6__funcIN7android4base10LogdLoggerENS_9allocatorIS4_EEFvNS3_5LogIdENS3_11LogSeverityEPKcSA_jSA_EE18destroy_deallocateEv
00033d40 W _ZNSt3__110__function6__funcIN7android4base10LogdLoggerENS_9allocatorIS4_EEFvNS3_5LogIdENS3_11LogSeverityEPKcSA_jSA_EE7destroyEv
00033d80 W _ZNSt3__110__function6__funcIN7android4base10LogdLoggerENS_9allocatorIS4_EEFvNS3_5LogIdENS3_11LogSeverityEPKcSA_jSA_EEclEOS7_OS8_OSA_SF_OjSF_
00033ec0 W _ZNSt3__110__function6__funcIPFvPKcENS_9allocatorIS5_EES4_E18destroy_deallocateEv
00033eb0 W _ZNSt3__110__function6__funcIPFvPKcENS_9allocatorIS5_EES4_E7destroyEv
00033ef0 W _ZNSt3__110__function6__funcIPFvPKcENS_9allocatorIS5_EES4_EclEOS3_
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKcj
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6assignEPKc
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6assignEPKcj
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6resizeEjc
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7reserveEj
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9push_backEc
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1ERKS5_
U _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1ERKS5_jjRKS4_
U _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryC1ERS3_
U _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryD1Ev
U _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEED0Ev
U _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEED1Ev
U _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEED2Ev
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE4syncEv
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5imbueERKNS_6localeE
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5uflowEv
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE6setbufEPci
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE6xsgetnEPci
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE6xsputnEPKci
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE9showmanycEv
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEEC2Ev
U _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEED2Ev
00034220 W _ZNSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE7seekoffExNS_8ios_base7seekdirEj
000344b0 W _ZNSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE8overflowEi
00034450 W _ZNSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE9pbackfailEi
00034410 W _ZNSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE9underflowEv
U _ZNSt3__115recursive_mutex4lockEv
U _ZNSt3__115recursive_mutex6unlockEv
U _ZNSt3__115recursive_mutexC1Ev
0001a4b0 W _ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_j
U _ZNSt3__15ctypeIcE2idE
U _ZNSt3__15mutex4lockEv
U _ZNSt3__15mutex6unlockEv
U _ZNSt3__16localeD1Ev
0002c510 W _ZNSt3__16vectorI5iovecNS_9allocatorIS1_EEE21__push_back_slow_pathIRKS1_EEvOT_
00021150 W _ZNSt3__16vectorINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEENS4_IS6_EEE21__push_back_slow_pathIRKS6_EEvOT_
00035ae0 W _ZNSt3__16vectorINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEENS4_IS6_EEE21__push_back_slow_pathIS6_EEvOT_
0002caa0 W _ZNSt3__16vectorIP13ScopedBytesRONS_9allocatorIS2_EEE21__push_back_slow_pathIS2_EEvOT_
0002c410 W _ZNSt3__16vectorIP13ScopedBytesRWNS_9allocatorIS2_EEE21__push_back_slow_pathIS2_EEvOT_
0002be90 W _ZNSt3__16vectorIP24AsynchronousCloseMonitorNS_9allocatorIS2_EEE21__push_back_slow_pathIS2_EEvOT_
00032470 W _ZNSt3__16vectorIcNS_9allocatorIcEEE8__appendEj
U _ZNSt3__18ios_base4initEPv
U _ZNSt3__18ios_base5clearEj
U _ZNSt3__19basic_iosIcNS_11char_traitsIcEEED2Ev
U _ZSt7nothrow
00044540 V _ZTCNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_13basic_ostreamIcS2_EE
00044524 V _ZTTNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE
U _ZTVN6icu_6013UnicodeStringE
00044480 V _ZTVN6icu_6014StringByteSinkINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE
000444b4 V _ZTVNSt3__110__function6__funcIN7android4base10LogdLoggerENS_9allocatorIS4_EEFvNS3_5LogIdENS3_11LogSeverityEPKcSA_jSA_EEE
000444d8 V _ZTVNSt3__110__function6__funcIPFvPKcENS_9allocatorIS5_EES4_EE
00044568 V _ZTVNSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEEE
000444fc V _ZTVNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE
U _ZTv0_n12_NSt3__113basic_ostreamIcNS_11char_traitsIcEEED0Ev
U _ZTv0_n12_NSt3__113basic_ostreamIcNS_11char_traitsIcEEED1Ev
U _ZdaPv
U _ZdlPv
U _Znaj
U _ZnajRKSt9nothrow_t
U _Znwj
U __android_log_buf_print
U __android_log_print
00045f98 A __bss_start
U __cxa_atexit
U __cxa_finalize
U __cxa_guard_acquire
U __cxa_guard_release
U __errno
U __libc_current_sigrtmax
U __libc_current_sigrtmin
U __memcpy_chk
U __open_2
U __pread_chk
U __read_chk
U __register_atfork
U __stack_chk_fail
U __stack_chk_guard
U __strcat_chk
U __strcpy_chk
U __strlen_chk
U __umask_chk
U __vsnprintf_chk
00045f98 A _edata
00046418 A _end
U abort
U accept
U access
U android_getaddrinfofornet
U android_set_abort_message
U basename
U bind
U capget
U capset
U chmod
U chown
U clock_gettime
U close
U connect
U deflateSetDictionary
U dirname
U dup
U dup2
U environ
U execv
U execve
U fchmod
U fchown
U fcntl
U fdatasync
U fprintf
U free
U freeaddrinfo
U freeifaddrs
U fstat
U fstatvfs
U fsync
U ftruncate64
U gai_strerror
U getegid
U getenv
U geteuid
U getgid
U getifaddrs
U getnameinfo
U getpeername
U getpgid
U getpid
U getppid
U getprogname
U getpwnam_r
U getpwuid_r
U getrlimit
U getsockname
U getsockopt
U gettid
U getuid
U getxattr
U if_indextoname
U if_nametoindex
U inet_pton
U inflateSetDictionary
U ioctl
U isatty
U isspace
U jniCreateFileDescriptor
U jniCreateString
U jniGetFDFromFileDescriptor
U jniRegisterNativeMethods
U jniSetFileDescriptorOfFD
U jniStrError
U jniThrowException
U jniThrowExceptionFmt
U jniThrowNullPointerException
U kill
U lchown
U link
U listen
U listxattr
U localtime_r
U lseek64
U lstat
U madvise
U malloc
U memcpy
U memmove
U memset
U mincore
U mkdir
U mkfifo
U mlock
U mmap
U mmap64
U msync
U munlock
U munmap
U open
U pipe2
U poll
U posix_fallocate64
U pow
U prctl
U pread
U pread64
U pwrite64
U read
U readlink
U readv
U realpath
U recvfrom
U remove
U removexattr
U rename
U sendfile
U sendto
U setegid
U setenv
U seteuid
U setgid
U setpgid
U setregid
U setreuid
U setsid
U setsockopt
U setuid
U setxattr
U shutdown
U socket
U socketpair
U splice
U stat
U statvfs
U stderr
U strcasecmp
U strchr
U strcmp
U strcpy
U strdup
U strerror
U strftime
U strlen
U strncasecmp
U strncmp
U strncpy
U strrchr
U strsignal
U strtok_r
U symlink
U sysconf
U tcdrain
U tcsendbreak
U time
U u_cleanup_60
U u_errorName_60
U u_getUnicodeVersion_60
U u_getVersion_60
U u_init_60
U u_strncpy_60
U u_versionToString_60
U ubrk_countAvailable_60
U ubrk_getAvailable_60
U ucal_countAvailable_60
U ucal_getAvailable_60
U ucnv_cbFromUWriteBytes_60
U ucnv_cbToUWriteUChars_60
U ucnv_close_60
U ucnv_countAliases_60
U ucnv_countAvailable_60
U ucnv_fromUnicode_60
U ucnv_getAlias_60
U ucnv_getAvailableName_60
U ucnv_getCanonicalName_60
U ucnv_getFromUCallBack_60
U ucnv_getInvalidChars_60
U ucnv_getInvalidUChars_60
U ucnv_getMaxCharSize_60
U ucnv_getMinCharSize_60
U ucnv_getStandardName_60
U ucnv_getSubstChars_60
U ucnv_getToUCallBack_60
U ucnv_getUnicodeSet_60
U ucnv_openStandardNames_60
U ucnv_open_60
U ucnv_resetFromUnicode_60
U ucnv_resetToUnicode_60
U ucnv_setFromUCallBack_60
U ucnv_setToUCallBack_60
U ucnv_toUnicode_60
U ucol_countAvailable_60
U ucol_getAvailable_60
U ucurr_getDefaultFractionDigits_60
U ucurr_getName_60
U ucurr_getNumericCode_60
U ucurr_isAvailable_60
U ucurr_openISOCurrencies_60
U udat_countAvailable_60
U udat_getAvailable_60
U udata_setCommonData_60
U udata_setFileAccess_60
U uloc_addLikelySubtags_60
U uloc_countAvailable_60
U uloc_getAvailable_60
U uloc_getParent_60
U ulocdata_getCLDRVersion_60
U uname
U unlink
U unsetenv
U unum_countAvailable_60
U unum_getAvailable_60
U ures_close_60
U ures_getByIndex_60
U ures_getByKey_60
U ures_getStringByIndex_60
U ures_getStringByKey_60
U ures_getString_60
U ures_getType_60
U ures_openDirect_60
U ures_open_60
U utext_close_60
U utext_openUChars_60
U waitpid
U write
U writev
U zError