面霸养成记;50万字2022最新Android11位大厂面试专题
Posted 初一十五啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面霸养成记;50万字2022最新Android11位大厂面试专题相关的知识,希望对你有一定的参考价值。
前言
面试专题前面的百度篇,腾讯篇,阿里篇,京东篇,bilibili篇,网易篇,字节篇七大板块已经更新完了,还剩下4个专题~持续更新中。
1.12W字;2022最新Android11位大厂面试专题(一)百度篇
2.12W字;2022最新Android11位大厂面试专题(二)阿里篇
3.12W字;2022最新Android11位大厂面试专题(三)腾讯篇
4.面霸养成记;50万字Android面试文档(四五)字节,京东篇
5.面霸养成记;50万字Android面试文档(六七)网易,Bilibili篇
一共50W字的文档,面试专题12W字只是一小部分,字数限制,分几篇更。
关注公众号:初一十五a
提前解锁 《整套50W字Android体系PDF》,让学习更贴近未来实战。
共十一模块,今天来更新第八丶九专题小米篇和小红书篇
八丶小米
1.handler机制
(第二章第3题)
2.一个线程中几个handler同时发送一个相同的消息,怎么分辨哪个消息是哪个handler发送的
(每个msg都有对应的target
,这个target
其实就是对应handler的引用。所以是通过msg.target
区分的 )
3.android服务的生命周期
服务生命周期具有以下回调
onCreate()
:
在首次创建服务以设置您可能需要的初始配置时执行。仅在服务尚未运行时才执行此方法。
onStartCommand()
:
每次执行startService()
都由另一个组件(例如Activity或BroadcastReceiver)调用。使用此方法时,服务将一直运行,直到您调用stopSelf()
或为止stopService()
。请注意,无论您调用多少次onStartCommand()
,方法stopSelf()
和都stopService()
必须仅被调用一次才能停止服务。
onBind()
:
在组件调用bindService()
并返回IBInder的实例时执行,以提供与Service的通信通道。bindService()
只要有绑定到它的客户端,对的调用将使服务保持运行。
onDestroy()
:
在不再使用该服务并允许处置已分配的资源时执行。
请务必注意,在服务的生命周期中可能会调用其他回调,例如onConfigurationChanged()andonLowMemory()
4.Android持久化存储的方式
内部存储、网络存储、SharedPreferences、SQLite、外部存储(SD卡)。
5.Android广播使用
动态注册广播:
在MainActivity
中:
public class MainActivity extends AppCompatActivity
private MyReceiver myReceiver;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn1 = findViewById(R.id.btn);
myReceiver = new MyReceiver();
registerReceiver(myReceiver,new IntentFilter("wk")); //IntentFilter的参数为广播接受的类型(自定义)
btn1.setOnClickListener((v)-> sendBroadcast(new Intent("wk"))); //Intent的参数为发送广播的类型(自定义)
class MyReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
Toast.makeText(context, "我是动态注册的广播", Toast.LENGTH_SHORT).show();
@Override
protected void onDestroy()
super.onDestroy();
unregisterReceiver(myReceiver); //Activity销毁时反注册,以免内存泄漏
点击按钮后在MainActivity
中发送广播,MyReceiver就能接受到广播Toast:
静态注册广播:
直接在包名按右键新建一个:
新建完要在Manifest定义这个广播接收什么类型:
<application
.....
<receiver
android:name=".MyReceiver2"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="wk"/> //定义广播接收的类型(自定义)
</intent-filter>
</receiver>
.....
</application>
发送广播时定义好发送的类型就能接收到广播了
6.自定义view哪个构造方法是不能不重写的
在setContentView
源码可以看到普通view的创建方法是createViewFromTag
。找到view = createView(context, name, null, attrs);
点进去看到根节点的view是通过反射获取的,然后获取根节点的构造方法clazz.getConstructor(mConstructorSignature) mConstructorSignature
是两个参数的数组。所以自定义View一定要重写两个参数的构造函数
/**
* Creates a view from a tag name using the supplied attribute set.
* <p>
* <strong>Note:</strong> Default visibility so the BridgeInflater can
* override it.
*
* @param parent the parent view, used to inflate layout params
* @param name the name of the XML tag used to define the view
* @param context the inflation context for the view, typically the
* @code parent or base layout inflater context
* @param attrs the attribute set for the XML tag used to define the view
* @param ignoreThemeAttr @code true to ignore the @code android:theme
* attribute (if set) for the view being inflated,
* @code false otherwise
*/
@UnsupportedAppUsage
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
boolean ignoreThemeAttr)
if (name.equals("view"))
name = attrs.getAttributeValue(null, "class");
// Apply a theme wrapper, if allowed and one is specified.
if (!ignoreThemeAttr)
final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
final int themeResId = ta.getResourceId(0, 0);
if (themeResId != 0)
context = new ContextThemeWrapper(context, themeResId);
ta.recycle();
try
View view = tryCreateView(parent, name, context, attrs);
if (view == null)
final Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = context;
try
if (-1 == name.indexOf('.'))
view = onCreateView(context, parent, name, attrs);
else
view = createView(context, name, null, attrs);
finally
mConstructorArgs[0] = lastContext;
return view;
catch (InflateException e)
throw e;
catch (ClassNotFoundException e)
final InflateException ie = new InflateException(
getParserStateDescription(context, attrs)
+ ": Error inflating class " + name, e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
catch (Exception e)
final InflateException ie = new InflateException(
getParserStateDescription(context, attrs)
+ ": Error inflating class " + name, e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
/**
* Low-level function for instantiating a view by name. This attempts to
* instantiate a view class of the given <var>name</var> found in this
* LayoutInflater's ClassLoader.
*
* <p>
* There are two things that can happen in an error case: either the
* exception describing the error will be thrown, or a null will be
* returned. You must deal with both possibilities -- the former will happen
* the first time createView() is called for a class of a particular name,
* the latter every time there-after for that class name.
*
* @param viewContext The context used as the context parameter of the View constructor
* @param name The full name of the class to be instantiated.
* @param attrs The XML attributes supplied for this instance.
*
* @return View The newly instantiated view, or null.
*/
@Nullable
public final View createView(@NonNull Context viewContext, @NonNull String name,
@Nullable String prefix, @Nullable AttributeSet attrs)
throws ClassNotFoundException, InflateException
Objects.requireNonNull(viewContext);
Objects.requireNonNull(name);
Constructor<? extends View> constructor = sConstructorMap.get(name);
if (constructor != null && !verifyClassLoader(constructor))
constructor = null;
sConstructorMap.remove(name);
Class<? extends View> clazz = null;
try
Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);
if (constructor == null)
// Class not found in the cache, see if it's real, and try to add it
clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
mContext.getClassLoader()).asSubclass(View.class);
if (mFilter != null && clazz != null)
boolean allowed = mFilter.onLoadClass(clazz);
if (!allowed)
failNotAllowed(name, prefix, viewContext, attrs);
constructor = clazz.getConstructor(mConstructorSignature);
constructor.setAccessible(true);
sConstructorMap.put(name, constructor);
else
// If we have a filter, apply it to cached constructor
if (mFilter != null)
// Have we seen this name before?
Boolean allowedState = mFilterMap.get(name);
if (allowedState == null)
// New class -- remember whether it is allowed
clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
mContext.getClassLoader()).asSubclass(View.class);
boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
mFilterMap.put(name, allowed);
if (!allowed)
failNotAllowed(name, prefix, viewContext, attrs);
else if (allowedState.equals(Boolean.FALSE))
failNotAllowed(name, prefix, viewContext, attrs);
Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = viewContext;
Object[] args = mConstructorArgs;
args[1] = attrs;
try
final View view = constructor.newInstance(args);
if (view instanceof ViewStub)
// Use the same context when inflating ViewStub later.
final ViewStub viewStub = (ViewStub) view;
viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
return view;
finally
mConstructorArgs[0] = lastContext;
catch (NoSuchMethodException e)
final InflateException ie = new InflateException(
getParserStateDescription(viewContext, attrs)
+ ": Error inflating class " + (prefix != null ? (prefix + name) : name), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
catch (ClassCastException e)
// If loaded class is not a View subclass
final InflateException ie = new InflateException(
getParserStateDescription(viewContext, attrs)
+ ": Class is not a View " + (prefix != null ? (prefix + name) : name), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
catch (ClassNotFoundException e)
// If loadClass fails, we should propagate the exception.
throw e;
catch (Exception e)
final InflateException ie = new InflateException(
getParserStateDescription(viewContext, attrs) + ": Error inflating class "
+ (clazz == null ? "<unknown>" : clazz.getName()), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
finally
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
7.java怎么使得一个同步方法变为异步方法
构造一个异步调用
1.使用wait和notify方法
2.使用条件锁
3.Future
4.使用CountDownLatch
5.使用CyclicBarrier
8.java 抽象类和接口的区别
1、声明方式不同。抽象类为abstract class
,接口类为interface
。
2、继承抽象类关键字为extends
,实现接口关键字为implements
。
3、继承抽象类仅支持单继承
,实现接口可以多实现
。
单继承:classB Extends classA
接口多实现:Interface implements Interface0, Interface1, interface2……
java中为什么要单继承,多实现?
若为多继承,那么当多个父类中有重复的属性或者方法时,子类的调用结果会含糊不清,因此用了单继承。
为什么可以多实现呢?
通过实现接口拓展了类的功能,若实现的多个接口中有重复的方法也没关系,因为实现类中必须重写接口中的方法,所以调用时还是调用的实现类中重写的方法。那么各个接口中重复的变量又是怎么回事呢?
4、抽象类可以有构造方法,接口中不能有构造方法。
5、抽象类可以有成员变量,接口类只能有常量(static)。
6、抽象类可以有成员方法,接口中只可以有抽象方法。
7、抽象类中增加方法可以影响子类,接口中增加方法通常影响子类(JDK1.8增加default方法不影响子类)
8、从JDK1.8开始允许接口中出现非抽象方法,但需要default关键字修饰
- 主要减少了代码牵一发而动全身的弊端.
9.抽象类的方法一定要继承吗
当父类的抽象类中有抽象方法时,继承的子类有两种选择,第一:定义子类是抽象类,就不需要实现抽象方法;第二:实现所有的抽象方法,不需要定义子类为抽象类;
当父类的抽象类中没有抽象方法时,子类直接继承不用做任何操作。
九丶小红书
1.Java深拷贝和浅拷贝的区别
关于深拷贝和浅拷贝区别
- 浅拷贝:浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
- 深拷贝 :深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。
2.自定义View是怎么绘制的?ViewGroup呢
(第一章第2题)
3.Handler机制
(第二章第3题)
4.TCP和UDP的区别
①连接
- TCP 是面向连接的传输层协议,传输数据前先要建立连接。
- UDP 是不需要连接,即刻传输数据。
②服务对象
- TCP 是一对一的两点服务,即一条连接只有两个端点。
- UDP 支持一对一、一对多、多对多的交互通信
③可靠性
- TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按需到达。
- UDP 是尽最大努力交付,不保证可靠交付数据。
④拥塞控制、流量控制
- TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。
- UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。
⑤首部开销
- TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是
20
个字节,如果使用了「选项」字段则会变长的。 - UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
⑥传输方式
- TCP 是流式传输,没有边界,但保证顺序和可靠。
- UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。
⑦分片不同
- TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
- UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。
TCP 和 UDP 应用场景:
由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:
FTP
文件传输;- HTTP / HTTPS;
由于 UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:
- 包总量较少的通信,如
DNS
、SNMP
等; - 视频、音频等多媒体通信;
- 广播通信;
关注公众号:初一十五a
提前解锁 《整套50W字Android体系PDF》,让学习更贴近未来实战。
以上是关于面霸养成记;50万字2022最新Android11位大厂面试专题的主要内容,如果未能解决你的问题,请参考以下文章
面霸养成记;50W字Android面试文档致敬2022摸爬滚打的一年