程序化视图如何设置唯一的ID?

我正在创build我的应用程序一堆编程View 。 因为它似乎是默认情况下都有相同的id=-1 。 为了与他们合作,我需要生成唯一的ID。

我已经尝试了几种方法 – 随机数生成和基于当前时间,但无论如何,没有100%的保证,不同的视图将有不同的ID

只是想知道有没有更可靠的方法来产生独特的? 可能有特殊的方法/类?

Solutions Collecting From Web of "程序化视图如何设置唯一的ID?"

除了@phantomlimb的答案之外,

View.generateViewId()要求API Level> = 17,
这个工具是与所有API兼容的。

根据目前的API级别,
它决定使用系统API的天气或不。

所以你可以同时使用ViewIdGenerator.generateViewId()View.generateViewId() ,不用担心得到相同的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 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(); } } } 

只需要添加到Kaj的答案,从API级别17,你可以打电话

View.generateViewId()

比使用setId(int)。

如果你需要它低于17级的目标,这里是它在View.java的内部实现,你可以直接在你的项目中使用:

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

大于0x00FFFFFF的ID号保留给在/ res xml文件中定义的静态视图。 (在我的项目中,最有可能是R.java的0x7f * *

从代码中,不知何故,Android不希望你使用0作为视图的ID,并且需要在0x01000000之前翻转,以避免使用静态资源ID冲突。

创build一个具有Integerprimefaces的单例类。 撞上整数,并在需要视图ID时返回值。

该id在执行过程中将是唯一的,但在重新启动过程时会重置。

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

请注意,如果已经有视图“视图”中具有ID的视图,则该ID可能不是唯一的。 你可以试着从一个Integer.MAX_VALUE开始,减less它,而不是从1 – > MAX_VALUE

关于API <17的回退解决scheme,我看到build议的解决scheme开始从0或1开始生成ID。View类有另一个生成器实例,也从第一个开始计数,这将导致您的View生成器生成相同的ID,并且您最终会在View层次结构中拥有具有相同ID的不同视图。 不幸的是,没有一个好的解决scheme,但这是一个应该被充分logging的黑客:

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