source

안드로이드:View.setID(intid)를 프로그래밍 방식으로 - ID 충돌을 방지하는 방법은?

ittop 2023. 9. 24. 13:08
반응형

안드로이드:View.setID(intid)를 프로그래밍 방식으로 - ID 충돌을 방지하는 방법은?

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

제가 어떻게 이용합니까TextView.setId(int id)? 다른 ID와 충돌하지 않도록 어떤 Integer ID를 생각해 내야 합니까?

API 레벨 17 이상부터 다음을 호출할 수 있습니다.View.generateViewId()

그런 다음 View.setId(int)를 사용합니다.

API 레벨 17보다 낮은 앱을 대상으로 하는 경우 ViewCompat.generateViewId()를 사용합니다.

나중에 사용할 ID를 정의할 수 있습니다.R.idxml 리소스 파일을 사용하는 클래스, 컴파일 시간 동안 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);

에 따르면View문서화

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

따라서 원하는 임의의 양의 정수를 사용할 수 있지만 이 경우 동등한 id를 가진 보기가 있을 수 있습니다.계층 호출에서 일부 보기를 검색하려면setTag중요한 물건이 있으면 도움이 될 겁니다

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

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

API 17 이후로.View수업은 정적인 방법이 있습니다. 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++;  
}

(이것은 딜레탄테의 대답에 대한 언급이었지만 너무 길어졌습니다.헤헤)

물론 여기는 정전기가 필요하지 않습니다.정적 환경설정 대신 공유 환경설정을 사용하여 저장할 수 있습니다.어느 쪽이든 복잡한 레이아웃에 비해 너무 느리지 않도록 현재 진행률을 저장하는 것이 이유입니다.왜냐하면, 사실 한 번 쓰고 나면 나중에 좀 빨라질 것이기 때문입니다.하지만 화면을 다시 재구성해야 하는 경우에는 이 방법이 경우) 이 방법이 좋지 않다고 생각합니다.onCreate를 다시 호출합니다. 그러면 처음부터 다시 시작하고 싶어질 것이므로 정적이 필요 없습니다.따라서 정적 변수 대신 인스턴스 변수로 지정합니다.

좀 더 빠르게 실행되고 읽기가 더 쉬울 수 있는 작은 버전은 다음과 같습니다.

int fID = 0;

public int findUnusedId() {
    while( findViewById(++fID) != null );
    return fID;
}

위와 같은 기능이면 충분합니다.왜냐하면, 제가 아는 한, 안드로이드에서 생성된 ID는 수십억 개에 달하기 때문에, 이것은 아마도 다시 돌아올 것이기 때문입니다.1처음에 그리고 항상 꽤 빠릅니다.왜냐하면, 사용되지 않은 ID를 찾기 위해 사용된 ID를 실제로 반복해서 사용하지 않을 것이기 때문입니다.그러나 루프는 실제로 사용된 ID를 찾아야 한다는 입니다.

그러나 앱의 후속 재생성 사이에 진행률을 저장하고 정적 사용을 피하고 싶다면.공유 기본 설정 버전은 다음과 같습니다.

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://stackoverflow.com/a/13241629/693927

편집/수정: 방금 내가 세이브를 완전히 망쳤다는 것을 깨달았습니다.제가 술에 취했나 봅니다.

에서 'Compat'도됩니다.generateViewId()전 API법 이전

을 꼭 하세요.Compat27.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 Level = 17,
이 도구는 모든 API와 호환됩니다.

현재 API Level 에
시스템 API를 이용하여 날씨를 결정합니다.

ViewIdGenerator.generateViewId()그리고.View.generateViewId()같은 에를 하지 마세요,요.

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을 동적으로 생성하려면

생성ViewId()

입니다에서 합니다.setId(int)이 은 . 된 ID appt 에에 시하지 않습니다.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();
        }
    }
}

@ dilettante 답변에서 영감을 얻어 코틀린의 확장 기능으로 솔루션을 소개합니다.

/* sets a valid id that isn't in use */
fun View.findAndSetFirstValidId() {
    var i: Int
    do {
        i = Random.nextInt()
    } while (findViewById<View>(i) != null)
    id = i
}
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();    
    }

언급URL : https://stackoverflow.com/questions/1714297/android-view-setidint-id-programmatically-how-to-avoid-id-conflicts

반응형