Programático puntos de vista de cómo establecer el identificador único?

Estoy creando en mi app montón de programación Views. Ya que parece ser que por defecto tienen el mismo id=-1. Con el fin de trabajar con ellos, me necesita generar un identificador único.

He intentado varios enfoques de generación de número aleatorios y basado en la hora actual, pero de todos modos no hay 100% de garantía de que los diferentes puntos de vista tienen diferentes id de

Solo me pregunto ¿hay alguna manera más confiable para generar únicos? Probablemente hay un método especial/clase?

InformationsquelleAutor barmaley | 2011-07-22

5 Kommentare

  1. 41

    Sólo una adición a la respuesta de @phantomlimb,

    mientras View.generateViewId() requieren a Nivel de API >= 17,

    esta herramienta es compatibe con todas las de la API.

    de acuerdo a la actual Nivel de API,

    es el decidir si el uso de la API del sistema o no.

    así que usted puede utilizar ViewIdGenerator.generateViewId() y View.generateViewId() en el
    mismo tiempo y no preocuparse de conseguir el mismo id

    import java.util.concurrent.atomic.AtomicInteger;
    
    import android.annotation.SuppressLint;
    import android.os.Build;
    import android.view.View;
    
    /**
     * {@link View#generateViewId()}要求API Level >= 17,而本工具类可兼容所有API Level
     * <p>
     * 自动判断当前API Level,并优先调用{@link View#generateViewId()},即使本工具类与{@link View#generateViewId()}
     * 混用,也能保证生成的Id唯一
     * <p>
     * =============
     * <p>
     * while {@link View#generateViewId()} require API Level >= 17, this tool is compatibe with all API.
     * <p>
     * according to current API Level, it decide weather using system API or not.<br>
     * so you can use {@link ViewIdGenerator#generateViewId()} and {@link View#generateViewId()} in the
     * same time and don't worry about getting same id
     * 
     * @author [email protected]
     */
    public class ViewIdGenerator {
        private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
    
        @SuppressLint("NewApi")
        public static int generateViewId() {
    
            if (Build.VERSION.SDK_INT < 17) {
                for (;;) {
                    final int result = sNextGeneratedId.get();
                    //aapt-generated IDs have the high byte nonzero; clamp to the range under that.
                    int newValue = result + 1;
                    if (newValue > 0x00FFFFFF)
                        newValue = 1; //Roll over to 1, not 0.
                    if (sNextGeneratedId.compareAndSet(result, newValue)) {
                        return result;
                    }
                }
            } else {
                return View.generateViewId();
            }
    
        }
    }
    • En realidad, esto es incorrecto, se utiliza un diferente AtomicInteger contador para que de Vista.generateViewId(), así que usted puede utilizar esta clase y a la Vista.generateViewId() indistintamente como usted afirma en la documentación de su clase. Será necesario el uso de esta clase exclusivamente.
    • si usted puede utilizar ViewIdGenerator.generateViewId() y View.generateViewId() indistintamente, lo que significa Construir.VERSIÓN.SDK_INT >= 17 ,por lo que el código if (Build.VERSION.SDK_INT < 17) {…} nunca se ejecutará. en realidad, siempre uso View.generateViewId() en ese caso. 🙂
    • Ha, es agradable ver a algunos comentarios de China en el código:)
    • Cómo restablecer la generateViewId()..
    • desde el Android oficial de la API View.generateViewId() no tiene nada como reset, este fragmento de código, que además no tiene
    • El código fuente es aquí.

  2. 54

    Sólo quiero añadir a Kaj la respuesta de la API de nivel 17, usted puede llamar a

    Vista.generateViewId()

    a continuación, utilizar la Vista.setId(int) método.

    En caso de que sea necesario para los objetivos de nivel inferior a 17, aquí está su implementación interna en View.java usted puede utilizar directamente en el proyecto:

    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
    
    /**
     * Generate a value suitable for use in {@link #setId(int)}.
     * This value will not collide with ID values generated at build time by aapt for R.id.
     *
     * @return a generated ID value
     */
    public static int generateViewId() {
        for (;;) {
            final int result = sNextGeneratedId.get();
            //aapt-generated IDs have the high byte nonzero; clamp to the range under that.
            int newValue = result + 1;
            if (newValue > 0x00FFFFFF) newValue = 1; //Roll over to 1, not 0.
            if (sNextGeneratedId.compareAndSet(result, newValue)) {
                return result;
            }
        }
    }

    Número de IDENTIFICACIÓN de más de 0x00FFFFFF está reservada para las vistas estáticas definidas en el /res archivos xml. (Lo más probable 0x7f****** de la R.java en mis proyectos.)

    Desde el código, de alguna manera, Android no quiere que usted use 0 como una vista de la identificación, y necesita ser volteado antes de 0x01000000 para evitar la conflits con la estática de los Identificadores de recursos.

    • No quiero que usen 0 como una vista de identificación debido a que este es universal para representar un recurso no válidos de identificación cuando se consulta un recurso en tiempo de ejecución.
    • Cómo restablecer la generateViewId ..
  3. 13

    Crear una clase singleton, que tiene un átomo Entero. Bump, el número entero y devuelva el valor cuando se necesita una vista de id.

    El id único durante la ejecución de su proceso, pero wil reset cuando el proceso se reinicia.

    public class ViewId {
    
        private static ViewId INSTANCE = new ViewId();
    
        private AtomicInteger seq;
    
        private ViewId() {
            seq = new AtomicInteger(0);
        }
    
        public int getUniqueId() {
            return seq.incrementAndGet();
        }
    
        public static ViewId getInstance() {
            return INSTANCE;
        }
    }

    Tenga en cuenta que el identificador puede no ser única, si ya hay puntos de vista que tienen identificadores en la vista de ‘el gráfico’. Usted podría tratar de comenzar con un número Entero.MAX_VALUE, y disminuir en lugar de ir de 1 -> MAX_VALUE

    • Corto de comprobación de todos los ID que se genera en el R.java archivo, no hay manera de saber si un IDENTIFICADOR es único o no (por lo que puedo decir). Ciertamente hay casos en los que Android va a muff las cosas porque de IDENTIFICACIÓN de los enfrentamientos. La mejor manera que encontré fue usar Entero.MAX_VALUE y disminuir el valor cada vez que se necesite un nuevo IDENTIFICADOR, como usted ha mencionado.
    • esta es una manera.. pero como Xiaochao Yang se mencionó, a partir de la API 17 puede utilizar el método de la Vista.generateViewId()
    • Puede que me responde.Esto se basa en su respuesta…stackoverflow.com/questions/32381678/…
    • Puede usted explicar poco más, en cuyo caso esta respuesta no va a generar Identificador único?
  4. 2

    Con respecto a la solución de reserva para la API<17, veo que las soluciones que se proponen iniciar la generación de Identificadores a partir de 0 o 1. La clase de Vista tiene otro ejemplo de generador, y también comienza a contar a partir del número uno, que será el resultado en ambos y la Vista del generador de la generación de los mismos Identificadores, y usted va a terminar encima de tener diferentes puntos de vista con el mismo Id en la Vista de jerarquía. Desafortunadamente, no hay una buena solución para esto, pero es un hack que deben estar bien documentados:

    public class AndroidUtils {
    
    /**
     *  Unique view id generator, like the one used in {@link View} class for view id generation.
     *  Since we can't access the generator within the {@link View} class before API 17, we create
     *  the same generator here. This creates a problem of two generator instances not knowing about
     *  each other, and we need to take care that one does not generate the id already generated by other one.
     *
     *  We know that all integers higher than 16 777 215 are reserved for aapt-generated identifiers
     *  (source: {@link View#generateViewId()}, so we make sure to never generate a value that big.
     *  We also know that generator within the {@link View} class starts at 1.
     *  We set our generator to start counting at 15 000 000. This gives us enough space
     *  (15 000 000 - 16 777 215), while making sure that generated IDs are unique, unless View generates
     *  more than 15M IDs, which should never happen.
     */
    private static final AtomicInteger viewIdGenerator = new AtomicInteger(15000000);
    
    /**
     * Generate a value suitable for use in {@link View#setId(int)}.
     * This value will not collide with ID values generated at build time by aapt for R.id.
     *
     * @return a generated ID value
     */
    public static int generateViewId() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return generateUniqueViewId();
        } else {
            return View.generateViewId();
        }
    }
    
    private static int generateUniqueViewId() {
        while (true) {
            final int result = viewIdGenerator.get();
            //aapt-generated IDs have the high byte nonzero; clamp to the range under that.
            int newValue = result + 1;
            if (newValue > 0x00FFFFFF) newValue = 1; //Roll over to 1, not 0.
            if (viewIdGenerator.compareAndSet(result, newValue)) {
                return result;
            }
        }
    }
    
    }
    • Buen punto sobre un posible conflicto entre la aplicación de la costumbre de generador y el generador interno en la clase de Vista. Has comprobado la propia lógica de la Vista.generateViewId() de la API de 16? No he encontrado una copia de la fuente, por lo que sólo la esperanza es básicamente el mismo como más recientes versiones de API.
    • No he encontrado el código fuente. Pero he experimentado conflictos cuando el uso de la Vista.generateViewId() incluso en nueva Api, así que he modificado el código para siempre uso mi propio generateUniqueViewId método.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea