Maison > interface Web > Questions et réponses frontales > Une compilation de problèmes rencontrés par les développeurs Android lors d'entretiens avec Alibaba et d'autres grands fabricants

Une compilation de problèmes rencontrés par les développeurs Android lors d'entretiens avec Alibaba et d'autres grands fabricants

藏色散人
Libérer: 2020-07-31 17:05:22
avant
4099 Les gens l'ont consulté

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.

1. Comment éviter les fuites de mémoire lors de la personnalisation de Handler

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);
}
}复制代码
Copier après la connexion

Reportez-vous au billet de blog blog.csdn.net/ucxiii/arti...

2 Le moment de l'appel de onNewIntent( )

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>复制代码
Copier après la connexion

2 Remplacez la méthode onNewIntent dans MainActivity

<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>复制代码
Copier après la connexion
<🎜. >3. Main2Activity exécute click jump , MainActivity est réutilisé et la méthode onNewIntent est exécutée

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....");
}
}复制代码
Copier après la connexion
Imprimer des captures d'écran**Voici une vidéo d'une architecture systématique complète de haut niveau ; **Sept modules technologiques grand public, vidéo + Code source + notes (

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

Analyse :

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

    Fonctions GridView.
  1. Fonctions de ListView horizontale
  2. Fonction de ScrollView horizontale
  3. Effet cascade
  4. Animations d'ajout et de suppression d'articles faciles à ajouter
  5. Mais c'est assez déprimant. Le problème est que le système ne fournit pas ClickListener et LongClickListener. Mais nous pouvons aussi l’ajouter nous-mêmes, cela nécessite juste plus de code. Il existe de nombreuses façons de le mettre en œuvre. Vous pouvez écouter et juger les gestes via mRecyclerView.addOnItemTouchListener
Bien sûr, vous pouvez également fournir vous-même des rappels via l'adaptateur

Référence

.

jcodecraeer.com/a/anzhuokai… blog.csdn.net/lmj62356579… www.360doc.com/content/16/…

4. Parlez de la technologie d'obscurcissement Proguard

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.

  • Composants du système Android, les composants du système ont des méthodes fixes qui sont appelées par le système.
  • est référencé par le fichier de ressources Android. Le nom a été corrigé et ne peut pas être confondu, comme dans le cas d'une vue personnalisée.
  • Android Parcelable, vous devez utiliser la sérialisation Android.

Les autres recommandations officielles d'Anroid ne prêtent pas à confusion, telles que

  • android.app.backup.BackupAgentHelper
  • android.preference . Préférence 
  • com.android.vending.licensing.ILicensingService 
  • Méthode de sérialisation Java, la sérialisation du système nécessite une méthode fixe. 
  • Énumération, le système a besoin d'une manière fixe pour gérer l'énumération.
  • Méthode locale, le nom de la méthode locale ne peut pas être modifié
  • annotations Annotations
  • Pilote de base de données
  • Certains fichiers de ressources utilisent la réflexion

5. Scénarios et solutions pour l'ANR

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

6. Le processus d'authentification par certificat SSL dans HTTPS

7 Décrivez brièvement le mécanisme interne de l'activité Android

8. introduction à un certain module (ou application système) de la couche Android Framework

9. Le mécanisme et le principe d'Android Handler

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 Android

www .cnblogs.com/yangtao1995…

11. Décrivez brièvement plusieurs détails de l'optimisation de la mémoire dans le projet

Réponse :

  1. Après avoir interrogé la base de données, fermez l'objet Cursor à temps.
  2. N'oubliez pas d'appeler la méthode unregisterReceiver() dans la méthode onPause de l'activité pour désenregistrer la diffusion
  3. afin d'éviter les fuites de mémoire du contenu. Par exemple, ne définissez pas l'objet Drawer sur statique sur les versions antérieures à 4.0. .1. Lorsqu'un Drawable est lié à une View, l'objet View deviendra en fait une variable membre de rappel du Drawable. Dans l'exemple ci-dessus, le sBackground statique contient une référence à l'étiquette de l'objet TextView, et lable n'a qu'une référence à Activity, et L'activité contiendra des références à d'autres objets supplémentaires. Le cycle de vie de sBackground est plus long que celui d’Activity. Lorsque l'écran pivote, l'activité ne peut pas être détruite, ce qui provoque un problème de fuite de mémoire.
  4. Essayez de ne pas utiliser de classes internes non statiques dans Activity, car les classes internes non statiques contiendront implicitement des références à des instances de classe externes lorsque la période de déclaration de la référence des classes internes non statiques est plus longue que la période de déclaration. période de déclaration de l'activité, cela empêchera l'activité d'être recyclée normalement par GC.
  5. Utilisez les discussions avec prudence ! ! C'est une erreur que font beaucoup de gens : une caractéristique des Threads en Java est qu'ils sont directement référencés par la racine GC. C'est-à-dire que la machine virtuelle Dalvik détient des références fortes à tous les threads activés, ce qui fait que ces objets thread GC ne peuvent jamais. être recyclé à moins que le thread ne soit arrêté manuellement et défini sur null ou que l'utilisateur ne tue directement le processus. Par conséquent, lorsque vous utilisez des threads, vous devez envisager d'arrêter et de libérer le thread à temps lorsque l'activité se termine
  6. Lors de l'utilisation de Handler, placez-le dans un fichier de classe séparé ou utilisez une classe interne statique. Étant donné que les classes internes statiques ne contiennent pas de références à des classes externes, elles ne provoqueront pas de fuites de mémoire des instances de classe externes

12. Décrivez brièvement l'optimisation du niveau de vue d'Android, décrivez brièvement la vue personnalisée ou les étapes personnalisées de définition de ViewGroup

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

13. Sélectionnez une bibliothèque open source tierce couramment utilisée et décrivez brièvement ses étapes d'accès

Tutoriel Volley blog.csdn.net/ jdfkldjlkjd…

14. La différence entre TCP et UPD et les scénarios d'utilisation

La différence fondamentale entre TCP et UDP

  1. Basé sur la connexion et sans connexion
  2. TCP nécessite plus de ressources système et moins d'UDP ;
  3. La structure du programme UDP est plus simple
  4. Mode flux (TCP) et mode datagramme (UDP) ;
  5. Garantie TCP exactitude des données, UDP peut perdre des paquets
  6. TCP garantit l'ordre des données, UDP ne garantit pas

Scénarios d'application UDP :

  1. Méthode orientée datagramme
  2. La plupart des données réseau sont des messages courts
  3. Avoir un grand nombre de clients
  4. Aucune exigence particulière en matière de sécurité des données
  5. La charge du réseau est très lourde, mais les exigences élevées en matière de vitesse de réponse

15 Décrivez brièvement le concept de modèle de conception et parlez brièvement des modèles de conception utilisés dans la couche cadre

<.>Mode cas unique : mode Singleton C'est un mode de création d'objet qui est utilisé pour générer une instance spécifique d'un objet. Il peut garantir qu'une seule instance d'une classe dans le système est générée.

Mode adaptateur : convertissez une interface en une autre interface souhaitée par le client. Le mode adaptateur permet aux classes avec des interfaces incompatibles de travailler ensemble. Son alias est wrapper (Wrapper)

Mode décoration : ajouter dynamiquement. quelques responsabilités supplémentaires pour un objet. En termes d'ajout de fonctions d'objet, le mode de décoration est plus flexible que la génération d'implémentations de sous-classes. Le motif de décoration est un motif structurel d’objet.

Scénarios d'utilisation :

    Ajoutez des responsabilités à un seul objet de manière dynamique et transparente sans affecter les autres objets.
  1. Le mode décoration peut être utilisé lorsque le système ne peut pas être étendu par héritage ou lorsque l'héritage n'est pas propice à l'expansion et à la maintenance du système.

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 :

  1. Lorsque vous souhaitez fournir une interface simple pour un sous-système complexe
  2. Il y avait une énorme dépendance entre le programme client et la partie implémentation de la classe abstraite
  3. Quand Quand vous besoin de construire un sous-système hiérarchique

** 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 :

  1. Besoin de représenter le niveau entier ou partiel d'un objet
  2. Autoriser le client à ignorer les modifications apportées à différents objets niveaux

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 :

  1. Plusieurs sous-classes ont des méthodes publiques, et la logique est fondamentalement la même
  2. Algorithmes importants et complexes, Le L'algorithme de base peut être conçu comme une méthode de modèle. Lors de la refactorisation, le modèle de méthode de modèle est un modèle fréquemment utilisé.
  3. Modèle d'observateur : définit une relation un-à-plusieurs entre les objets. chaque fois que l'état d'un objet change, ses objets dépendants associés sont notifiés et automatiquement mis à jour.

Scénarios d'utilisation :

Un modèle abstrait a deux aspects dont l'un dépend de l'autre
  1. Un objet Les changements en provoqueront un ou plusieurs autres objets à modifier également
  2. Une chaîne de déclenchement doit être créée dans le système
Application spécifique :

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 :

HttpStack
  1. Volley Framework
  2. 16. Octet stream La différence avec le flux de caractères

L'unité de base du fonctionnement du flux d'octets est l'octet ; l'unité de base du fonctionnement du flux de caractères est l'unité de code Unicode (2 octets). Les flux d'octets n'utilisent pas de tampons par défaut ; les flux de caractères utilisent des tampons.

Le 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

Vue. et ViewGroup Le processus de dessin de base

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 ?)

Un seul Dans ce cas, il est possible de faire ceci : un objet volumineux est déclaré dans l'instruction try, provoquant le MOO, et il peut être confirmé que le MOO est provoqué par la déclaration d'objet dans l'instruction try, alors ces objets peuvent être publié dans l'instruction catch, résolvez le problème du MOO et continuez à exécuter les instructions restantes.

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 PhantomReference

20. Veuillez calculer la mémoire occupée par une image de 100 pixels * 100 pixels

blog.csdn.net/u010652002/…

Principe de mise en œuvre d'okHttp

22. Quels intercepteurs possède okHttp

23. +3 ! +4 ! +5 ! Le résultat de +...+20 ! est implémenté dans le code

24. Écrivez le mode singleton, lesquels sont thread-safe et pourquoi ils sont thread-safe

25. principe

26.Quels sont les formats des images Android ?

Réponse : blog.csdn.net/xmc28114194…

27. Comment SQLite peut-il effectuer des opérations multithread ? pour assurer le fonctionnement de la base de données multithread Sécurité

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<.>

Analyse : leetcode Le point d'intersection de deux listes chaînées www.360doc.com/content/16/…

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

De nos jours, le développement Android n'est pas aussi populaire que les années précédentes, mais les talents seniors sont encore rares. Cette phrase vous semble familière, car les talents web seniors le sont également. en pénurie, et les talents seniors c++ sont toujours rares, donc à l'ère de l'intelligence artificielle, il y aura également une pénurie de talents de haut niveau à l'ère de l'intelligence artificielle !

Il semble que les gens qui sont des talents de haut niveau soient aussi des talents de haut niveau dans d'autres domaines, et ce n'est pas parce qu'ils choisissent les plus populaires que tout se passera bien.

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!

Étiquettes associées:
source:csdn.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal