我以編程方式在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