android進階面試題

1. HashMap為什么大小是2的冪次?

最重要的就是下邊的源碼,就是2的冪次:

    /**
     * Returns index for hash code h.
     */
    static int indexFor(int h, int length) {
        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
        return h & (length-1);
    }

原因就是:
為了數(shù)據(jù)更加分散,散列,方便存儲 和查詢,就是提高存儲和查詢的速度

2. Retrofit如何支持 RxJava,它底層原理是如何做到的?

因為 Retrofit 返回 Call,實現(xiàn)類是 OkHttpCall,把 Call -> 變?yōu)?Observable,是采用 adapter設計模式達到的,在Retrofit中 添加了 RxJava 支持: .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
如下代碼:

Retrofit retrofit = new Retrofit.Builder()
                // 訪問后臺接口的主路徑
                .baseUrl("http://ppw.zmzxd.cn/index.php/api/v1/")
                // 添加解析轉換工廠,Gson 解析,Xml解析,等等
                .addConverterFactory(GsonConverterFactory.create())
                // 添加 OkHttpClient,不添加默認就是 光桿 OkHttpClient
                .client(okHttpClient)
                // 支持RxJava Call -> Obsevrable 怎么做到的? 1 2  采用了 Adapter 設計模式
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
3. 為什么下邊不睡眠可以設置setText(),添加 睡眠1秒就拋出異常?看下面代碼:
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final TextView textview = (TextView) findViewById(R.id.textview);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                textview.setText("1111");

            }
        }).start();
    }
}

如上代碼:
如果不添加 睡眠,直接在線程中設置 setText("1111")不會報錯;
如果添加了 睡眠,然后設置 setText("1111")就會在 1秒 后報錯:Only the original thread that created a view hierarchy can touch its views.
這個錯意思是:不能在原始線程以外的任何線程去更新UI

前提知識:在ViewRootImpl中,首先調(diào)用 requestLayout(),然后在 requestLayout() 中調(diào)用 checkThread()方法,這個方法會判斷當前線程是否等于創(chuàng)建的線程,如果不等于,直接拋出異常;

原因如下:
1>:不添加睡眠:不報錯,是因為 onCreate()是在 MainActivity創(chuàng)建之后就會執(zhí)行,而 checkThread()是在 ViewRootImpl的 requestLayout()中執(zhí)行的,而布局的 繪制流程是在 onResume()之后開始的。所以說:在 onCreate()中 new Thread(new Runnable()).start() 更新UI是可以的,因為它不會調(diào)用 onResume(),不會去繪制布局,所以就不會調(diào)用 checkThread()方法,所以不會拋出異常;

2>:添加睡眠:但是當睡眠1秒之后,這個時候 onResume()已經(jīng)執(zhí)行完了,就開始繪制布局,如果你在去更新UI,就會調(diào)用 requestLayout(),就會調(diào)用checkThread()方法,所以就會拋出異常;

4. 什么是主線程(UI線程)、什么是子線程?

不能在子線程中更新UI,這個觀點不太對;
假設子線程可以更新UI,會出現(xiàn)錯亂的問題,因為會涉及到 同步問題,假設線程1和線程2同時去更新UI,無法確保到底更新成線程1的樣子還是線程2的樣子,加鎖?無法確定加鎖的位置。所以谷歌就只能允許一個線程去更新UI,就把這個線程叫做UI線程,也稱為主線程。

所以,谷歌這樣做如果直接在 子線程更新UI,就會報錯 Only the original thread that created a view hierarchy can touch its views.,不能在原始線程以外的任何線程去更新UI,而不是不能在子線程中更新UI。

5. toast在 new Thread中的問題:
new Thread(new Runnable() {
            @Override
            public void run() {
               
                Looper.prepare();
                Toast.makeText(MainActivity.this , "1111" , Toast.LENGTH_SHORT).show();
                Looper.loop();

            }
        }).start();

如果直接讓 toast 在 new Thread()中彈出,就會報錯,報這個錯:Can't create handler inside thread that has not called Looper.prepare()

如果添加了Looper.prepare()和 Looper.loop(),就可以彈出 toast,這個還是在子線程中 彈出的 toast;

在子線程可以彈出 toast,原因是:
子線程更新 Toast是加載在 WindowManager上邊,它不是Activity,所以就不會來到 ViewRootImpl中,所以就不會執(zhí)行 checkThread(),所以就不會拋出異常

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容