前语

面试专题前面的百度篇,腾讯篇,阿里篇,京东篇,bilibili篇,网易篇,字节篇,小红书,小米九大板块已经更新完了,还剩下2个专题~持续更新中。

1.12W字;2022最新Android11位大厂面试专题(一)百度篇

2.12W字;2022最新Android11位大厂面试专题(二)阿里篇

3.12W字;2022最新Android11位大厂面试专题(三)腾讯篇

4.面霸养成记;50万字Android面试文档(四五)字节,京东篇

5.面霸养成记;50万字Android面试文档(六七)网易,Bilibili篇

6.面霸养成记;50万字Android面试文档(八九)小红书,小米篇

一共50W字的文档,面试专题12W字仅仅一小部分,字数约束,分几篇更。

重视公众号:Android苦做舟

提前解锁 《整套50W字Android系统PDF》,让学习更靠近未来实战。

总共包括

1.腾讯Android开发笔记(33W字)

2.2022最新Android十一位大厂面试专题(12W字)

3.音视频经典面试题(6W字)

4.Jetpack全家桶

5.Android 功能监控框架Matrix

6.JVM

7.车载使用开发

共十一模块,今日来更新第八丶九专题小米篇和小红书篇

八丶小米

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:

静态注册播送:

直接在包名按右键新建一个:

面霸养成记;50万字2022最新Android11位大厂面试专题(六)

新建完要在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关键字修饰

  • 主要减少了代码牵一发而动全身的弊端.

面霸养成记;50万字2022最新Android11位大厂面试专题(六)

9.笼统类的办法一定要承继吗

当父类的笼统类中有笼统办法时,承继的子类有两种挑选,榜首:界说子类是笼统类,就不需求完成笼统办法;第二:完成所有的笼统办法,不需求界说子类为笼统类;

当父类的笼统类中没有笼统办法时,子类直接承继不用做任何操作。

九丶小红书

1.Java深仿制和浅仿制的差异

关于深仿制和浅仿制差异

  • 浅仿制:浅仿制会在堆上创建一个新的方针(差异于引证仿制的一点),不过,假如原方针内部的特点是引证类型的话,浅仿制会直接仿制内部方针的引证地址,也便是说仿制方针和原方针共用同一个内部方针。
  • 深仿制 :深仿制会完全仿制整个方针,包括这个方针所包含的内部方针。

2.自界说View是怎样绘制的?ViewGroup呢

(榜首章第2题)

3.Handler机制

(第二章第3题)

4.TCP和UDP的差异

①衔接

  • TCP 是面向衔接的传输层协议,传输数据前先要树立衔接。
  • UDP 是不需求衔接,即刻传输数据。

②服务方针

  • TCP 是1对1的两点服务,即一条衔接只要两个端点。
  • UDP 支撑1对1、一对多、多对多的交互通讯

③牢靠性

  • 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本身的处理既简单又高效,因而常常用于:

  • 包总量较少的通讯,如 DNSSNMP 等;
  • 视频、音频等多媒体通讯;
  • 播送通讯;

一共50W字的文档,面试专题12W字仅仅一小部分,字数约束,分几篇更。

重视公众号:Android苦做舟

提前解锁 《整套50W字Android系统PDF》,让学习更靠近未来实战。

总共包括

1.腾讯Android开发笔记(33W字)

2.2022最新Android十一位大厂面试专题(12W字)

3.音视频经典面试题(6W字)

4.Jetpack全家桶

5.Android 功能监控框架Matrix

6.JVM

7.车载使用开发