Yanıtlar:
View
Belgelere göre
Tanımlayıcının bu görünümün hiyerarşisinde benzersiz olması gerekmez. Tanımlayıcı pozitif bir sayı olmalıdır.
Bu nedenle, istediğiniz herhangi bir pozitif tamsayıyı kullanabilirsiniz, ancak bu durumda eşdeğer kimliklere sahip bazı görünümler olabilir. Hiyerarşide bazı görünümleri aramak istiyorsanız setTag
, bazı önemli nesnelerle çağrı yapmak kullanışlı olabilir.
findViewById
bulduğu ilk değeri döndürür.
setContentView()
diyelim, kimlikleri aynı hiyerarşide aynı kimlik numarasına ayarlanmış 10 görünüm , o zaman bir çağrı findViewById([repeated_id])
bu tekrarlanan kimliğe sahip ilk görünüm kümesini döndürecektir. Demek istediğim şey o.
API düzey 17 ve üzeri sürümlerden şunu arayabilirsiniz: View.generateViewId ()
Sonra View.setId (int) kullanın .
Uygulamanız API 17 düzeyinden düşükse, ViewCompat.generateViewId () kullanın
AtomicInteger
yöntemlerin uygulanmasına bir göz atın .
for(;;)
bunu daha önce hiç görmedim. Buna ne denir?
Daha sonra R.id
sınıfta kullanacağınız kimlikleri bir xml kaynak dosyası kullanarak ayarlayabilir ve Android SDK'nın derleme süresi boyunca onlara benzersiz değerler vermesine izin verebilirsiniz.
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"/>
Kodda kullanmak için:
myEditTextView.setId(R.id.my_edit_text_1);
"int currentId = 1000; whateverView.setId(currentId++);
- Bu, her currentId++
kullanıldığında kimliği artırır, benzersiz bir kimlik sağlar ve Daha sonra erişmek için ArrayList'imdeki kimlikler.
<resources>
.
Ayrıca tanımlayabilirsiniz ids.xml
içinde res/values
. Android'in örnek kodunda tam bir örnek görebilirsiniz.
samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml
API 17, View
sınıf bir sahip statik yöntemi generateViewId()
bu olacak
setId (int) 'de kullanıma uygun bir değer üretir
Bu benim için çalışıyor:
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++;
}
findViewById()
yavaş bir işlemdir. Yaklaşım işe yarar ama performans pahasına.
(Bu dilettante cevabının bir yorumuydu ama çok uzun sürdü ... hehe)
Tabii ki burada bir statik gerekli değildir. Statik yerine kaydetmek için SharedPreferences kullanabilirsiniz. Her iki durumda da, mevcut ilerlemeyi kaydetmek, böylece karmaşık düzenler için çok yavaş olmamasını sağlamaktır. Çünkü, aslında, bir kez kullanıldıktan sonra, daha sonra oldukça hızlı olacaktır. Ancak, bunu yapmak için iyi bir yol olduğunu düşünmüyorum, çünkü ekranınızı tekrar yeniden oluşturmanız gerekiyorsa ( onCreate
tekrar çağrılır), o zaman muhtemelen baştan başlamak istersiniz, statik ihtiyacını ortadan kaldırırsınız. Bu nedenle, bunu statik yerine bir örnek değişkeni yapın.
İşte biraz daha hızlı çalışan ve daha kolay okunabilen daha küçük bir sürüm:
int fID = 0;
public int findUnusedId() {
while( findViewById(++fID) != null );
return fID;
}
Yukarıdaki fonksiyon yeterli olmalıdır. Çünkü, söyleyebildiğim kadarıyla, android tarafından oluşturulan kimlikler milyarlarca, bu yüzden bu muhtemelen 1
ilk kez geri dönecek ve her zaman oldukça hızlı olacaktır. Çünkü, kullanılmayan bir kimlik bulmak için kullanılan kimlikleri geçmeyecek. Bununla birlikte, çevrim olduğu aslında kullanılmış bir kimliği var bulmalıdır.
Bununla birlikte, uygulamanızın sonraki rekreasyonları arasında ilerleme kaydedilmesini istiyorsanız ve statik kullanmaktan kaçınmak istiyorsanız. İşte SharedPreferences sürümü:
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;
}
Benzer bir soruya verilen bu cevap, Android ile kimlikler hakkında bilmeniz gereken her şeyi size söylemelidir: https://stackoverflow.com/a/13241629/693927
DÜZENLEME / DÜZELTME: Sadece kurtarmayı tamamen kandırdığımı fark ettim. Sarhoş olmalıydım.
'Compat' kitaplığı artık generateViewId()
17'den önceki API seviyeleri için yöntemi de desteklemektedir .
Sadece Compat
kütüphanenin bir sürümünü kullandığınızdan emin olun.27.1.0+
Örneğin, build.gradle
dosyanıza şunu koyun:
implementation 'com.android.support:appcompat-v7:27.1.1
Sonra basitçe kullanabilirsiniz generateViewId()
gelen ViewCompat
yerine sınıfında View
aşağıdaki gibi sınıfta:
//Will assign a unique ID
myView.id = ViewCompat.generateViewId()
Mutlu kodlama!
@Phantomlimb cevabına sadece bir ek,
ise View.generateViewId()
API Seviye> = 17 gerektirir,
bu aracı tüm API ile compatibe olduğunu.
mevcut API Seviyesine göre,
sistem API'sini kullanarak hava durumuna karar verir.
böylece aynı anda ve kullanabilirsiniz ViewIdGenerator.generateViewId()
ve View.generateViewId()
aynı kimliği alma konusunda endişelenmeyin
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();
}
}
}
for (;;) { … }
Android Kaynak Kodundan gelir.
generateViewId()
else { return View.generateViewId(); }
17 cihazdan daha küçük api seviyesi için bu sonsuz döngüye girecek mi?
View Id form API 17'yi dinamik olarak oluşturmak için şunu kullanın:
Hangi kullanım için uygun bir değer üretecektir setId(int)
. Bu değer, aapt tarafından derleme zamanında oluşturulan kimlik değerleriyle çarpışmayacaktır R.id
.
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();
}
}
}
Kullanırım:
public synchronized int generateViewId() {
Random rand = new Random();
int id;
while (findViewById(id = rand.nextInt(Integer.MAX_VALUE) + 1) != null);
return id;
}
Rastgele bir sayı kullanarak, ilk denemede benzersiz kimliği alma şansım her zaman büyüktür.
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);
}
findViewById
daha aynı kimlikle olandan varsa görünüm döndürülür sonra da hangi herhangi bir garanti? Dokümanlar hiçbir şeyden bahsetmiyor.