我以编程方式在for-loop中添加TextView并将它们添加到ArrayList。Android:以编程方式查看.setID(int id) - 如何避免ID冲突?
我该如何使用TextView.setId(int id)
?什么整数ID我想出来,所以它不会与其他ID冲突?
我以编程方式在for-loop中添加TextView并将它们添加到ArrayList。Android:以编程方式查看.setID(int id) - 如何避免ID冲突?
我该如何使用TextView.setId(int id)
?什么整数ID我想出来,所以它不会与其他ID冲突?
根据View
文档
标识符不必在此视图的层次结构独特。标识符应该是一个正数。
所以你可以使用你喜欢的任何正整数,但在这种情况下,可以有一些视图与等效的ID。如果您想搜索层次结构中的某个视图,调用setTag
,某些关键对象可能会很方便。
您还可以在res/values
中定义ids.xml
。你可以在android的示例代码中看到一个确切的例子。
samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml
这里也是这个方法的答案:http://stackoverflow.com/questions/3216294/android-programatically-add-id-to-r-id – Ixx 2012-04-21 10:57:33
作为参考,我发现文件在: /samples/android -15/ApiDemos/src/com/example/android/apis/view/RadioGroup1.java – 2012-05-28 04:00:56
这个工作对我来说:
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++;
}
哇,简直是亲切! – max4ever 2012-08-10 10:49:02
[This](http://stackoverflow.com/a/6790714/581205)有点复杂,但我敢打赌它会工作。在多线程环境中使用全局变量肯定会在某一天失败,尤其是在多核心的情况下。 – maaartinus 2012-09-14 22:21:38
另外,这对于复杂的布局可能不是很慢吗? – 2013-01-11 00:17:53
(这是外行的答案注释,但它得到了太久......嘿嘿)
当然,此处不需要静态。你可以使用SharedPreferences来保存,而不是静态的。无论哪种方式,原因是要保存当前的进度,以便其复杂的布局不会太慢。因为事实上在使用过一次之后,它会在以后相当快。但是,我不觉得这是一个很好的方法,因为如果你不得不重新生成屏幕(例如onCreate
再次被调用),那么你可能想从头开始,无论如何,无需静态。因此,只需使其成为实例变量而不是静态变量。
这里是运行快一点,可能更容易阅读的缩小版:
int fID = 0;
public int findUnusedId() {
while(findViewById(++fID) != null);
return fID;
}
这上面的函数应该是足够的。因为,据我所知,Android生成的ID数十亿,所以这可能会第一次返回1
,并且总是很快。 因为它实际上不会循环使用已用的ID来找到一个未使用的ID。但是,循环是它应该实际上找到一个使用的ID。
但是,如果您仍然希望在应用程序后续重新创建之间保存进度,并且希望避免使用静态。这里是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;
}
这回答类似的问题应该告诉你,你需要了解与Android ID的一切:https://stackoverflow.com/a/13241629/693927
编辑/ FIX:刚刚意识到我完全疯玩起来保存。我一定喝醉了。
这应该是最好的答案。大量使用++关键字和空语句;) – 2015-04-11 00:07:33
由于API 17,View
类有一个static methodgenerateViewId()
,将
产生适合于在SETID(INT)使用
谷歌终于实现生成用于唯一ID的需要的值以编程方式创建的视图...
从API级别17及以上,您可以拨打电话
然后使用View.setId(int)。
情况下你需要它比17水平低的目标,这里是其在View.java内部实现,你可以在你的项目中直接使用,把它放在你的Util类或某处:
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;
}
}
}
ID大于0x00FFFFFF的数字保留给/ res xml文件中定义的静态视图。 (最有可能在我的项目****** 0x7f的从R.java)
在你的代码,你可以这样做:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
myView.setId(Utils.generateViewId());
} else {
myView.setId(View.generateViewId());
}
只是一个除了@phantomlimb的答案,
而View.generateViewId()
需要API等级> = 17,
这个工具是compatibe所有的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 [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();
}
}
}
您可以设置ID,你会在R.id
类使用XML资源文件后使用的,并让Android SDK在编译期间为它们提供唯一值。
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"/>
要在代码中使用它:
myEditTextView.setId(R.id.my_edit_text_1);
当我拥有未知数量的要分配ID的元素时,这不起作用。 – 2015-10-13 18:44:21
@MooingDuck我知道这是晚了一年,但是当我必须在运行时为未知数量的元素分配独特的ID时,我只需使用'“int currentId = 1000; whateverView.setId(currentId ++);' - 这会增加ID每当使用'currentId ++'时,确保一个唯一的ID,并且我可以将这些ID存储在我的ArrayList中以供以后访问。 – 2016-12-12 15:59:07
@MikeinSAT:这只能保证它们在它们之间是唯一的。它不会与其他ID冲突“,这是问题的关键部分 – 2016-12-13 03:15:24
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);
}
请以对未来访问者更清晰的方式为您的答案添加一个正确的描述,以评估您的答案的价值。在评论期间可以删除,谢谢! – 2016-12-12 22:41:15
我用:
public synchronized int generateViewId() {
Random rand = new Random();
int id;
while (findViewById(id = rand.nextInt(Integer.MAX_VALUE) + 1) != null);
return id;
}
通过使用一个随机数,我总是有一个庞大的获得唯一的ID在第一次尝试的机会。
我的选择:
// Method that could us an unique id
int getUniqueId(){
return (int)
SystemClock.currentThreadTimeMillis();
}
有趣的,我不知道,标识不必是唯一的?那么'findViewById'做出任何保证,那么如果有多个相同的ID,那么返回哪个视图?文档没有提及任何内容。 – Matthias 2012-05-03 10:04:55
我认为文档提到了这件事。如果在同一层次结构中具有相同ID的视图,则findViewById将返回它找到的第一个ID。 – kaneda 2012-05-07 14:32:11
@kaneda我不认为它获得第一个ID。它会得到你在setContentView()中设置的布局中的id – 2013-06-19 16:15:41