linearlayout - Android: View.setID(int id) mediante programación: ¿cómo evitar conflictos de ID?
android linearlayout set id programmatically (14)
Estoy agregando TextViews programáticamente en un bucle for y los agrego a un ArrayList.
¿Cómo uso TextView.setId(int id)
? ¿Con qué ID de entero se me ocurre para que no entre en conflicto con otras ID?
(Esto fue un comentario a la respuesta del diletante, pero se hizo demasiado largo ... jeje)
Por supuesto que aquí no se necesita una estática. Podrías usar SharedPreferences para guardar, en lugar de estática. De cualquier manera, la razón es guardar el progreso actual para que no sea demasiado lento para diseños complicados. Porque, de hecho, después de su uso una vez, será bastante rápido más tarde. Sin embargo, no creo que esta sea una buena forma de hacerlo porque si tiene que reconstruir su pantalla de nuevo (por ejemplo, si onCreate
se vuelva a llamar a onCreate
), probablemente desee volver a empezar desde el principio, eliminando la necesidad de estática. Por lo tanto, simplemente conviértalo en una variable de instancia en lugar de estática.
Aquí hay una versión más pequeña que se ejecuta un poco más rápido y podría ser más fácil de leer:
int fID = 0;
public int findUnusedId() {
while( findViewById(++fID) != null );
return fID;
}
Esta función anterior debería ser suficiente. Porque, por lo que puedo decir, las identificaciones generadas por Android están en los miles de millones, por lo que probablemente regresará 1
la primera vez y siempre será bastante rápido. Porque, en realidad, no se pasará de los identificadores utilizados para encontrar uno no utilizado. Sin embargo, el bucle está ahí si realmente encuentra un ID usado.
Sin embargo, si aún desea que el progreso se guarde entre las recreaciones posteriores de su aplicación y desea evitar el uso de estática. Aquí está la versión de SharedPreferences:
SharedPreferences sp = getSharedPreferences("your_pref_name", MODE_PRIVATE);
public int findUnusedId() {
int fID = sp.getInt("find_unused_id", 0);
while( findViewById(++fID) != null );
SharedPreferences.Editor spe = sp.edit();
spe.putInt("find_unused_id", fID);
spe.commit();
return fID;
}
Esta respuesta a una pregunta similar debe informarle todo lo que necesita saber sobre las ID con android: https://.com/a/13241629/693927
EDITAR / ARREGLAR: Me di cuenta de que me equivoqué totalmente al guardar. Debo haber estado borracho
Desde el nivel de API 17 y superior, puede llamar a: View.generateViewId()
Luego use View.setId(int) .
Si su aplicación está dirigida a un nivel inferior al API 17, use ViewCompat.generateViewId()
Desde la API 17, la clase de View
tiene un View.generateViewId() generateViewId()
que
generar un valor adecuado para su uso en setId (int)
Esto funciona para mí:
static int id = 1;
// Returns a valid id that isn''t in use
public int findId(){
View v = findViewById(id);
while (v != null){
v = findViewById(++id);
}
return id++;
}
La biblioteca ''Compat'' ahora también es compatible con el método generateViewId()
para los niveles de API anteriores al 17.
Solo asegúrate de usar una versión de la biblioteca 27.1.0+
que sea 27.1.0+
Por ejemplo, en su archivo build.gradle
, ponga:
implementation ''com.android.support:appcompat-v7:27.1.1
Luego, simplemente puede usar el ViewCompat
generateViewId()
de la clase ViewCompat
lugar de la clase View
como sigue:
//Will assign a unique ID myView.id = ViewCompat.generateViewId()
¡Feliz codificación!
Mi elección:
// Method that could us an unique id
int getUniqueId(){
return (int)
SystemClock.currentThreadTimeMillis();
}
Para generar dinámicamente el ID 17 del formulario de ID de Vista, use
Lo que generará un valor adecuado para su uso en setId(int)
. Este valor no chocará con los valores de ID generados en el momento de la compilación por aapt para R.id
Puede configurar las ID que usará más adelante en la clase R.id
usando un archivo de recursos xml, y dejar que el SDK de Android les dé valores únicos durante el tiempo de compilación.
res/values/ids.xml
<item name="my_edit_text_1" type="id"/>
<item name="my_button_1" type="id"/>
<item name="my_time_picker_1" type="id"/>
Para usarlo en el código:
myEditTextView.setId(R.id.my_edit_text_1);
Según View
documentación.
El identificador no tiene que ser único en la jerarquía de esta vista. El identificador debe ser un número positivo.
Por lo tanto, puede usar cualquier entero positivo que desee, pero en este caso puede haber algunas vistas con id equivalentes. Si desea buscar alguna vista en la jerarquía, puede ser útil llamar a setTag
con algunos objetos clave.
Solo una adición a la respuesta de @phantomlimb,
mientras que View.generateViewId()
requiere un nivel de API> = 17,
Esta herramienta es compatible con todas las API.
de acuerdo con el nivel API actual,
Se decide el clima usando la API del sistema o no.
para que puedas usar ViewIdGenerator.generateViewId()
y View.generateViewId()
al mismo tiempo y no te preocupes por obtener la misma 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();
}
}
}
También puede definir ids.xml
en res/values
. Puedes ver un ejemplo exacto en el código de ejemplo de Android.
samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml
Yo suelo:
public synchronized int generateViewId() {
Random rand = new Random();
int id;
while (findViewById(id = rand.nextInt(Integer.MAX_VALUE) + 1) != null);
return id;
}
Al usar un número aleatorio, siempre tengo una gran posibilidad de obtener la identificación única en el primer intento.
int fID;
do {
fID = Tools.generateViewId();
} while (findViewById(fID) != null);
view.setId(fID);
...
public class Tools {
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
public static int generateViewId() {
if (Build.VERSION.SDK_INT < 17) {
for (;;) {
final int result = sNextGeneratedId.get();
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();
}
}
}
public String TAG() {
return this.getClass().getSimpleName();
}
private AtomicInteger lastFldId = null;
public int generateViewId(){
if(lastFldId == null) {
int maxFld = 0;
String fldName = "";
Field[] flds = R.id.class.getDeclaredFields();
R.id inst = new R.id();
for (int i = 0; i < flds.length; i++) {
Field fld = flds[i];
try {
int value = fld.getInt(inst);
if (value > maxFld) {
maxFld = value;
fldName = fld.getName();
}
} catch (IllegalAccessException e) {
Log.e(TAG(), "error getting value for /'"+ fld.getName() + "/' " + e.toString());
}
}
Log.d(TAG(), "maxId="+maxFld +" name="+fldName);
lastFldId = new AtomicInteger(maxFld);
}
return lastFldId.addAndGet(1);
}