2024年安卓最全Android 10 适配及具体解决办法(3),2024年最新安卓开发高级面试题

Android核心知识点

面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验。

下面这份PDF是我翻阅了差不多3个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点,全部都是精华中的精华,我能面试到现在2-2资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。

不管是Android基础还是Java基础以及常见的数据结构,这些是无原则地必须要熟练掌握的,尤其是非计算机专业的同学,面试官一上来肯定是问你基础,要是基础表现不好很容易被扣上基础不扎实的帽子,常见的就那些,只要你平时认真思考过基本上面试是没太大问题的。

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上我搜集整理的2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节。

节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

String androidId = Settings.Secure.getString(
context.contentResolver,
Settings.Secure.ANDROID_ID
);

  1. 但是在实际应用中发现, 有Android Id获取失败的情况, 所以就完善了上面的方法

kotlin:

var deviceId = Settings.Secure.getString(
getAppContext().contentResolver,
Settings.Secure.ANDROID_ID
)
if (androidId.isNullOrEmpty()) {
deviceId = getUniquePsuedoID()
}

fun getUniquePsuedoID(): String {
val devIDShort =
“35” + Build.BOARD.length % 10 + Build.BRAND.length % 10 + Build.CPU_ABI.length % 10 + Build.DEVICE.length % 10 + Build.MANUFACTURER.length % 10 + Build.MODEL.length % 10 + Build.PRODUCT.length % 10

// API >= 9 的设备才有 android.os.Build.SERIAL
// http://developer.android.com/reference/android/os/Build.html#SERIAL
// 如果用户更新了系统或 root 了他们的设备,该 API 将会产生重复记录
var serial: String?
try {
serial = android.os.Build::class.java.getField(“SERIAL”).get(null).toString()
return UUID(
devIDShort.hashCode().toLong(),
serial.hashCode().toLong()
).toString()
} catch (exception: Exception) {
serial = “serial”
}
// 最后,组合上述值并生成 UUID 作为唯一 ID
return UUID(devIDShort.hashCode().toLong(), serial!!.hashCode().toLong()).toString()
}

java:

String deviceId = Settings.Secure.getString(
context.contentResolver,
Settings.Secure.ANDROID_ID
);
if(TextUtils.isEmpty(deviceId)) {
deviceId = getUniquePsuedoID()
}

public String getUniquePsuedoID() {
String devIDShort =
“35” + Build.BOARD.length % 10 + Build.BRAND.length % 10 + Build.CPU_ABI.length % 10 + Build.DEVICE.length % 10 + Build.MANUFACTURER.length % 10 + Build.MODEL.length % 10 + Build.PRODUCT.length % 10;

// API >= 9 的设备才有 android.os.Build.SERIAL
// http://developer.android.com/reference/android/os/Build.html#SERIAL
// 如果用户更新了系统或 root 了他们的设备,该 API 将会产生重复记录
String serial;
try {
serial = android.os.Build::class.java.getField(“SERIAL”).get(null).toString()
return UUID(
devIDShort.hashCode().toLong(),
serial.hashCode().toLong()
).toString();
} catch (Exception e) {
serial = “serial”;
}
// 最后,组合上述值并生成 UUID 作为唯一 ID
return UUID((long)devIDShort.hashCode(), (long)serial.hashCode()).toString();
}

限制Activity后台启动

说明: 此项行为变更适用于在 Android Q 上运行的所有应用,甚至包括以 Android 9(API 级别 28)或更低版本为目标平台的应用。此外,即使您的应用以 Android 9 或更低版本为目标平台并且最初安装在运行 Android 9 或更低版本的设备上,该行为变更仍会在设备升级到 Android Q 后生效。

解决方法:

发送全屏通知会自动启动Activity

kotlin:

fun sendNotification(
title: String?,
body: String?,
data: PushMessageNode?,
bitmap: Bitmap?
) {
val intent = Intent(this, PushJumpActivity::class.java)
intent.putExtra(WhatConstants.Intent.FIRE_PUSH_MESSAGE, data)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val pendingIntent = PendingIntent.getActivity(
this, requestCode, intent,
PendingIntent.FLAG_UPDATE_CURRENT
)

val notificationManager =
this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?

if (notificationManager != null) {
val notificationBuilder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val mNotificationChannel =
NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH
)

notificationManager.createNotificationChannel(mNotificationChannel)
}

notificationBuilder
.setSmallIcon(R.mipmap.logo)
.setLargeIcon(
bitmap ?: BitmapFactory.decodeResource(
context,
R.mipmap.logo
)
)
.setContentTitle(title)
.setContentText(body)
.setShowWhen(true)
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
//设置为全屏通知, 此时若App处于前台, 会为悬挂通知, 无论前台后台, 都会自动启动Acitivity
.setFullScreenIntent(pendingIntent, true)
.setContentIntent(pendingIntent)

notificationManager.notify(
requestCode /* ID of notification */,
notificationBuilder.build()
)

bitmap?.recycle()
}
}

java:

private void sendNotification(String title, String body, PushMessageNode data, Bitmap bitmap) {
Intent intent = new Intent(this, PushJumpActivity.class);
intent.putExtra(WhatConstants.Intent.INSTANCE.getFIRE_PUSH_MESSAGE(), data);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
int requestCode = (int) (Math.random() * 1000) + 1;
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode /* Request code */, intent,
PendingIntent.FLAG_UPDATE_CURRENT);

Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationManager notificationManager = null;
notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder notificationBuilder;
if (notificationManager != null) {
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel mNotificationChannel = new NotificationChannel(“1”, “Channel1”, NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(mNotificationChannel);
notificationBuilder = new Notification.Builder(this, “1”);
} else {
notificationBuilder = new Notification.Builder(this);
}

notificationBuilder = notificationBuilder
.setSmallIcon(R.mipmap.logo)
.setLargeIcon(bitmap != null ? bitmap : BitmapFactory.decodeResource(context.getResources(), R.mipmap.logo))
.setContentTitle(title)
.setContentText(body)
.setShowWhen(true)
.setPriority(Notification.PRIORITY_HIGH)
.setAutoCancel(true)
.setSound(defaultSoundUri)
//设置为全屏通知, 此时若App处于前台, 会为悬挂通知, 无论前台后台, 都会自动启动Acitivity
.setFullScreenIntent(pendingIntent, true);
.setContentIntent(pendingIntent);

notificationManager.notify(requestCode /* ID of notification */, notificationBuilder.build());

if (bitmap != null)
bitmap.recycle();
}
}

获取剪贴板数据

说明: 只有默认输入法(IME)或者是目前处于焦点的应用, 才能访问到剪贴板数据.

这也就是说应用已经不能在后台监听剪贴板数据了, 不过我对目前处于焦点的应用这句话不太了解 . 另外在适配过程中, 遇到了一个问题, 在Acitivity onCreate直接获取剪贴板数据是不能成功获取的, 而在按钮点击的时候是可以的:

class SimpleActivity: AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

//直接获取剪切板数据
getTextFromClip()
//剪贴板有数据也return “”

//点击按钮获取剪切板数据
view.setOnClickListener {
getClipboardData()
//返回剪贴板的正常数据
}

}

private fun getTextFromClip(): String {
val clipboardManager =
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?
if (null == clipboardManager || !clipboardManager.hasPrimaryClip()) {
return “”
}
val clipData = clipboardManager.primaryClip
if (null == clipData || clipData.itemCount < 1) {
return “”
}
val clipText = clipData.getItemAt(0)?.text ?: “”
return clipText.toString()
}
}

后面又对目前处于焦点的应用思考了一下, 应该就是视图加载到窗口上才能获取焦点, 后面经过适配, 在view.post()之后获取剪贴板数据,又参考了这篇文章[Android源码解析]view.post()到底干了啥, 了解到view.post()是在view dispatchAttachedToWindow后执行的, 然后写出方法如下:

kotlin:

/**

  • 获取剪贴板的内容
    */
    fun getClipBoardText(@Nullable activity: Activity?, f: (String) -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && activity != null) {
    getTextFromClipFroAndroidQ(activity, f)
    } else {
    f.invoke(getTextFromClip())
    }
    }

/**

  • AndroidQ 获取剪贴板的内容
    */
    @TargetApi(Build.VERSION_CODES.Q)
    private fun getTextFromClipFroAndroidQ(@NonNull activity: Activity, f: (String) -> Unit) {
    val runnable = Runnable {
    try {
    val clipboardManager =
    activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?
    if (null == clipboardManager || !clipboardManager.hasPrimaryClip()) {
    f.invoke(“”)
    return@Runnable
    }
    val clipData = clipboardManager.primaryClip
    if (null == clipData || clipData.itemCount < 1) {
    f.invoke(“”)
    return@Runnable
    }
    val clipText = clipData.getItemAt(0)?.text ?: “”
    f.invoke(clipText.toString())
    return@Runnable
    } catch (e: Exception) {
    f.invoke(“”)
    return@Runnable
    }
    }
    activity.registerActivityLifecycleCallbacks(object :Application.ActivityLifecycleCallbacks {
    override fun onActivityPaused(activity: Activity) {
    }

override fun onActivityStarted(activity: Activity) {
}

override fun onActivityDestroyed(activity: Activity) {
activity.window?.decorView?.removeCallbacks(runnable)
}

override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}

override fun onActivityStopped(activity: Activity) {
}

override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
}

override fun onActivityResumed(activity: Activity) {
}
})
activity.window?.decorView?.post(runnable) ?: f.invoke(“”)
}

private fun getTextFromClip(): String {
try {
//可以使用Application的Context
val clipboardManager =
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?
if (null == clipboardManager || !clipboardManager.hasPrimaryClip()) {
return “”
}
val clipData = clipboardManager.primaryClip
if (null == clipData || clipData.itemCount < 1) {
return “”
}
val item = clipData.getItemAt(0) ?: return “”
val clipText = item.text ?: “”
return if (TextUtils.isEmpty(clipText)) “” else clipText.toString()
} catch (e: Exception) {
return “”
}
}

总结

【Android 详细知识点思维脑图(技能树)】

我个人是做Android开发,已经有十来年了,目前在某创业公司任职CTO兼系统架构师。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

最后,赠与大家一句话,共勉!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

C-1715726076256)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

最后,赠与大家一句话,共勉!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 13
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2024前端面试题可能会涉及以下几个方面的内容: 1. HTML/CSS基础知识:括HTML标签的使用、CSS选择器、盒模型、浮动、定位等基本概念和常见问题。 2. JavaScript基础知识:括数据类型、变量、运算符、流程控制语句、函数、作用域、闭等基本概念和常见问题。 3. 前端框架和库:例如React、Vue等,可能会涉及到它们的基本原理、生命周期、组件通信等方面的问题。 4. 前端性能优化:括减少HTTP请求、压缩和合并文件、使用CDN加速、懒加载、缓存等方面的知识。 5. 前端工程化:括模块化开发、构建工具(如Webpack)、版本控制(如Git)、自动化测试等方面的知识。 6. 前端安全:括XSS攻击、CSRF攻击、点击劫持等常见安全问题及其防范措施。 7. 前端跨域问题:括同源策略、跨域请求的方法(如JSONP、CORS等)以及解决跨域问题的方案。 8. 移动端开发:括响应式设计、移动端适配、触摸事件、移动端性能优化等方面的知识。 9. Web标准和浏览器兼容性:括HTML5、CSS3的新特性以及不同浏览器之间的差异和兼容性问题。 10. 数据可视化:括使用图表库(如Echarts、D3.js)进行数据可视化的基本原理和常见问题。 以上只是一些可能涉及到的内容,具体面试题目还会根据面试官的要求和公司的需求而有所不同。在准备面试时,建议多做一些实际项目练习,加深对前端知识的理解和应用能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值