[JAVA] 2 milliards de chats, AndroidN EasterEgg, Faites beaucoup de chats ~ HyperUltraCatGenerator ~

HyperUltraCatGenerator! C'est une application qui fait beaucoup de chats de l'oeuf de Pâques d'Android N, Neko Atsume.

ezgif-3-747df78d5897.gif

generate cat Vous pouvez générer n'importe quel chat Android en tournant le sélecteur de numéro sur la gauche ou en le spécifiant sur la droite. Il sera partagé en appuyant sur.

save 1000 cats Vous pouvez générer un chat Android avec une plage de noms spécifiés par de ~ à. Le chat Android généré est enregistré dans Images / Chats.

Dépôt

https://github.com/nekomimi-daimao/hyper-ultra-cat-generator

Description du code

Suivez la trajectoire de cette putain de création d'application pendant que l'auto-code examine chaque commit. Je pense que ce serait amusant de garder une trace de ce à quoi les gens pensent lors du développement. Si vous êtes libre de sortir avec moi, veuillez lire en regardant le référentiel.

initial commit L'image que j'utilise pour l'icône est générée à partir d'Android N's Easter Egg et de Neko Atsume. L'impression que les images que j'ai collectées sont exposées les unes aux autres sur le net et qu'elles sont relativement populaires. Il existe également des jeux clones sur le playStore. Android Nougat Easter Egg Neko Easter Egg Je pensais jouer au jeu original et au jeu clone, mais je ne peux pas produire en masse Android Cat. Placez les aliments et attendez, ou appuyez dessus pour les générer un par un. J'ai pensé. ** Je veux beaucoup. ** **

import cats Commencez par créer une activité. Je suis toujours une activité vide car il est rare qu'elle ne se compile pas avec la génération automatique. https://android.googlesource.com/platform/frameworks/base/+/nougat-mr2.3-release/packages/EasterEgg Extrayez les fichiers nécessaires du référentiel comme ça et réécrivez les parties qui ne se compilent pas. Cat.java. Quoi qu'il en soit, quand je lis le code, Cat semble être généré aux endroits suivants. En gros, il est généré aléatoirement avec Cat.create (), et si vous voulez un Android Cat arbitraire, passez la graine de int au constructeur de Cat .... Je ne sais pas ce qu'est l'algorithme de teinture, alors je me demande si ça va ...

Cat.java



//Ceci est généré aléatoirement
public static Cat create(Context context) {
    return new Cat(context, Math.abs(ThreadLocalRandom.current().nextInt()));
}

//La logique de génération est un constructeur
public Cat(Context context, long seed) {
    D = new CatParts(context);
    mSeed = seed;
    setName(context.getString(R.string.default_cat_name,
            String.valueOf(mSeed % 1000)));
    final Random nsr = notSoRandom(seed);
    // body color
    mBodyColor = chooseP(nsr, P_BODY_COLORS);
    if (mBodyColor == 0) mBodyColor = Color.HSVToColor(new float[] {
            nsr.nextFloat()*360f, frandrange(nsr,0.5f,1f), frandrange(nsr,0.5f, 1f)});
    tint(mBodyColor, D.body, D.head, D.leg1, D.leg2, D.leg3, D.leg4, D.tail,
            D.leftEar, D.rightEar, D.foot1, D.foot2, D.foot3, D.foot4, D.tailCap);
    tint(0x20000000, D.leg2Shadow, D.tailShadow);
    if (isDark(mBodyColor)) {
        tint(0xFFFFFFFF, D.leftEye, D.rightEye, D.mouth, D.nose);
    }
    tint(isDark(mBodyColor) ? 0xFFEF9A9A : 0x20D50000, D.leftEarInside, D.rightEarInside);
    tint(chooseP(nsr, P_BELLY_COLORS), D.belly);
    tint(chooseP(nsr, P_BELLY_COLORS), D.back);
    final int faceColor = chooseP(nsr, P_BELLY_COLORS);
    tint(faceColor, D.faceSpot);
    if (!isDark(faceColor)) {
        tint(0xFF000000, D.mouth, D.nose);
    }
    mFootType = 0;
    if (nsr.nextFloat() < 0.25f) {
        mFootType = 4;
        tint(0xFFFFFFFF, D.foot1, D.foot2, D.foot3, D.foot4);
    } else {
        if (nsr.nextFloat() < 0.25f) {
            mFootType = 2;
            tint(0xFFFFFFFF, D.foot1, D.foot3);
        } else if (nsr.nextFloat() < 0.25f) {
            mFootType = 3; // maybe -2 would be better? meh.
            tint(0xFFFFFFFF, D.foot2, D.foot4);
        } else if (nsr.nextFloat() < 0.1f) {
            mFootType = 1;
            tint(0xFFFFFFFF, (Drawable) choose(nsr, D.foot1, D.foot2, D.foot3, D.foot4));
        }
    }
    tint(nsr.nextFloat() < 0.333f ? 0xFFFFFFFF : mBodyColor, D.tailCap);
    final int capColor = chooseP(nsr, isDark(mBodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS);
    tint(capColor, D.cap);
    //tint(chooseP(nsr, isDark(bodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS), D.nose);
    final int collarColor = chooseP(nsr, P_COLLAR_COLORS);
    tint(collarColor, D.collar);
    mBowTie = nsr.nextFloat() < 0.1f;
    tint(mBowTie ? collarColor : 0, D.bowtie);
}

cat is a seekbar

Comment utiliser la barre de recherche / MISE EN ROUTE Je ne l'ai pas utilisé pour le moment, j'ai donc essayé d'utiliser la barre de recherche. J'ai adopté Android Cat parce que cela semblait intéressant lorsque je définissais Android Cat dynamiquement sur le bouton de la barre de recherche. Alignez la piste et le bouton d'Android SeekBar Pour une raison quelconque, la position d'Android Cat est fixe, mais c'est toujours la première fois et j'ai pensé que je devrais le réparer plus tard, alors je l'ai laissé. La plage de la barre de recherche va de 0 à 999. Oui, je réfléchissais encore à ce moment. "Comme vous pouvez le deviner d'après le nom d'Android Cat, le nombre total est de 1 000 de # 0 à # 999" ...

cat is a picker Entrez les numéros avec NUMBER PICKER / MISE EN ROUTE Un autre sélecteur de nombres que j'ai toujours voulu utiliser. Lorsque vous le faites tourner, Android Cat est généré en rond et en rond, et c'est juste amusant. Définissez la valeur maximale sur ʻInteger.MAX_VALUE`, et si vous la tournez plus loin, elle devrait être 0, mais elle déborde et le nombre suivant ne s'affiche pas. Cela semble être négatif. Je pense que c'est un bug, mais je ne peux pas m'en empêcher car il n'est pas censé être utilisé d'une manière aussi déraisonnable.

Comme il est difficile de se tourner vers le nombre souhaité, une fonction de saut a été ajoutée. Mais. mPicker.setValue (jump); ne vient pas avec ʻonProgressChanged`. Quand je l'ai cherché, il y avait une personne qui avait la même question.

https://stackoverrun.com/ja/q/10095347

Je ne peux pas m'en empêcher, alors lisez NumberPicker.java. J'ai été surpris d'hériter de LiearLayout, mais je suis convaincu.

NumberPicker.java


    /*
     * @param value The current value.
     * @see #setWrapSelectorWheel(boolean)
     * @see #setMinValue(int)
     * @see #setMaxValue(int)
     */
    public void setValue(int value) {
        setValueInternal(value, false);
    }

C'est celui qui peut être frappé de l'extérieur. Et ce que cela donne est ci-dessous.

NumberPicker.java


   /**
     * Sets the current value of this NumberPicker.
     *
     * @param current The new value of the NumberPicker.
     * @param notifyChange Whether to notify if the current value changed.
     */
    private void setValueInternal(int current, boolean notifyChange) {
        if (mValue == current) {
            return;
        }
        // Wrap around the values if we go past the start or end
        if (mWrapSelectorWheel) {
            current = getWrappedSelectorIndex(current);
        } else {
            current = Math.max(current, mMinValue);
            current = Math.min(current, mMaxValue);
        }
        int previous = mValue;
        mValue = current;
        // If we're flinging, we'll update the text view at the end when it becomes visible
        if (mScrollState != OnScrollListener.SCROLL_STATE_FLING) {
            updateInputTextView();
        }
        if (notifyChange) {
            notifyChange(previous, current);
        }
        initializeSelectorWheelIndices();
        invalidate();
    }

** Pourquoi êtes-vous privé? ** ** Comme la valeur est définie de l'extérieur, il est décidé que nous attendons un rappel pour modifier la valeur, ou il semble que nous puissions choisir de notifier ou non le rappel de la notification de modification. Comme cela ne peut pas être aidé, je vais donner l'impression que le rappel a été exécuté lorsque la valeur a été définie.

cat is cardview, cat is extracter, cat is start Il n'y a pas de changements majeurs, je vais donc les résumer. La vue Cat is card ne se compile pas car il semble que j'ai commis quelque chose correctement. Quoi qu'il en soit, il était difficile de voir Android Cat sur un fond blanc, j'ai donc présenté CardView. À l'origine, je devrais faire une mise en page avec ConstraintLayout et CoordinatorLayout, mais je n'ai pas encore étudié du tout, donc je me suis juste habitué à RelativeLayout. Dans l'éditeur de mise en page, il est classé dans Legacy. Puisque l'affichage d'erreur est ennuyeux, je suis allé sur string.xml. Cliquez sur l'ampoule ou appuyez sur «Alt + Entrée» et Android Studio fera le reste. Après cela, si vous permettez de partager l'Android Cat généré en insérant la valeur initiale générée de manière appropriée au moment de l'affichage initial de la page, la partie generate cat prendra fin.

cat is provider Mais cependant. Quand j'ai lancé shareCat, que j'avais commis par inadvertance avec cat is a picker, il s'est écrasé avec brio. Pourquoi s'écrase-t-il! ** Même si c'est une copie! ** **

E/AndroidRuntime: FATAL EXCEPTION: main


    Process: plan.militarize.stray.cat.hyperultracatgenerator, PID: 5979
    android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/Cats/Cat_180.png exposed beyond app through ClipData.Item.getUri()

[Android]android.os.FileUriExposedException FileUriExposedException se produit sur Android 7.0 Nougat Comportement du partage de fichiers par fichier: // schéma sur Android N

Recherche par message d'erreur. Il est également vrai que WRITE_EXTERNAL_STORAGE n'a pas été ajouté, mais il semble que la gestion d'Uri soit devenue plus stricte depuis Android N. Est-ce encore plus explicite si vous sortez avec des fichiers? Je n'ai pas fait grand-chose à propos de ContetProvider, c'est donc environ une heure. Je ne l'ai pas bien compris, mais je suis allé au point où cela fonctionne pour le moment. C'est un mystère que l'original NekoLand.java ne plante pas, mais peut-être que EasterEgg est une application privilégiée stockée dans la zone système?

cat is snack C'est comme Toast! C'est pourquoi nous avons introduit un snack-bar qui, selon nous, est la dernière tendance. Displaying the Snackbar J'ai entendu dire qu'il apparaît sous la vue qui a été utilisée comme argument, mais il apparaît en bas de l'écran. Je pensais que c'était normal de le laisser tranquille. Ajoutez un bouton de saut aux images où Android Cat sera enregistré. Je ne pense pas vraiment à quoi faire du vol **. De plus, je vais créer un espace d'affichage dédié pour Android Cat, qui était un bouton de la barre de recherche. Définissez la version de la bibliothèque de support sur une constante avec gradle. Je pense toujours que c'est ennuyeux de séparer la version ou un autre fichier ... N'est-ce pas ennuyeux? Il est certain que gradle a tendance à être chaotique.

cat is permission RuntimePermission est pris en charge ici. Java 8 est également introduit pour une raison quelconque. Lambda est bon!

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    for (int grantResult : grantResults) {
        if (grantResult != PackageManager.PERMISSION_GRANTED) {
            Snackbar.make(mCardSave, R.string.request_permission, Snackbar.LENGTH_SHORT).show();
            return;
        }
    }
    switch (requestCode) {
        case R.id.current_cat:
            shareCat(new Cat(getApplicationContext(), mPicker.getValue()));
            break;
        case R.id.save_cats:
            // TODO save tha cats
            break;
        default:
            return;
    }
}

La gestion des rappels RuntimePermission est ennuyeuse car vous devez vous rappeler quelle fonctionnalité a demandé quelle autorisation. Étant donné que requestCode et viewId sont tous deux int, ils sont inclus tels quels. C'est juste une question de définir le requestCode vous-même, mais alors vous pouvez le laisser tel quel ... Pourquoi avez-vous ajouté «READ_EXTERNAL_STORAGE»? Probablement pas nécessaire.

cat is foreground Commencez à implémenter la partie save 1000 cats.

Neko Easter Egg

This can't really be compared to the easter egg, as this just ruins all of the fun and gives you over 4 billion different cat possibilities...but perhaps you'll find the fun in looking at them one at a time. ;)

4 billion different cat possibilities... Je vais le garder ...?

Cat.java


public static Cat create(Context context) {
    return new Cat(context, Math.abs(ThreadLocalRandom.current().nextInt()));
}

C'est ce ThreadLocalRandom.current (). NextInt () qui détermine AndroidCat. ThreadLocalRandom#nextInt Je ne l'ai pas écrit, mais il peut probablement renvoyer toutes les valeurs int. La plage de int est -2147483648 ~ 2147483647, et comme il s'agit d'une valeur absolue avec Math.abs (), il devrait y avoir 2147483647 Android Cats. Si vous incluez 0, cela peut être 2147483648, mais c'est ennuyeux et ne calcule pas. Je vais le garder ...

Implémentez de manière stupéfiante le ForegroundService IntentService. Je pense que c'est une phrase fixe, donc c'est approprié. Parfois, j'oublie l'autorisation «FOREGROUND_SERVICE» et cela me fait mal.

cat is progress Android Progress Notification with Examples Je n'ai pas fait la progression de la notification, alors je l'ai créée.

Si vous pensez que la progression n'est pas mise à jour de temps en temps, il semble qu'il y ait une limite à la fréquence des mises à jour des notifications. Android Nougat and rate limiting of notification updates À part une telle putain d'application, y a-t-il une application ordinaire qui est mise à jour si souvent? Aucun utilisateur ne veut connaître les progrès avec autant de détails.

Pour le moment, la logique de génération d'Android Cat est la suivante.

CatServeService.java


Set<Integer> set = new HashSet<>(MAX);
List<Future<?>> list = new ArrayList<Future<?>>(MAX);
executorService = Executors.newWorkStealingPool();

while (set.size() < MAX) {
    int seed = Math.abs(ThreadLocalRandom.current().nextInt());
    int name = seed % 1000;
    if (name < from || to < name) {
        continue;
    }
    if (set.contains(name)) {
        continue;
    }
    set.add(name);
    list.add(executorService.submit(new CatSaver(seed)));
}
executorService.shutdown();

Je suis fier que ce soit une ** logique macho ** qui mourra si je continue à la frapper avec un réseau de fer. Si la génération de nombres aléatoires est biaisée, vous ne pourrez pas sortir indéfiniment de la boucle while, mais tant que vous l'essayez avec l'émulateur, elle sortira toujours immédiatement, donc tout ira bien. Peut-être. CatSaver est un Runnable ridicule qui ne fait que copier le contenu de shareCat. Passez-le à ExecutorService et attendez.

CatServeService.java


for (int count = 0; count < list.size(); count++) {
    try {
        list.get(count).get();
        builder.setProgress(MAX, count, false);
        manager.notify(NOTIFICATION_ID_SAVE_CAT_PROGRESS, builder.build());
    } catch (ExecutionException | InterruptedException e) {
    }
}

À l'origine, il devrait être mis à jour dès que chaque personne a terminé, pas dans l'ordre passé à ExecutorService, ou une nouvelle tentative de la tâche a échoué devrait être incluse, mais je l'ai arrêtée car elle est gênante. Effrayant multi-thread.

cat is name Je lui ai donné un nom.

cat is crash Jusqu'à présent, nous avons confirmé le fonctionnement avec l'émulateur P. Ici, quand je l'ai mis dans la machine réelle de N et que j'ai généré une grande quantité d'Android Cat ** crash **. ** Crash ** lorsque j'ai créé un émulateur N et l'ai exécuté. En particulier, logcat ne teinture en rouge </ font> ... C'est lourd et je n'aime pas beaucoup ça, mais quand je lance Profiler, la mémoire augmente beaucoup et ça plante. ** C'est une image, donc c'est une fuite de mémoire! ** ** Donc des mesures.

  • Rendre la classe interne statique
  • Bitmap.recycle()
  • Mettre null dans le Bitmap utilisé et Drawable

Il s'est encore écrasé. Comme cela ne peut pas être aidé, j'ai changé l'endroit où Android Cat a été généré par multi-thread en thread unique et il ne plante plus.

CatServeService.java


//avant multi-thread
executorService = Executors.newWorkStealingPool();

//après un seul fil
executorService = Executors.newSingleThreadExecutor();

Le service exécuteur qui peut être facilement commuté est Dieu. Il semble que IO avec multi-thread soit également gênant, mais je pense que ce crash est quelque chose qui ne va pas avec le traitement de la libération de mémoire de Bitmap et Drawable de N. Si c'est O ou P, le GC fonctionnera et ne plantera pas.

cat is icon Comment prendre en charge Adaptive Icon pour le moment Créer une icône adaptative dans Android Studio Comme c'est un gros problème, je vais essayer de créer une icône adaptative. Il semble que le nombre d'applications domestiques compatibles soit faible au 16 octobre 2018 et sa puissance n'a pas pu être confirmée. Je pense qu'il ne peut être utilisé que dans la mesure où il peut être utilisé en disant: "Ah, cette application ne prend pas en charge Adaptive Icon! Si vous ne rattrapez pas les nouvelles spécifications du framework, c'est une sélection assez cruelle que les utilisateurs verront la putain d'icône. Au fait, j'ai créé cette putain d'icône Dasa avec gimp pendant 20 minutes, mais quand j'y pense maintenant, il aurait peut-être été plus cool de sculpter le chat Android verticalement plutôt qu'horizontalement.

cat is font Kielo Typeface Des polices sont également ajoutées. J'ai également ajouté un toolBar. Je pense qu'il est préférable de laisser les polices ordinaires aux polices standard du terminal, mais il peut être amusant d'utiliser des polices décoratives comme de tels accents. Au début, je pensais que j'utiliserais this, mais * je n'ai pas besoin de deux types de chats *, c'est donc à la mode.

cat is large icon La grande icône ne s'affiche pas dans la notification après O. Je ne l'ai pas bien vérifié, mais il semble que l'icône adaptative ne puisse pas être définie sur Grande icône. Peut-être que Bitmap n'a pas pu être généré. Si c'est Vector, je peux y aller ...? C'est ennuyeux, alors ** copiez l'image de l'icône générée automatiquement à partir du dossier mipmap et insérez-la dans le dossier pouvant être dessiné **. Le pouvoir est le pouvoir!

cat is modifications Divers ajustements. J'ai remarqué que ** le son de notification continue de sonner ** chaque fois que la progression est mise à jour, j'ai donc changé de NotificationManager.IMPORTANCE_DEFAULT à NotificationManager.IMPORTANCE_LOW. Vous faites .setCategory (NotificationCompat.CATEGORY_PROGRESS)! Ne sonnez pas! Je pense, mais bon, ça ne peut pas être aidé ...

corrigez ForegroudService car il pourrait également planter. Un service démarré avec ContextCompat.startForegroundService plantera s'il n'y a que startForeground () même s'il se termine sans rien faire à cause d'une faille dans l'intention. C'est un cas d'erreur auquel il est difficile de penser, il peut donc être difficile à découvrir plus tard.

Le reste est «Media Scanner Connection». Je fais cela lorsque je veux que d'autres applications voient immédiatement les images générées, mais je n'aime pas le fait que je demande constamment à chacune d'entre elles, alors je leur ai demandé de tout faire en même temps. fait. J'ai vraiment fait ça d'une manière ou d'une autre, donc si vous avez des connaissances, faites-le moi savoir si vous faites une erreur.

en conclusion

Vous êtes maintenant libre de générer un grand nombre de chats Android. Au moment où j'écris cet article, juste avant cette publication, je pense que je suis la personne qui a produit le plus de chats Android sur cette planète **. Veuillez utiliser HyperUltraCat Generator pour générer un grand nombre de chats Android et les utiliser pour les icônes et ainsi de suite!

prime

Il y avait [une personne qui analyse vraiment](https://zau2and.blogspot.com/search/label/ Nekoatsume). Pour être clair, si vous lisez cet article à temps pour lire cet article, ce sera mieux depuis Android. Je l'ai trouvé après avoir créé l'application. C'est vrai.

Bonus bonus

La taille d'image moyenne d'Android Cat est de 14 Ko. 14 * 2147483647 = 30064771058

f2668204-9e05-4e18-b941-82f629d57bd0.png

C'est incroyable.

Recommended Posts

2 milliards de chats, AndroidN EasterEgg, Faites beaucoup de chats ~ HyperUltraCatGenerator ~
Notez les arguments de mot-clé Ruby
Faire une marge à gauche du TextField