기계적 인조 인간:프로그래밍 방식으로 View.setID(int id) - ID 충돌을 피하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1714297

  •  19-09-2019
  •  | 
  •  

문제

for-loop에 프로그래밍 방식으로 TextView를 추가하고 이를 ArrayList에 추가합니다.

어떻게 사용하나요? TextView.setId(int id)?다른 ID와 충돌하지 않도록 하려면 어떤 정수 ID를 만들어야 합니까?

도움이 되었습니까?

해결책

에 따르면 View 선적 서류 비치

식별자는 이 보기의 계층 구조에서 고유할 필요는 없습니다.식별자는 양수여야 합니다.

따라서 원하는 양의 정수를 사용할 수 있지만 이 경우 동일한 ID를 가진 일부 뷰가 있을 수 있습니다.계층 호출에서 일부 뷰를 검색하려는 경우 setTag 일부 주요 개체를 사용하면 편리할 수 있습니다.

다른 팁

API 레벨 17 이상에서 호출 할 수 있습니다. view.generateviewid ()

그런 다음 사용하십시오 view.setid (int).

앱이 API 레벨 17보다 낮은 대상이되는 경우 사용하십시오. viewCompat.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);

또한 정의 할 수 있습니다 ids.xml 안에 res/values. Android의 샘플 코드에서 정확한 예를 볼 수 있습니다.

samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml

API 17 이후 View 클래스는 a 정적 방법 generateViewId() 그게 될 것입니다

setid (int)에서 사용하기에 적합한 값을 생성합니다.

이것은 나를 위해 작동합니다 :

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++;  
}

(이것은 Dilettante의 답변에 대한 의견 이었지만 너무 오래 걸렸습니다 ... hehe)

물론 여기에는 정적이 필요하지 않습니다. 정적 대신 공유 예약을 사용하여 저장할 수 있습니다. 어느 쪽이든, 그 이유는 복잡한 레이아웃에 대해 너무 느리지 않도록 현재 진행 상황을 저장하기 위해서는 그렇습니다. 실제로 한 번 사용한 후에는 나중에 다소 빠르기 때문입니다. 그러나 나는 당신이 화면을 다시 재건해야한다면 ( 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;
}

비슷한 질문에 대한이 답변은 Android를 사용한 ID에 대해 알아야 할 모든 것을 알려야합니다. https://stackoverflow.com/a/13241629/693927

편집/수정 : 저장을 완전히 바꾸 었다는 것을 깨달았습니다. 나는 취했을 것입니다.

'Compat'라이브러리도 이제 지원합니다 generateViewId() 17 이전 API 수준에 대한 방법.

버전의 버전을 사용하십시오 Compat 도서관 27.1.0+

예를 들어, 당신의 build.gradle 파일, put :

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();
        }

    }
}

View ID 양식 API 17 사용을 동적으로 생성하려면

GenerateViewId ()

사용하기에 적합한 값을 생성합니다 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 synchronized int generateViewId() {
    Random rand = new Random();
    int id;
    while (findViewById(id = rand.nextInt(Integer.MAX_VALUE) + 1) != null);
    return id;
}

임의의 숫자를 사용하면 항상 첫 번째 시도에서 고유 한 ID를 얻을 수 있습니다.

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);
}

내 선택:

// Method that could us an unique id

    int getUniqueId(){
        return (int)    
                SystemClock.currentThreadTimeMillis();    
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top