Android:以编程方式 View.setID(int id) - 如何避免 ID 冲突?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1714297/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: View.setID(int id) programmatically - how to avoid ID conflicts?
提问by znq
I'm adding TextViews programmatically in a for-loop and add them to an ArrayList.
我在 for 循环中以编程方式添加 TextViews 并将它们添加到 ArrayList。
How do I use TextView.setId(int id)
? What Integer ID do I come up with so it doesn't conflict with other IDs?
我如何使用TextView.setId(int id)
?我想出了什么整数 ID 才不会与其他 ID 冲突?
采纳答案by Nikolay Ivanov
According to View
documentation
根据View
文档
The identifier does not have to be unique in this view's hierarchy. The identifier should be a positive number.
该标识符在此视图的层次结构中不必是唯一的。标识符应为正数。
So you can use any positive integer you like, but in this case there can be some views with equivalent id's. If you want to search for some view in hierarchy calling to setTag
with some key objects may be handy.
所以你可以使用任何你喜欢的正整数,但在这种情况下,可能会有一些具有等效 id 的视图。如果您想在层次结构中搜索某些视图,调用setTag
某些关键对象可能会很方便。
回答by X.Y.
From API level 17 and above, you can call: View.generateViewId()
从 API 级别 17 及以上,您可以调用:View.generateViewId()
Then use View.setId(int).
然后使用View.setId(int)。
If your app is targeted lower than API level 17, use ViewCompat.generateViewId()
如果您的应用的目标低于 API 级别 17,请使用ViewCompat.generateViewId()
回答by Sai Aditya
You can set ID's you'll use later in R.id
class using an xml resource file, and let Android SDK give them unique values during compile time.
您可以R.id
使用 xml 资源文件设置稍后在课堂上使用的ID ,并让 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"/>
To use it in the code:
要在代码中使用它:
myEditTextView.setId(R.id.my_edit_text_1);
回答by yenliangl
Also you can define ids.xml
in res/values
. You can see an exact example in android's sample code.
您也可以ids.xml
在res/values
. 您可以在 android 的示例代码中看到一个确切的示例。
samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml
回答by Diederik
Since API 17, the View
class has a static methodgenerateViewId()
that will
从 API 17 开始,View
该类有一个静态方法generateViewId()
,它将
generate a value suitable for use in setId(int)
生成适合在 setId(int) 中使用的值
回答by dilettante
This works for me:
这对我有用:
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++;
}
回答by Pimp Trizkit
(This was a comment to dilettante's answer but it got too long...hehe)
(这是对业余爱好者的回答的评论,但时间太长了......呵呵)
Of course a static is not needed here. You could use SharedPreferences to save, instead of static. Either way, the reason is to save the current progress so that its not too slow for complicated layouts. Because, in fact, after its used once, it will be rather fast later. However, I dont feel this is a good way to do it because if you have to rebuild your screen again (say onCreate
gets called again), then you probably want to start over from the beginning anyhow, eliminating the need for static. Therefore, just make it an instance variable instead of static.
当然,这里不需要静态。您可以使用 SharedPreferences 来保存,而不是静态的。无论哪种方式,原因都是为了保存当前进度,以便对于复杂的布局不会太慢。因为,其实用过一次,后面会比较快。但是,我不认为这是一个好方法,因为如果您必须再次重建屏幕(例如onCreate
再次调用),那么无论如何您可能希望从头开始,消除对静态的需要。因此,只需将其设为实例变量而不是静态变量。
Here is a smaller version that runs a bit faster and might be easier to read:
这是一个运行速度更快且可能更易于阅读的较小版本:
int fID = 0;
public int findUnusedId() {
while( findViewById(++fID) != null );
return fID;
}
This above function should be sufficient. Because, as far as I can tell, android-generated IDs are in the billions, so this will probably return 1
the first time and always be quite fast.
Because, it wont actually be looping past the used IDs to find an unused one. However, the loop isthere should it actually find a used ID.
上面这个功能应该就够了。因为,据我所知,android 生成的 ID 有数十亿,所以这可能会1
第一次返回并且总是很快。因为,它实际上不会遍历使用过的 ID 来查找未使用的 ID。但是,如果它确实找到了一个使用过的 ID ,那么循环就在那里。
However, if you still want the progress saved between subsequent recreations of your app, and want to avoid using static. Here is the SharedPreferences version:
但是,如果您仍然希望在应用程序的后续重新创建之间保存进度,并且希望避免使用静态。这是 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;
}
This answer to a similar question should tell you everything you need to know about IDs with android: https://stackoverflow.com/a/13241629/693927
这个对类似问题的回答应该告诉你你需要知道的关于安卓 ID 的一切:https: //stackoverflow.com/a/13241629/693927
EDIT/FIX: Just realized I totally goofed up the save. I must have been drunk.
编辑/修复:刚刚意识到我完全搞砸了保存。我一定是喝醉了。
回答by Alex Roussiere
The 'Compat' library now also supports the generateViewId()
method for API levels prior 17.
'Compat' 库现在还支持generateViewId()
17 之前的 API 级别的方法。
Just make sure to use a version of the Compat
library that is 27.1.0+
只要确保使用的Compat
库版本是27.1.0+
For example, in your build.gradle
file, put :
例如,在您的build.gradle
文件中,输入:
implementation 'com.android.support:appcompat-v7:27.1.1
implementation 'com.android.support:appcompat-v7:27.1.1
Then you can simply use the generateViewId()
from the ViewCompat
class instead of the View
class as follow:
然后你可以简单地使用generateViewId()
来自ViewCompat
类而不是View
类,如下所示:
//Will assign a unique ID
myView.id = ViewCompat.generateViewId()
//Will assign a unique ID
myView.id = ViewCompat.generateViewId()
Happy coding !
快乐编码!
回答by fantouch
Just an addition to the answer of @phantomlimb,
只是对@phantomlimb 的回答的补充,
while View.generateViewId()
require API Level >= 17,
this tool is compatibe with all API.
虽然View.generateViewId()
需要 API 级别 >= 17,但
此工具与所有 API 兼容。
according to current API Level,
it decide weather using system API or not.
根据当前的 API 级别,
它决定是否使用系统 API 来决定天气。
so you can use ViewIdGenerator.generateViewId()
and View.generateViewId()
in the
same time and don't worry about getting same id
这样您就可以同时使用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();
}
}
}
回答by Arun C
In order to dynamically generate View Id form API 17 use
为了动态生成 View Id 表单 API 17 使用
Which will generate a value suitable for use in setId(int)
. This value will not collide with ID values generated at build time by aapt for R.id
.
这将生成一个适用于setId(int)
. 该值不会与 aapt for 在构建时生成的 ID 值发生冲突R.id
。