Recommandé : "Résumé des questions d'entretien Android 2020 [Collection] "
Permettez-moi de parler brièvement de mes quatre dernières années d'entretien. expérience. J'ai interviewé de nombreuses entreprises, et certaines d'entre elles m'ont enthousiasmé, et d'autres m'ont déçu et impuissant. J'ai enregistré toutes ces expériences après y avoir soigneusement réfléchi, cela en valait la peine, s'il n'y avait rien. en fin de compte, ce serait vraiment du gâchis de rester. Au moins pour moi, certaines choses ne peuvent recevoir une réponse définitive qu'après avoir trié et résumé. J'espère que cela pourra être utile à vous qui êtes sur le point de changer d'emploi ou qui envisagez de rechercher des opportunités.
Les réponses aux questions suivantes sont toutes compilées grâce à la pratique d'entretiens personnels au cours des quatre dernières années. Si vous avez des opinions différentes, n'hésitez pas à me corriger.
Réponse :
Généralement, lorsqu'une classe interne non statique contient une référence à un classe externe, ce qui empêche la classe externe d'être récupérée par le système après utilisation, provoquant ainsi une fuite de mémoire. Afin d'éviter ce problème, nous pouvons déclarer le gestionnaire personnalisé comme une classe interne statique, puis laisser le gestionnaire conserver une référence à la classe externe via une référence faible, évitant ainsi les fuites de mémoire.
Ce qui suit est l'implémentation du code
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private TextView mTextView; private WeakReference<MainActivity> activityWeakReference; private MyHandler myHandler; static class MyHandler extends Handler { private MainActivity activity; MyHandler(WeakReference<MainActivity> ref) { this.activity = ref.get(); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: //需要做判空操作 if (activity != null) { activity.mTextView.setText("new Value"); } break; default: Log.i(TAG, "handleMessage: default "); break; } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //在onCreate中初始化 activityWeakReference = new WeakReference<MainActivity>(this); myHandler = new MyHandler(activityWeakReference); myHandler.sendEmptyMessage(1); mTextView = (TextView) findViewById(R.id.tv_test); } }复制代码
Reportez-vous au billet de blog blog.csdn.net/ucxiii/arti...
Analyse :
Lors du développement d'applications Android, il est très simple de démarrer une autre activité à partir d'une activité et de transmettre certaines données à la nouvelle activité, mais lorsque vous en avez besoin pour laisser revenir l'activité exécutée en arrière-plan. Il peut y avoir un léger problème pour se rendre à la réception et transmettre certaines données.
Tout d'abord, par défaut, lorsque vous démarrez une activité via Intent, même s'il existe déjà une activité identique en cours d'exécution, le système créera une nouvelle instance d'activité et l'affichera. Afin d'éviter que l'activité ne soit instanciée plusieurs fois, nous devons configurer le mode de chargement (launchMode) de l'activité dans AndroidManifest. Pour une activité, si le système dispose déjà d'une instance, le système enverra la requête à cette instance, mais à ce stade, le système n'appellera pas la méthode onCreate qui gère habituellement les données de la requête, mais appellera la méthode onNewIntent
Réponse :Prérequis : ActivityA a a été démarré et se trouve dans la pile d'activités de l'application actuelle ; Lorsque LaunchMode d'ActivityA est SingleTop, si ActivityA est en haut de la pile et que vous souhaitez redémarrer ActivityA, la méthode onNewIntent() sera appelée. Lorsque le LaunchMode d'ActivityA est SingleInstance, SingleTask, si ActivityA est déjà dans la pile, alors la méthode onNewIntent() sera appelée à ce moment
Lorsque le LaunchMode d'ActivityA est Standard, puisque chaque fois qu'ActivityA est démarré, un nouveau The L'instance n'a rien à voir avec le démarrage d'origine, donc la méthode onNewIntent de l'ActivityA d'origine ne sera pas appelée. La méthode onCreate est toujours appelée
Ce qui suit est un exemple de code
. 1. Définir le démarrage de MainActivity Le mode est SingleTask (réutilisation dans la pile)<activity
android:label="@string/app_name"android:launchmode="singleTask"android:name="Activity1">
</activity>复制代码
<activity
android:name=".MainActivity"android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>复制代码
package code.xzy.com.handlerdemo; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.forward_btn); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startActivity(new Intent(MainActivity.this, Main2Activity.class)); } }); } @Override protected void onNewIntent(Intent intent) { Toast.makeText(this, "onnewIntent", Toast.LENGTH_SHORT).show(); Log.i(TAG, "onNewIntent: i done...."); } }复制代码
Il y a un ensemble spécial détaillé de matériel d'entretien à partager à la fin de l'article
)3. avantages de RecyclerView par rapport à ListView
Tout d'abord, nous devons expliquer le nom de RecyclerView. À en juger par son nom de classe, la signification de RecyclerView est. que je ne me soucie que de Recycler View, ce qui signifie que RecyclerView recycle et réutilise uniquement les vues. Vous pouvez configurer le reste par vous-même. On peut voir que son haut degré de découplage vous offre une totale liberté de personnalisation (vous pouvez donc facilement obtenir ListView, GirdView, le débit en cascade et d'autres effets grâce à ce contrôle)
Deuxièmement, RecyclerView offre la possibilité d'ajouter et supprimer des éléments. Effets d'animation et peut être personnaliséL'avantage de RecyclerView par rapport à ListView est qu'il peut être facilement implémenté :Fonctions ListView
Référence
.jcodecraeer.com/a/anzhuokai… blog.csdn.net/lmj62356579… www.360doc.com/content/16/…
Réponse :
La technologie Proguard a les fonctions suivantes :
Compression - vérifie et supprime les classes inutiles dans le code Optimisation - Optimisez le bytecode et supprimez le bytecode inutile Obfuscation - obscurcir le nom de la définition pour éviter la décompilation
Pré-surveillance-détecter à nouveau le code traité sur la plateforme Java
L'obscurcissement du code n'est utilisé que lors de la mise en ligne, le débogage Il sera activé désactivé en mode et est une technologie optionnelle.
Alors pourquoi utiliser l'obscurcissement du code ?
Parce que Java est un langage de développement interprété multiplateforme et que le code source de Java sera compilé en octets, les fichiers de code sont stockés dans les fichiers .class En raison des besoins multiplateformes, le bytecode Java contient de nombreuses informations sur le code source, telles que les noms de variables, les noms de méthodes, etc. Et accéder aux variables et aux méthodes via ces noms. Beaucoup de ces variables n'ont aucun sens, mais elles sont faciles à décompiler en code source Java. Afin d'éviter ce phénomène, nous devons utiliser proguard pour obscurcir le bytecode Java et le réorganiser. traiter le programme publié de manière à ce que le code traité ait la même fonction et un affichage de code différent que le code prétraité. Même s'il est décompilé, il est difficile de comprendre la signification du code et ceux qui ont été obscurcis. toujours être exécuté selon la logique précédente et obtenir le même résultat.
Cependant, certaines classes Java ne peuvent pas être confondues. Par exemple, les classes Java qui implémentent la sérialisation ne peuvent pas être confondues, sinon des problèmes surviendront lors de la désérialisation.
Lorsque vous masquez le code suivant, veillez à le conserver et à ne pas le masquer.
Les autres recommandations officielles d'Anroid ne prêtent pas à confusion, telles que
Sous Android, la réactivité des applications est surveillée par deux services système : Activity Manager et Window Manager. Lorsque l'utilisateur déclenche un événement d'entrée (tel qu'une saisie au clavier, un clic sur un bouton, etc.), si l'application ne répond pas à l'événement d'entrée de l'utilisateur dans les 5 secondes, Android considérera l'application comme ne répondant pas et affichera la boîte de dialogue ANR. L'exception ANR apparaît principalement pour améliorer l'expérience utilisateur.
La solution est que pour les opérations fastidieuses, telles que l'accès au réseau, l'accès à la base de données, etc., vous devez ouvrir un sous-thread et traiter les opérations fastidieuses dans le sous-thread. Le fil principal implémente principalement les opérations de l'interface utilisateur
Le processus d'utilisation de Handler dans le thread principal
Créez d'abord un objet Handler dans le thread principal et réécrivez-le dans la méthode handleMessage(). Ensuite, lorsque l'interface utilisateur doit être mise à jour dans le thread enfant, nous créons un objet Message et envoyons le message via le gestionnaire. Après cela, le message est ajouté à la file d'attente MessageQueue pour attendre son traitement. L'objet Looper essaiera toujours de récupérer le message en attente de la file d'attente de messages, et enfin de le distribuer à la méthode Message() du gestionnaire. Blog de référence.csdn.net/u012827296/…10. Quelle est la différence entre la communication inter-thread et la communication inter-processus, et comment est-elle implémentée dans le processus de développement Androidwww .cnblogs.com/yangtao1995…11. Décrivez brièvement plusieurs détails de l'optimisation de la mémoire dans le projetRéponse :
Ma compréhension personnelle est que le rendu de la vue Android doit passer par trois étapes : mesurer, mettre en page et dessiner. Le processus de mesure est parcouru en continu dans une structure arborescente. Si le niveau de l'interface utilisateur est profondément imbriqué, cela prendra certainement. beaucoup de temps, vous devriez donc essayer de réduire le niveau d'imbrication, vous assurer que la structure arborescente est plate et supprimer les vues qui n'ont pas besoin d'être rendues
Étapes de la vue personnalisée :
Étapes générales pour la vue personnalisée Android
Tutoriel Volley blog.csdn.net/ jdfkldjlkjd…
La différence fondamentale entre TCP et UDP
Scénarios d'application UDP :
Scénarios d'utilisation :
Avantages :
Pour étendre la fonction d'un objet, le mode décoration est plus flexible que l'héritage et n'entraînera pas une forte augmentation en nombre de classes.
peut étendre les fonctionnalités d'un objet de manière dynamique.
Un objet peut être décoré plusieurs fois en utilisant différentes classes de décoration spécifiques et les permutations et combinaisons de ces classes de décoration.
Application pratique :
Implémentation de la classe Context dans Android Mode Apparence : L'objectif principal est de réduire le nombre de sous-systèmes internes L'interaction entre les modules facilite l'utilisation du sous-système par le monde extérieur. Il est chargé de transmettre les demandes des clients à divers modules du sous-système pour traitement.Scénarios d'utilisation :
** Mode combinaison : ** Organiser les objets dans une structure arborescente pour obtenir une hiérarchie "partie-tout", afin que le client utilise de manière cohérente des objets uniques et des objets combinés .
Scénarios d'utilisation :
Avantages :
1. Les appels de module de haut niveau sont simples. 2. Ajoutez librement des nœuds
** Méthode du modèle : ** consiste à retarder les étapes de l'algorithme vers les sous-classes via un squelette d'algorithme, afin que les sous-classes puissent remplacer la mise en œuvre de ces étapes pour implémenter des algorithmes spécifiques.
Ses scénarios d'utilisation :
Un modèle abstrait a deux aspects dont l'un dépend de l'autre
Par exemple, en mode rappel, une fois que l'instance qui implémente la classe/interface abstraite a implémenté la méthode abstraite fournie par la classe parent, la méthode est renvoyée à la classe parent pour gérer
notifyDataSetChanged dans Listview
dans le modèle RxJava Observer
**Mode chaîne de responsabilité :** Une demande est traitée par plusieurs objets. Ces objets sont une chaîne, mais quel objet est traité est déterminé en fonction d'un jugement conditionnel s'il ne peut pas être traité. transmis à l'objet suivant dans la chaîne jusqu'à ce qu'un objet le gère.
Scénarios d'utilisation :1. Plusieurs objets peuvent gérer la même requête. L'objet spécifique qui gère la requête sera déterminé au moment de l'exécution. 2. Soumettez une demande à l'un des multiples objets sans spécifier explicitement le destinataire.
Application pratique :Try...catch déclaration Diffusion commandée MotionEvent : actionDwon actionMove actionUp Trois méthodes importantes du mécanisme de distribution d'événements : dispatchTouchEvent. onInterceptTouchEvent** Modèle de stratégie : ** Définissez une série d'algorithmes, encapsulez-les un par un et rendez-les interchangeables. Ce modèle permet à l'algorithme de changer indépendamment du client qui l'utilise. Scénarios d'utilisation du modèle de stratégie : Une classe définit une variété de comportements, et ces comportements apparaissent sous la forme de plusieurs instructions conditionnelles dans les méthodes de cette classe. Vous pouvez ensuite utiliser le modèle de stratégie pour éviter d'utiliser un grand nombre d'instructions conditionnelles dans la classe. classe.
Scénario d'utilisation :Une classe définit plusieurs comportements, et ces comportements apparaissent sous la forme de plusieurs instructions conditionnelles dans les méthodes de cette classe, vous pouvez alors utiliser le modèle de stratégie pour éviter d'en utiliser beaucoup d'instructions conditionnelles.
Avantages :1. Le contexte et la stratégie spécifique de ConcreateStrategy sont faiblement couplés. 2. Le modèle de stratégie satisfait au principe d'ouverture-fermeture Applications spécifiques :
HttpStackLe flux d'octets est généralement utilisé pour traiter des données binaires. En fait, il peut traiter tout type de données, mais il ne prend pas en charge l'écriture ou la lecture directe d'éléments de code Unicode. Le flux de caractères traite généralement les données texte, il prend en charge l'écriture ; et lisez les éléments de code Unicode.
Référez-vous à la compréhension de la différence entre le flux de caractères et le flux d'octets en Java
17. Processus de dessin de la vue, qu'il s'agisse de mesurer d'abord la vue parent ou la vue enfant
18. Les exceptions MOO peuvent-elles être détectées par try...catch (ou une erreur de mémoire insuffisante peut-elle être capturée avec try-catch pour éviter son apparition ?)
Mais ce n’est généralement pas l’approche appropriée. En plus de capturer explicitement le MOO, il existe des moyens plus efficaces de gérer la mémoire en Java : tels que SoftReference, WeakReference, le cache du disque dur, etc. Avant que la JVM ne manque de mémoire, le GC sera déclenché plusieurs fois, et ces GC réduiront l'efficacité du fonctionnement du programme. Si la cause du MOO n'est pas l'objet dans l'instruction try (comme une fuite de mémoire), alors le MOO continuera à être généré dans l'instruction catch
19 La différence entre WeakReference et SoftReference
<.>StrongReference, SoftReference de Java, La différence entre WeakReference et PhantomReferenceblog.csdn.net/u010652002/…
Réponse :
Chaque fois que vous avez besoin d'utiliser la base de données, vous devez utiliser la méthode openDatabase() de DatabaseManager pour obtenir le Cette méthode utilise un seul Le mode exemple garantit l'unicité des objets de la base de données, c'est-à-dire que les objets SQLite utilisés à chaque fois que la base de données est utilisée sont obtenus de manière cohérente. Deuxièmement, nous utiliserons un décompte de références pour déterminer s’il convient de créer un objet de base de données. Si le nombre de références est 1, nous devons créer une base de données. S'il n'est pas 1, nous l'avons déjà créé. Dans la méthode closeDatabase(), nous jugeons également la valeur du nombre de références. Si le nombre de références tombe à 0, cela signifie que nous devons fermer la base de données. L'approche générale est que dans le cas d'un accès multithread, vous devez encapsuler un DatabaseManager pour gérer la lecture et l'écriture de la base de données SQLite. La synchronisation est requise, asynchrone est asynchrone et ne fonctionne pas directement. la base de données, ce qui est facile à réaliser. L'opération après le verrouillage a échoué en raison du problème de verrouillage. Cette réponse fait référence à cet article blog.csdn.net/rockcode_li...28 Il existe deux listes chaînées avec des longueurs connues Comment déterminer l'intersection des deux listes chaînées<.>Il y a les idées suivantes :
(1) Fissuration par force brute , parcourez tous les nœuds de la liste chaînée A, et pour chaque nœud, il est comparé à tous les nœuds de la liste chaînée B, et la condition de sortie est de trouver le premier nœud égal dans B. La complexité temporelle est O(lengthA*lengthB) et la complexité spatiale est O(1).
(2) Table de hachage. Parcourez la liste chaînée A et stockez les nœuds dans la table de hachage. Parcourez ensuite la liste chaînée B, et pour chaque nœud de B, recherchez dans la table de hachage. S'il se trouve dans la table de hachage, cela signifie que c'est le nœud où commence l'intersection. La complexité temporelle est O(longueurA+longueurB) et la complexité spatiale est O(longueurA) ou O(longueurB).
(3) Méthode du double pointeur, les pointeurs pa et pb pointent respectivement vers les premiers nœuds des listes chaînées A et B.
Parcourez la liste chaînée A et enregistrez sa longueur lengthA, parcourez la liste chaînée B et enregistrez sa longueur lengthB.
Parce que les longueurs des deux listes chaînées peuvent être différentes, par exemple, dans le cas donné dans la question, longueurA=5, longueurB=6, alors la différence est longueurB- longueurA=1, et le pointeur pb est modifié à partir du premier nœud de la liste chaînée B Commencez à faire un pas, qui pointe vers le deuxième nœud, et pa pointe vers le premier nœud de la liste chaînée A. Ensuite, ils font un pas en même temps lorsqu'ils sont égaux, ce sont les nœuds d'intersection.
Fin
Il existe un mélange d'articles liés aux entretiens d'ingénieurs senior en ligne, soit un tas de contenu, soit la qualité du contenu est trop superficielle
Compte tenu de cela, J'ai compilé les questions et réponses d'entretien d'ingénieur senior en développement Android pour vous aider. J'ai été promu avec succès au rang d'ingénieur senior. Actuellement, je travaille en tant qu'ingénieur Android senior dans un grand fabricant. contribuer aux ingénieurs Android. J'ai trié ces questions après les avoir soigneusement examinées et pensé qu'elles étaient bonnes. Tout le monde, je sais que les ingénieurs seniors ne se verront pas poser de questions qui peuvent être exprimées clairement en une ou deux phrases comme celles qui débutent. j'ai donc filtré les articles pour aider tout le monde à comprendre, et j'espère que cela sera utile à tout le monde.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!