面试复习路线,梳理知识,提升储备
自己的知识准备得怎么样,这直接决定了你能否顺利通过一面和二面,所以在面试前来一个知识梳理,看需不需要提升自己的知识储备是很有必要的。
关于知识梳理,这里再分享一下我面试这段时间的复习路线:(以下体系的复习资料是我从各路大佬收集整理好的)
- 架构师筑基必备技能
- Android高级UI与FrameWork源码
- 360°全方面性能调优
- 解读开源框架设计思想
- NDK模块开发
- 微信小程序
- Hybrid 开发与Flutter
知识梳理完之后,就需要进行查漏补缺,所以针对这些知识点,我手头上也准备了不少的电子书和笔记,这些笔记将各个知识点进行了完美的总结:
《960全网最全Android开发笔记》
《379页Android开发面试宝典》
历时半年,我们整理了这份市面上最全面的安卓面试题解析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
如何使用它?
1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
} else {
buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
}
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
/**
-
分段加密
-
@param data 要加密的原始数据
-
@param privateKey 秘钥
*/
public static byte[] encryptByPrivateKeyForSpilt(byte[] data, byte[] privateKey) throws Exception {
int dataLen = data.length;
if (dataLen <= DEFAULT_BUFFERSIZE) {
return encryptByPrivateKey(data, privateKey);
}
List allBytes = new ArrayList(2048);
int bufIndex = 0;
int subDataLoop = 0;
byte[] buf = new byte[DEFAULT_BUFFERSIZE];
for (int i = 0; i < dataLen; i++) {
buf[bufIndex] = data[i];
if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
subDataLoop++;
if (subDataLoop != 1) {
for (byte b : DEFAULT_SPLIT) {
allBytes.add(b);
}
}
byte[] encryptBytes = encryptByPrivateKey(buf, privateKey);
for (byte b : encryptBytes) {
allBytes.add(b);
}
bufIndex = 0;
if (i == dataLen - 1) {
buf = null;
} else {
buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
}
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
/**
-
公钥分段解密
-
@param encrypted 待解密数据
-
@param publicKey 密钥
*/
public static byte[] decryptByPublicKeyForSpilt(byte[] encrypted, byte[] publicKey) throws Exception {
int splitLen = DEFAULT_SPLIT.length;
if (splitLen <= 0) {
return decryptByPublicKey(encrypted, publicKey);
}
int dataLen = encrypted.length;
List allBytes = new ArrayList(1024);
int latestStartIndex = 0;
for (int i = 0; i < dataLen; i++) {
byte bt = encrypted[i];
boolean isMatchSplit = false;
if (i == dataLen - 1) {
// 到data的最后了
byte[] part = new byte[dataLen - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPublicKey(part, publicKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
} else if (bt == DEFAULT_SPLIT[0]) {
// 这个是以split[0]开头
if (splitLen > 1) {
if (i + splitLen < dataLen) {
// 没有超出data的范围
for (int j = 1; j < splitLen; j++) {
if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
break;
}
if (j == splitLen - 1) {
// 验证到split的最后一位,都没有break,则表明已经确认是split段
isMatchSplit = true;
}
}
}
} else {
// split只有一位,则已经匹配了
isMatchSplit = true;
}
}
if (isMatchSplit) {
byte[] part = new byte[i - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPublicKey(part, publicKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
/**
- 使用私钥分段解密
*/
public static byte[] decryptByPrivateKeyForSpilt(byte[] encrypted) throws Exception {
int splitLen = DEFAULT_SPLIT.length;
if (splitLen <= 0) {
return decryptByPrivateKey(encrypted);
}
int dataLen = encrypted.length;
List allBytes = new ArrayList(1024);
int latestStartIndex = 0;
for (int i = 0; i < dataLen; i++) {
byte bt = encrypted[i];
boolean isMatchSplit = false;
if (i == dataLen - 1) {
// 到data的最后了
byte[] part = new byte[dataLen - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPrivateKey(part);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
} else if (bt == DEFAULT_SPLIT[0]) {
// 这个是以split[0]开头
if (splitLen > 1) {
if (i + splitLen < dataLen) {
// 没有超出data的范围
for (int j = 1; j < splitLen; j++) {
if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
break;
}
if (j == splitLen - 1) {
// 验证到split的最后一位,都没有break,则表明已经确认是split段
isMatchSplit = true;
}
}
}
} else {
// split只有一位,则已经匹配了
isMatchSplit = true;
}
}
if (isMatchSplit) {
byte[] part = new byte[i - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPrivateKey(part);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
/**
- 通过字符串生成私钥,转换服务器传递过来的私钥
*/
public static PrivateKey getPrivateKey(String privateKeyData) {
PrivateKey privateKey = null;
try {
byte[] decodeKey = Base64Decoder.decodeToBytes(privateKeyData);
PKCS8EncodedKeySpec x509 = new PKCS8EncodedKeySpec(decodeKey);//创建x509证书封装类
KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);//指定RSA
privateKey = keyFactory.generatePrivate(x509);//生成私钥
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return privateKey;
}
/**
- 通过字符串生成公钥,转换服务器传递过来的公钥
*/
public static PublicKey getPublicKey(String publicKeyData) {
PublicKey publicKey = null;
try {
byte[] decodeKey = Base64Decoder.decodeToBytes(publicKeyData);
X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodeKey);
KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);
publicKey = keyFactory.generatePublic(x509);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return publicKey;
}
/**
-
判断是否创建过秘钥
-
@return
-
@throws KeyStoreException
-
@throws CertificateException
-
@throws NoSuchAlgorithmException
-
@throws IOException
-
@throws UnrecoverableEntryException
*/
public static boolean isHaveKeyStore() {
try {
KeyStore ks = KeyStore.getInstance(“AndroidKeyStore”);
ks.load(null);
if (mAlias == null) {
setAlias(SAMPLE_ALIAS);
}
//从Android加载密钥对密钥存储库中
KeyStore.Entry entry = ks.getEntry(mAlias, null);
if (entry == null) {
return false;
}
} catch (KeyStoreException e) {
e.printStackTrace();
return false;
} catch (CertificateException e) {
e.printStackTrace();
return false;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (UnrecoverableEntryException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
-
获得本地AndroidKeyStore中的公钥
-
@return
*/
public static PublicKey getLocalPublicKey() {
try {
KeyStore ks = KeyStore.getInstance(“AndroidKeyStore”);
ks.load(null);
if (mAlias == null) {
setAlias(SAMPLE_ALIAS);
}
//从Android加载密钥对密钥存储库中
KeyStore.Entry entry = ks.getEntry(mAlias, null);
if (entry == null) {
return null;
}
if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
return null;
}
PublicKey publicKey = ((KeyStore.PrivateKeyEntry) entry).getCertificate().getPublicKey();
return publicKey;
} catch (KeyStoreException e) {
e.printStackTrace();
return null;
} catch (CertificateException e) {
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (UnrecoverableEntryException e) {
e.printStackTrace();
return null;
}
}
}
package tsou.com.encryption.androidkeystoresign;
public class SecurityConstants {
public static final String KEYSTORE_PROVIDER_ANDROID_KEYSTORE = “AndroidKeyStore”;
public static final String TYPE_RSA = “RSA”;
public static final String TYPE_DSA = “DSA”;
public static final String TYPE_BKS = “BKS”;
public static final String SIGNATURE_SHA256withRSA = “SHA256withRSA”;
public static final String SIGNATURE_SHA512withRSA = “SHA512withRSA”;
}
- 加密封装在SPSecuredUtils秘钥中方便拿过来直接用
package tsou.com.encryption.sp;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
import tsou.com.encryption.AndroidKeyStoreRSA.AndroidKeyStoreRSAUtils;
import tsou.com.encryption.aescbc.Base64Decoder;
import tsou.com.encryption.aescbc.Base64Encoder;
/**
- Created by zb666 on 2017/2/9.
*/
public class SPSecuredUtils {
/**
- 保存在手机里面的文件名
*/
public static final String FILE_NAME = “sp_secured”;
private static SharedPreferences mSharedPreferences;
/**
-
保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
-
@param context
-
@param key
-
@param object
-
@param publicKey
*/
public static void put(Context context, String key, Object object, RSAPublicKey publicKey) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
// byte[] encryptBytes = AndroidKeyStoreRSAUtils.encryptByPublicKeyForSpilt(encryptionString.getBytes(),
// publicKey.getEncoded());
try {
if (object instanceof String) {
byte[] encryptBytes = AndroidKeyStoreRSAUtils.encryptByPublicKey(((String) object).getBytes(),
publicKey.getEncoded());
editor.putString(key, Base64Encoder.encode(encryptBytes));
} else if (object instanceof Integer) {
put(context, key, Integer.toString((Integer) object), publicKey);
} else if (object instanceof Boolean) {
put(context, key, Boolean.toString((Boolean) object), publicKey);
} else if (object instanceof Float) {
put(context, key, Float.toString((Float) object), publicKey);
} else if (object instanceof Long) {
put(context, key, Long.toString((Long) object), publicKey);
} else {
put(context, key, object.toString(), publicKey);
}
SharedPreferencesCompat.apply(editor);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
-
得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
-
@param context
-
@param key
-
@param defaultObject
-
@return
*/
public static Object get(Context context, String key, Object defaultObject) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
// byte[] decryptBytes = AndroidKeyStoreRSAUtils.decryptByPrivateKeyForSpilt(
// Base64Decoder.decodeToBytes(decodeString));
try {
if (defaultObject instanceof String) {
String string = sp.getString(key, (String) defaultObject);
if (!string.equals((String) defaultObject)) {
byte[] decryptBytes = AndroidKeyStoreRSAUtils.decryptByPrivateKey(
Base64Decoder.decodeToBytes(string));
return new String(decryptBytes);
}
return (String) defaultObject;
} else if (defaultObject instanceof Integer) {
String string = sp.getString(key, Integer.toString((Integer) defaultObject));
if (!string.equals(Integer.toString((Integer) defaultObject))) {
byte[] decryptBytes = AndroidKeyStoreRSAUtils.decryptByPrivateKey(
Base64Decoder.decodeToBytes(string));
return Integer.valueOf(new String(decryptBytes));
}
return (Integer) defaultObject;
} else if (defaultObject instanceof Boolean) {
String string = sp.getString(key, Boolean.toString((Boolean) defaultObject));
if (!string.equals(Boolean.toString((Boolean) defaultObject))) {
byte[] decryptBytes = AndroidKeyStoreRSAUtils.decryptByPrivateKey(
Base64Decoder.decodeToBytes(string));
return Boolean.valueOf(new String(decryptBytes));
}
return (Boolean) defaultObject;
} else if (defaultObject instanceof Float) {
String string = sp.getString(key, Float.toString((Float) defaultObject));
if (!string.equals(Float.toString((Float) defaultObject))) {
byte[] decryptBytes = AndroidKeyStoreRSAUtils.decryptByPrivateKey(
Base64Decoder.decodeToBytes(string));
return Float.valueOf(new String(decryptBytes));
}
return (Float) defaultObject;
} else if (defaultObject instanceof Long) {
String string = sp.getString(key, Long.toString((Long) defaultObject));
if (!string.equals(Long.toString((Long) defaultObject))) {
byte[] decryptBytes = AndroidKeyStoreRSAUtils.decryptByPrivateKey(
Base64Decoder.decodeToBytes(string));
return Long.valueOf(new String(decryptBytes));
}
return (Long) defaultObject;
}else if (defaultObject instanceof Double){
String string = sp.getString(key, Double.toString((Double) defaultObject));
if (!string.equals(Double.toString((Double) defaultObject))) {
byte[] decryptBytes = AndroidKeyStoreRSAUtils.decryptByPrivateKey(
Base64Decoder.decodeToBytes(string));
return Double.valueOf(new String(decryptBytes));
}
return (Double) defaultObject;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
-
将对象储存到sharepreference
-
@param key
-
@param device
-
@param
*/
public static boolean saveDeviceData(Context context, String key, T device, RSAPublicKey publicKey) {
if (mSharedPreferences == null) {
mSharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try { //Device为自定义类
// 创建对象输出流,并封装字节流
ObjectOutputStream oos = new ObjectOutputStream(baos);
// 将对象写入字节流
oos.writeObject(device);
// 将字节流编码成base64的字符串
String oAuth_Base64 = new String(Base64.encode
(baos.toByteArray(), Base64.DEFAULT));
byte[] encryptBytes = AndroidKeyStoreRSAUtils.encryptByPublicKey(oAuth_Base64.getBytes(),
publicKey.getEncoded());
mSharedPreferences.edit().putString(key, Base64Encoder.encode(encryptBytes)).apply();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
-
将对象从shareprerence中取出来
-
@param key
-
@param
-
@return
*/
public static T getDeviceData(Context context, String key) {
if (mSharedPreferences == null) {
mSharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
}
try {
T device = null;
String productBase64 = mSharedPreferences.getString(key, null);
if (productBase64 == null) {
return null;
}
byte[] decryptBytes = AndroidKeyStoreRSAUtils.decryptByPrivateKey(
Base64Decoder.decodeToBytes(productBase64));
// 读取字节
byte[] base64 = Base64.decode(new String(decryptBytes).getBytes(), Base64.DEFAULT);
// 封装到字节流
ByteArrayInputStream bais = new ByteArrayInputStream(base64);
// 再次封装
ObjectInputStream bis = new ObjectInputStream(bais);
// 读取对象
device = (T) bis.readObject();
return device;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
-
移除某个key值已经对应的值
-
@param context
-
@param key
*/
public static void remove(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}
/**
-
清除所有数据
-
@param context
*/
public static void clear(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
-
查询某个key是否已经存在
-
@param context
-
@param key
-
@return
*/
public static boolean contains(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
-
返回所有的键值对
-
@param context
-
@return
*/
public static Map<String, ?> getAll(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.getAll();
}
/**
-
创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
-
@author zhy
*/
private static class SharedPreferencesCompat {
private static final Method sApplyMethod = findApplyMethod();
/**
-
反射查找apply的方法
-
@return
*/
@SuppressWarnings({“unchecked”, “rawtypes”})
private static Method findApplyMethod() {
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
-
查询某个key是否已经存在
-
@param context
-
@param key
-
@return
*/
public static boolean contains(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
-
返回所有的键值对
-
@param context
-
@return
*/
public static Map<String, ?> getAll(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.getAll();
}
/**
-
创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
-
@author zhy
*/
private static class SharedPreferencesCompat {
private static final Method sApplyMethod = findApplyMethod();
/**
-
反射查找apply的方法
-
@return
*/
@SuppressWarnings({“unchecked”, “rawtypes”})
private static Method findApplyMethod() {
[外链图片转存中…(img-CbWvrD1O-1715758932356)]
[外链图片转存中…(img-st2gb6V6-1715758932356)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!