답변:
View
설명서 에 따르면
이 뷰의 계층에서 식별자가 고유하지 않아도됩니다. 식별자는 양수 여야합니다.
따라서 원하는 양의 정수를 사용할 수 있지만이 경우 동등한 id를 가진 일부 뷰가있을 수 있습니다. setTag
키 객체로 호출하는 계층 구조에서 일부 뷰를 검색하려는 경우 편리 할 수 있습니다.
findViewById
가장 먼저 찾은 것을 반환합니다.
setContentView()
에 동일한 계층 구조 에서 동일한 ID 번호로 ID가 설정된 10 개의 뷰가 있다고 가정 하면 호출하면 findViewById([repeated_id])
해당 하나의 반복 된 ID로 첫 번째 뷰 세트가 반환됩니다. 그게 내 뜻이야
API 레벨 17 이상에서 다음을 호출 할 수 있습니다. View.generateViewId ()
그런 다음 View.setId (int)를 사용하십시오. .
앱이 API 레벨 17보다 낮게 타겟팅 된 경우 ViewCompat.generateViewId ()를 사용하십시오.
AtomicInteger
메소드 구현을 살펴보십시오 .
for(;;)
내가 전에 본 적이없는 것. 그게 뭐야?
나중에 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"/>
코드에서 사용하려면 :
myEditTextView.setId(R.id.my_edit_text_1);
"int currentId = 1000; whateverView.setId(currentId++);
- 사용 할 때마다 ID가 증가하여 currentId++
고유 ID를 보장하며 나중에 액세스 할 수 있도록 내 ArrayList의 ID
<resources>
.
또한 ids.xml
에서 정의 할 수 있습니다 res/values
. 안드로이드의 샘플 코드에서 정확한 예제를 볼 수 있습니다.
samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml
이것은 나를 위해 작동합니다 :
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()
느린 작업입니다. 이 방법은 효과가 있지만 성능이 저하됩니다.
(이것은 dilettante의 답변에 대한 의견이지만 너무 길었습니다 ... hehe)
물론 정적은 필요하지 않습니다. 정적 대신 SharedPreferences를 사용하여 저장할 수 있습니다. 어느 쪽이든, 이유는 복잡한 진행을 위해 너무 느리지 않도록 현재 진행 상황을 저장하는 것입니다. 실제로 한 번 사용한 후에는 나중에 더 빠르기 때문입니다. 그러나 화면을 다시 작성 해야하는 경우 (예 onCreate
: 다시 호출되는 경우) 어쨌든 처음부터 다시 시작하여 정적이 필요 하지 않기 때문에 이것이 좋은 방법이라고 생각하지 않습니다 . 따라서 정적 대신 인스턴스 변수로 만드십시오.
다음은 조금 더 빠르게 실행되고 읽기 쉬운 작은 버전입니다.
int fID = 0;
public int findUnusedId() {
while( findViewById(++fID) != null );
return fID;
}
이 기능으로 충분합니다. 내가 알 수있는 한 안드로이드 생성 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;
}
비슷한 질문에 대한이 답변은 안드로이드 ID에 대해 알아야 할 모든 것을 알려줍니다. https //.com/a/13241629/693927
편집 / 수정 : 방금 내가 완전히 저장을 깨달았다는 것을 깨달았습니다. 나는 술에 취했을 것입니다.
'Compat'라이브러리는 이제 generateViewId()
17 이전의 API 레벨 방법 도 지원합니다 .
Compat
라이브러리 버전을 사용하십시오.27.1.0+
예를 들어 build.gradle
파일에 다음을 입력하십시오.
implementation 'com.android.support:appcompat-v7:27.1.1
그런 다음 다음 generateViewId()
과 같이 ViewCompat
클래스 대신 클래스 에서 간단하게 사용할 수 있습니다 View
.
//Will assign a unique ID
myView.id = ViewCompat.generateViewId()
행복한 코딩!
@phantomlimb의 답변에 추가 된 것,
View.generateViewId()
API 레벨> = 17이 필요 하지만
이 이 도구는 모든 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 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 소스 코드에서 제공됩니다.
generateViewId()
else { return View.generateViewId(); }
이것은 17 장치보다 작은 API 레벨에 대해 무한 루프가 될 것입니까?
View Id 양식 API 17을 동적으로 생성하려면
에 사용하기에 적합한 값을 생성합니다 setId(int)
. 이 값은 빌드시 aapt에 의해 생성 된 ID 값과 충돌하지 않습니다 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();
}
}
}
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
동일한 ID를 가진 뷰가 두 개 이상있는 경우 어떤 뷰가 반환되는지를 보증합니까? 문서에는 언급이 없습니다.