Antworten:
Laut View
Dokumentation
Der Bezeichner muss in der Hierarchie dieser Ansicht nicht eindeutig sein. Die Kennung sollte eine positive Zahl sein.
Sie können also eine beliebige positive Ganzzahl verwenden. In diesem Fall kann es jedoch einige Ansichten mit entsprechenden IDs geben. Wenn Sie nach einer Ansicht in der Hierarchie suchen möchten, setTag
kann das Aufrufen mit einigen Schlüsselobjekten hilfreich sein.
findViewById
wird die erste gefundene zurückgegeben.
setContentView()
haben, beispielsweise 10 Ansichten mit derselben ID auf dieselbe ID-Nummer in derselben Hierarchie festgelegt hat , ein Aufruf von findViewById([repeated_id])
die erste Ansicht zurückgibt, die mit dieser einen wiederholten ID festgelegt wurde. Das ist es was ich meinte.
Ab API-Level 17 und höher können Sie Folgendes aufrufen: View.generateViewId ()
Verwenden Sie dann View.setId (int) .
Wenn Ihre App auf eine niedrigere Stufe als API-Stufe 17 ausgerichtet ist, verwenden Sie ViewCompat.generateViewId ()
AtomicInteger
Methodenimplementierung an.
for(;;)
habe ich noch nie gesehen? Wie heißt das?
Sie können IDs, die Sie später im R.id
Unterricht verwenden, mithilfe einer XML-Ressourcendatei festlegen und das Android SDK während der Kompilierungszeit eindeutige Werte festlegen lassen.
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"/>
So verwenden Sie es im Code:
myEditTextView.setId(R.id.my_edit_text_1);
"int currentId = 1000; whateverView.setId(currentId++);
- Das erhöht die ID bei jeder currentId++
Verwendung, stellt eine eindeutige ID sicher und ich kann die speichern IDs in meiner ArrayList für den späteren Zugriff.
<resources>
.
Auch können Sie festlegen , ids.xml
in res/values
. Sie können ein genaues Beispiel im Beispielcode von Android sehen.
samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml
Da 17 - API, die View
hat Klasse eine statische Methode generateViewId()
das wird
Generieren Sie einen Wert, der für die Verwendung in setId (int) geeignet ist.
Das funktioniert bei mir:
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()
ist eine langsame Operation. Der Ansatz funktioniert, jedoch auf Kosten der Leistung.
(Dies war ein Kommentar zu Dilettantes Antwort, aber es wurde zu lang ... hehe)
Natürlich wird hier keine Statik benötigt. Sie können SharedPreferences zum Speichern anstelle von statischen verwenden. In beiden Fällen besteht der Grund darin, den aktuellen Fortschritt so zu speichern, dass er für komplizierte Layouts nicht zu langsam ist. Denn in der Tat wird es nach seiner einmaligen Verwendung später ziemlich schnell sein. Ich glaube jedoch nicht, dass dies ein guter Weg ist, dies zu tun, denn wenn Sie Ihren Bildschirm erneut erstellen müssen (zonCreate
erstellen müssen (z. wird er erneut aufgerufen), möchten Sie wahrscheinlich trotzdem von vorne beginnen, sodass keine statische Aufladung erforderlich ist. Machen Sie es daher einfach zu einer Instanzvariablen anstelle einer statischen.
Hier ist eine kleinere Version, die etwas schneller läuft und möglicherweise leichter zu lesen ist:
int fID = 0;
public int findUnusedId() {
while( findViewById(++fID) != null );
return fID;
}
Diese obige Funktion sollte ausreichend sein. Weil, soweit ich das beurteilen kann, von Android generierte IDs in Milliardenhöhe liegen, wird dies wahrscheinlich 1
das erste Mal zurückkehren und immer recht schnell sein. Weil es nicht an den verwendeten IDs vorbeischleift, um eine nicht verwendete zu finden. Die Schleife ist jedoch vorhanden, wenn tatsächlich eine verwendete ID gefunden wird.
Wenn Sie jedoch weiterhin möchten, dass der Fortschritt zwischen den nachfolgenden Neuerstellungen Ihrer App gespeichert wird, und die Verwendung von statischer Aufladung vermeiden möchten. Hier ist die SharedPreferences-Version:
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;
}
Diese Antwort auf eine ähnliche Frage sollte Ihnen alles sagen, was Sie über IDs mit Android wissen müssen: https://stackoverflow.com/a/13241629/693927
EDIT / FIX: Ich habe gerade festgestellt, dass ich den Save total vermasselt habe. Ich muss betrunken gewesen sein.
Die 'Compat'-Bibliothek unterstützt jetzt auch die generateViewId()
Methode für API-Level vor 17.
Stellen Sie einfach sicher, dass Sie eine Version der Compat
Bibliothek verwenden27.1.0+
Fügen Sie beispielsweise in Ihre build.gradle
Datei Folgendes ein:
implementation 'com.android.support:appcompat-v7:27.1.1
Dann können Sie einfach die generateViewId()
aus der ViewCompat
Klasse anstelle der View
Klasse wie folgt verwenden:
//Will assign a unique ID
myView.id = ViewCompat.generateViewId()
Viel Spaß beim Codieren!
Nur eine Ergänzung zur Antwort von @phantomlimb,
während View.generateViewId()
API Level> = 17 erforderlich ist,
ist dieses Tool Compatibe mit allen API.
Je nach aktuellem API-Level wird
das Wetter mithilfe der System-API entschieden oder nicht.
So können Sie ViewIdGenerator.generateViewId()
und View.generateViewId()
in der gleichen Zeit verwenden und müssen sich keine Sorgen machen, dass Sie dieselbe ID erhalten
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 (;;) { … }
stammt aus dem Android-Quellcode.
generateViewId()
else { return View.generateViewId(); }
Dies wird eine Endlosschleife für API-Level kleiner als 17 Geräte?
Verwenden Sie zum dynamischen Generieren der View ID Form API 17
Dadurch wird ein Wert generiert, der für die Verwendung in geeignet ist setId(int)
. Dieser Wert kollidiert nicht mit ID-Werten, die zur Erstellungszeit von aapt for generiert wurden 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();
}
}
}
Ich benutze:
public synchronized int generateViewId() {
Random rand = new Random();
int id;
while (findViewById(id = rand.nextInt(Integer.MAX_VALUE) + 1) != null);
return id;
}
Durch die Verwendung einer Zufallszahl habe ich immer eine große Chance, die eindeutige ID im ersten Versuch zu erhalten.
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
dann irgendwelche Garantien dafür, welche Ansicht zurückgegeben wird, wenn es mehr als eine mit derselben ID gibt? Die Dokumente erwähnen nichts.