iQiyiとDidiDacheのAndroidクライアントとのインタビューの経験を覚えています。インタビュアーからのこれらの質問は私に批判を感じさせました!

「それは十分に不快です!短い本に書いて共有してほしいですか?聞いて、すぐに聞いてください、それは私の悲痛な声です」

以上が私と元同僚・友人の会話です。今年のゴールデン9thシルバー10thでこのインタビューと募集の好機を大いに期待しましたが、当初は思いがけない出来事に遭遇することは予想していませんでした。好きな2つの会社(DidiとiQiyiにインタビューしたことはありません。インタビューのプロセスは、最も悲しいインタビュー体験と見なすことができます。彼は私にインタビューの友人にインタビューされたときに注意を避けるためにピットを共有することによって顔を作るように頼みました、彼の言葉を聞いて、私は少し仕上げることによって表面失敗を置きましたそしてこの記事を編集した段落の美しい言語インタビューに参加した友達が、私が歩いていた穴を完全に回避できることを願っています。

IQiyiAndroidクライアントの顔の分析

1.Java言語の特徴とOOPのアイデアについて話します

これは、オブジェクト指向とプロセス指向の比較などの比較によって説明されます。これら2つのアイデアの比較のために、プレーヤーの実装などの開発の例を示すこともできます。プロセス指向の実装は、ビデオ機能を再生することです。複数のプロセスに分解します。

たとえば、ビデオアドレスをロードし、ビデオ情報を取得し、デコーダーを初期化し、デコードに適切なデコーダーを選択し、ビデオ形式の変換とオーディオのリサンプリングのためにデコードされたフレームを読み取り、再生のためにフレームを読み取ります。これは完全なプロセスです。 、このプロセスにはクラスの概念は含まれていません。オブジェクト指向の最大の機能はクラスであり、カプセル化の継承と多態性がコアです。

同様に、プレーヤーを例にとると、オブジェクト指向のアプローチでは、Muxer、ビデオ情報の取得、デコーダー、デコード、フォーマットコンバーター、ビデオプレーヤー、オーディオプレーヤーなどの各機能のオブジェクトがカプセル化 されます。デバイスなど、各機能はオブジェクトに対応し、オブジェクトは対応する機能によって達成され、単一の責任の原則に従い、オブジェクトのみに関連します

2.アクティビティ、ウィンドウ、ビューの違い、およびフラグメントの特性は何ですか?

アクティビティ、ウィンドウ、およびビューがインターフェイスを一緒に表示する方法。

-テストサイト:表示されたプロセス(ビュー描画プロセス)のソースコードに精通していること。
アクティビティウィンドウグリルをカットする人(制御)、
ウィンドウウィンドウ(モデルが搭載されている)、
ウィンドウグリルを表示する(表示するビュー)、
LayoutInflaterはさみ---レイアウト(図面)をウィンドウグリルにカットします。

フラグメントの特徴:フラグメントの設計は、主に、ロジックを含むアクティビティインターフェイスを多くの独立したモジュールに分割することです。これにより、モジュールの再利用と、多様なインターフェイスを提示するためのより柔軟なアセンブリが容易になります。
1)フラグメントはアクティビティインターフェイスの一部として使用できます
。2)複数のフラグメントを1つのアクティビティに表示でき、1つのフラグメントを複数のアクティビティで使用できます
。3)アクティビティの実行中に、動的に追加、削除、および置換できます。断片。
4)フラグメントには独自のライフサイクルがあり、入力イベントに応答できます。

3.低バージョンSDKで高バージョンapiを実装する方法は?

2つの状況:
1)一般に、上位バージョンの多くの新しいAPIは、互換性パッケージに代替実装を見つけます。フラグメントなど。通知、v4互換性パッケージにはNotificationCompatクラスがあります。5.0以降に表示されるbackgroundTintとminSdkが5.0未満の場合、検出エラーが含まれます。v4互換性パッケージDrawableCompatクラス。
2)代替実装なしの手動実装。例:コントロールの水の波及効果-サードパーティの実装。または、この効果を下位バージョンで直接削除します。
3)補足:minSDKが設定されているが、コードでより高いバージョンのAPIが使用されている場合、検出エラーが発生します。コードで@SuppressLintや@TargetApiアノテーションなどの宣言的なコンパイル検出戦略を使用して、コンパイラにルールのコンパイルを促す必要があります。@SuppressLintは検出を無視します; @ TargetApi = 23は、関数で使用されているAPIに従ってSDKのバージョンと厳密に一致し、対応するコンパイルエラープロンプトを表示します。
4)ロケーションエラーを回避するために、廃止されたAPIを使用しないことをお勧めします。(通常の状況では、互換性の問題は発生しません。このAPIメソッドは、後でいつでも削除される可能性があります。パフォーマンスの問題です。)

4.描画プロセスを表示しますか?

ビュー描画の主なプロセスは、測定、レイアウト、描画の3つの段階に分かれています。

メジャー:親ビューから渡されたMeasureSpecに従ってサイズを計算します。
レイアウト:子ビューを測定して得られたレイアウトサイズとレイアウトパラメータに従って、子ビューを適切な位置に配置します。
draw:画面にViewオブジェクトを描画します。

5.ハンドラーのソースコードの観点から、ハンドラーはどのように実行されますか?

これらはかなりたくさんあります。それではまず栗を見てみましょう

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_http).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                text();
            }
        });

    }

    private void text() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                Handler handler1 = new Handler() {//为了说明问题的写法
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        Log.e(TAG, "handle1: " + msg.what + "-thread1-" + Thread.currentThread().getName());
                    }
                };
                Message msg = new Message();
                msg.what = 2;
                handler1.sendMessage(msg);
                handler2.obtainMessage(1).sendToTarget();
                handler2.obtainMessage(4).sendToTarget();
                Looper.loop();
                Log.e(TAG, "loop 执行完毕");
                handler2.obtainMessage(3).sendToTarget();
            }
        }).start();
    }

    Handler handler2 = new Handler() {//普通写法
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.e(TAG, "handle2: " + msg.what + "-thread2-" + Thread.currentThread().getName());
        }
    };
}

6. OOMを回避する方法は?

  • 1.より軽いデータ構造を使用します。たとえば、HashMapの代わりにArrayMap / SparseArrayを使用すると、マッピング操作を記録するために追加のインスタンスオブジェクトが必要になるため、HashMapはより多くのメモリを消費します。SparseArrayは、キー値の自動ボックス化を回避するため、より効率的です。そして、梱包後の開梱作業。

  • 2.便利な列挙の使用は、静的定数または注釈@IntDefに置き換えることができます。

  • 3.ビットマップの最適化:a。サイズ圧縮:InSampleSizeを介して適切なスケーリングを設定しますb。色品質:適切なフォーマットを設定します、ARGB_6666 / RBG_545 / ARGB_4444 / ALPHA_6、大きな違いがありますc.inBitmap:inBitmapプロパティを使用してビットマップデコーダーに通知します既存のメモリ領域を使用してみてください。新しくデコードされたビットマップは、ビットマップを格納する領域を再申請するようにメモリに要求する代わりに、ヒープ内の前のビットマップが占めていたピクセルデータメモリ領域を使用しようとします。この機能を使用すると、数千枚の写真でも画面に表示できる写真の数のメモリサイズを占有するだけで済みますが、再利用にはいくつかの制限があります。これは特に反映されています。Android4.4より前では、同じサイズしか再利用できません。後のビットマップが前のビットマップよりも小さい限り、ビットマップ、Android4.4以降のバージョンのメモリ。inBitmapパラメータを使用する前に、作成された各Bitmapオブジェクトは、使用するためにメモリのブロックを割り当てます。inBitmapパラメータを使用した後、複数のビットマップがメモリのブロックを再利用できるため、パフォーマンスが向上します。

  • 4. Stringの代わりにStringBuilder:場合によっては、コードで多くの文字列スプライシング操作を使用する必要があります。この場合、頻繁な「+」の代わりにStringBuilderを使用することを検討する必要があります。

  • 5. onDrawのようなメソッドでオブジェクトを作成することは避けてください。オブジェクトはすぐに大量のメモリを消費し、GCが頻繁に発生し、メモリジッタが発生する可能性があります。

  • 6.メモリリークを減らすこともOOMを回避する方法です

7.メモリリークのシナリオと解決策は何ですか?

  • 1.非静的内部クラスの静的インスタンス。非静的内部クラスは外部クラスへの参照を保持します。非静的内部クラスのインスタンスが静的である場合、外部クラスの参照を長期間維持し、組織はシステムによってリサイクルされます。解決策静的内部クラスを使用しています

  • 2.マルチスレッド関連の匿名内部クラスと非静的内部クラス匿名内部クラスも外部クラスへの参照を保持します。時間のかかる操作がスレッドで実行されると、メモリリークが発生し、外部クラスが消費されるまでリサイクルできなくなる可能性があります。タスクが終了したときの解決策は、ページが終了したときにスレッド内のタスクを終了することです。

  • 3.ハンドラーのメモリリークハンドラーによるメモリリークは、非静的内部クラスによるものとして要約することもできます。ハンドラーの内部メッセージはMessageQueueに保存されます。一部のメッセージはすぐに処理できず、長期間存在するため、ハンドラーは処理できません。ハンドラーが非静的である場合、リサイクルされるため、外部クラスをリサイクルできなくなります。解決策は1です。静的ハンドラーを使用し、弱い参照を使用して外部クラス参照を処理します。2。ページを終了するときにメッセージキューからメッセージを削除します。

  • 4.コンテキストによりメモリリークが発生します。2つのライフサイクルが異なるため、シーンに応じてアクティビティのコンテキストとアプリケーションのコンテキストのどちらを使用するかを決定します。アクティビティのコンテキストを使用する必要がないシーン(ダイアログ)の場合は、アプリケーションコンテキストが使用されます。シングルトンモードが最も一般的です。このリークが発生するシナリオ。たとえば、アクティビティで渡されたコンテキストが静的クラスによって参照されているため、リサイクルに失敗します。

  • 5.静的ビューはリークの原因になります。静的ビューを使用すると、アクティビティが開始されるたびにビューの読み取りとレンダリングを回避できますが、静的ビュー
    はアクティビティの参照を保持し、再利用できません。解決策は、静的ビューをアクティビティが破棄されたときに設定することです。 null(ビューがインターフェイスに読み込まれると、Contextオブジェクトへの参照が保持されます。この例では、コンテキストオブジェクトはアクティビティです。このビューを参照する静的変数を宣言すると、アクティビティも参照されます)

  • 6. WebViewによるメモリリークWebViewを一度使用するとメモリが解放されないため、WebViewにメモリリークの問題が発生します。通常の解決策は、WebViewのプロセスを開き、AIDLを使用して通信することです。リリースする時間

  • 7.カーソル、ファイルなどのリソースオブジェクトが閉じられていない場合、バッファが内部で使用されることが多く、メモリリークが発生します。必ず閉じて、参照をnullに設定してください。

  • 8.コレクション内のオブジェクトはクリーンアップされません。コレクションはオブジェクトを保存するために使用されます。コレクションがどんどん大きくなると、特に共有のセットが静的である場合、適切なクリーニングは行われません。

  • 9.ビットマップはメモリリークを引き起こしますビットマップはより多くのメモリを消費するため、大きなビットマップオブジェクトを保持する静的変数を回避するために、使用していないときは時間内にクリーンアップする必要があります

  • 10.リスナーは閉じられていません。登録と登録解除が必要な多くのシステムサービスは、適切なタイミングで登録解除する必要があり、手動で追加したリスナーも時間内に削除する必要があります。

ディディタクシーAndroidクライアントの分析

1.アクティビティのライフサイクルはどうですか?

典型的な状況での包括的なライフサイクル分析

異常条件下でのライフサイクル分析

2.プロセスを存続させる方法は?

  • a:サービスはSTART_STICKY kill(約5秒待機)に設定された後に再起動され、インテントを再送信し、再起動前と同じ状態を維持します

  • b:startForegroundを介してプロセスをフォアグラウンドプロセスとして設定し、フォアグラウンドサービスを実行します。優先度はフォアグラウンドアプリケーションと同じレベルです。ただし、システムメモリが非常に不足していない限り、プロセスは強制終了されません。

  • c:2プロセスサービス:2つのプロセスが相互に保護するようにします。一方のサービスがクリーンアップされた後、クリーンアップされていないもう一方のプロセスはプロセスをすぐに再開できます。

  • d:Cを使用してデーモンプロセス(つまり、子プロセス)を記述します。Androidシステムの現在のプロセス(プロセス)の子プロセスフォークは、システムによって2つの異なるプロセスと見なされます。親プロセスが強制終了されても、子プロセスは存続でき、影響を受けません(Android 5.0以降は実行できません)。製造元に連絡して、ホワイトリストに追加してください。

  • e。画面がロックされたら、1ピクセルのアクティビティを開始します

3.コールドスタートとホットスタートとは何ですか?違い?シナリオを最適化して使用する方法は?

アプリのコールドスタート:アプリケーションの起動時に、バックグラウンドでアプリケーションのプロセスがない場合、システムは新しいプロセスを再作成してアプリケーションに割り当てます。この起動方法はコールドスタートと呼ばれます(アプリケーションプロセスはバックグラウンドに存在しません)。

システムは割り当てられた新しいプロセスを再作成するため、コールドスタートします。そのため、最初にApplicationクラスを作成して初期化し、次にMainActivityクラス(一連の測定、レイアウト、描画を含む)を作成して初期化し、最後にインターフェイスに表示します。

アプリのホットスタート:アプリケーションを開いた後、リターンキー、ホームキー、その他のキーを押すと、デスクトップまたはその他のプログラムに戻り、アプリを再度開くと、このメソッドはホットスタートと呼ばれます(アプリケーションはすでにバックグラウンドに存在します)。処理する)。

ホットスタートは既存のプロセスから開始されるため、ホットスタートはアプリケーションステップを実行せず、直接MainActivity(一連の測定、レイアウト、および描画を含む)に移動するため、ホットスタートプロセスは作成するだけで済みます。アプリの開始アイコンをクリックしたときにアプリケーションのコールドスタートプロセスを作成して初期化するのではなく、MainActivityを初期化するだけです。

Androidシステムは、Zygoteプロセスから分岐して新しいプロセスを作成し、それをアプリケーションに割り当てます。その後、Applicationクラスを作成して初期化し、MainActivityクラスを作成し、テーマスタイルでwindowBackgroundをロードし、プロパティをMainActivityに設定して、アクティビティレベルを構成します。一部の属性、レイアウトの拡張、およびonCreate / onStart / onResumeメソッドがすべて終了すると、contentViewの測定/レイアウト/描画が最終的にインターフェイスに表示されます

コールドスタートのライフサイクルの簡単なプロセス: アプリケーション構築メソッド-> attachBaseContext()-> onCreate->アクティビティ構築メソッド-> onCreate()->本体でバックグラウンドおよびその他の操作を構成する-> onStart()-> onResume()->測定、レイアウト、図面表示

コールドスタートの最適化は、主に視覚的な最適化であり、ホワイトスクリーンの問題を解決し、ユーザーエクスペリエンスを向上させるため、上記のコールドスタートプロセスを実行します。実行できる最適化は次のとおりです。

  • 1. onCreate()メソッドの作業負荷を軽減します
  • 2.アプリケーションを事業運営に参加させないでください
  • 3.アプリケーションで時間のかかる操作を実行しないでください
  • 4.アプリケーションに静的変数としてデータを保存しないでください
  • 5.レイアウトの複雑さとレベルを減らします
  • 6.メインスレッドの消費時間を削減します

4. ANRの理由は?

  • 1.時間のかかるネットワークアクセス
  • 2.大量のデータの読み取りと書き込み
  • 3.データベース操作
  • 4.ハードウェア操作(カメラなど)
  • 5.スレッドのjoin()メソッド、sleep()メソッド、wait()メソッドを呼び出すとき、またはスレッドロックを待機するとき
  • 6.サービスバインダーの数が上限に達する
  • 7. WatchDogANRはシステムサーバーで発生します
  • 8.サービスがビジーで、タイムアウト後に応答がない
  • 9.他のスレッドがロックを保持し、メインスレッドがタイムアウトを待機するようにします
  • 10.他のスレッドの終了またはクラッシュにより、メインスレッドが待機します

5.LruCacheの基本的な実装原則について教えてください。

LruCacheでのLruアルゴリズムの実装は、LinkedHashMapを介して実現されます。

LinkedHashMapはHashMapを継承し、二重リンクリストを使用してエントリシーケンスの関係をマップに格納します。get、put、removeなどの操作の場合、LinkedHashMapはHashMapの機能を実行するだけでなく、エントリシーケンスリストも調整します。LruCacheでは、LRUキャッシングを実現するためにLinkedHashMapの順序がLRUの順序に設定されます。getが呼び出されるたびに(つまり、画像がメモリキャッシュから取得されるたびに)、オブジェクトはリンクリストの最後に移動します。

新しいオブジェクトを挿入するためのputの呼び出しもリンクリストの最後に保存されるため、メモリキャッシュが設定された最大値に達すると、リンクリストの先頭にあるオブジェクト(近い将来最も使用されない)が削除されます。

6.ビューツリーの描画プロセスについて教えてください。

アクティビティがフォーカスを受け取ると、レイアウトの描画が要求されます。要求はAndroidフレームワークによって処理されます。描画はルートノードから開始され、レイアウトツリーを測定して描画します。

ビューツリー全体の描画プロセスは、ViewRoot.javaクラスのperformTraversals()関数で展開されます。この関数によって実行される作業は、ビューサイズ(メジャー)を再計算する必要があるかどうか、ビューの場所を再配置する必要があるかどうか(レイアウト)、および再描画するか(描画)

ショートブックの長さには限りがあるため、一部のみを共有しています。インタビュー、回答分析、Androidインタビューレビュー資料のフルバージョンは、私が(HDバージョン)PDFにまとめました。PDFには多くの知識と詳細が含まれているため、実際には予想よりも多くの時間と労力を要しました。

 

 

 

総括する

実際、Androidプログラマーにとっては、知識の内容やコアテクノロジーが多すぎて学ぶことができませんインタビューで排除されたくない場合は、事前に独自の知識システムを確立し、学習を計画して、学習を続けるしかありません。自分自身を向上させることによってのみ、インターネット市場の寒い冬に進むことができます。

私たちは常に環境に適応するのであって、私たちに適応する環境ではないことを忘れないでください!

①「AndroidFaceSutraSummaryPDF」と②「2020AndroidReview MaterialsSummaryPDF」を無料で受け取りたい友達———— (無料パッケージに参加して受け取る)

おすすめ

転載: blog.csdn.net/qq_39477770/article/details/108798569