Vistas programáticas de cómo configurar identificadores únicos

Estoy creando en mi conjunto de aplicaciones View programáticos. Como parecía ser, todos por defecto tienen la misma id=-1 . Para trabajar con ellos, necesito generar identificaciones únicas.

He intentado varios enfoques: generación aleatoria de números y según la hora actual, pero de todos modos no hay garantía del 100% de que las diferentes vistas tengan diferentes id.

Solo me pregunto si hay alguna manera más confiable de generar unos únicos. Probablemente hay un método / clase especial?

Solo una adición a la respuesta de @phantomlimb,

mientras que View.generateViewId() requiere API Level> = 17,
esta herramienta es compatible con todas las API.

de acuerdo con el nivel de API actual,
decide el clima usando el API del sistema o no.

para que pueda usar ViewIdGenerator.generateViewId() y View.generateViewId() al mismo tiempo y no se preocupe por obtener 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 * 

* 自动判断当前API Level,并优先调用{@link View#generateViewId()},即使本工具类与{@link View#generateViewId()} * 混用,也能保证生成的Id唯一*

* ============= *

* while {@link View#generateViewId()} require API Level >= 17, this tool is compatibe with all API. *

* according to current API Level, it decide weather using system API or not.
* so you can use {@link ViewIdGenerator#generateViewId()} and {@link View#generateViewId()} in the * same time and don't worry about getting same id * * @author fantouchx@gmail.com */ 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(); } } }

Solo quiero agregar a la respuesta de Kaj, desde el nivel 17 de la API, puedes llamar

View.generateViewId ()

luego use el método View.setId (int).

En caso de que lo necesite para objectives inferiores al nivel 17, aquí está su implementación interna en View.java que puede usar directamente en su 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; } } } 

El número de ID más grande que 0x00FFFFFF está reservado para vistas estáticas definidas en los archivos / res xml. (Probablemente 0x7f ****** del R.java en mis proyectos).

Desde el código, de alguna manera, Android no quiere que uses 0 como id de una vista, y debe voltearse antes de 0x01000000 para evitar las conflits con ID de recursos estáticos.

Crea una clase singleton, que tenga un entero atómico. Combate el número entero y devuelve el valor cuando necesites una ID de vista.

La identificación será única durante la ejecución de su proceso, pero se reiniciará cuando se reinicie su proceso.

 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 ID puede no ser exclusivo, si ya hay vistas que tienen identificadores en la vista ‘gráfico’. Puede intentar comenzar con un número que sea Integer.MAX_VALUE, y disminuirlo en lugar de pasar de 1 -> MAX_VALUE

En cuanto a la solución de respaldo para API <17, veo que las soluciones sugeridas comienzan a generar ID a partir de 0 o 1. La clase View tiene otra instancia de generador, y también comienza a contar desde el número uno, lo que generará tanto su generador como el de View. los mismos ID, y terminará teniendo diferentes Vistas con los mismos ID en su jerarquía de Vista. Lamentablemente, no hay una buena solución para esto, pero es un truco que debe estar bien documentado:

 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; } } } } 

Desde la biblioteca de soporte 27.1.0, hay generateViewId () en ViewCompat

ViewCompat.generateViewId ()