程序化视图如何设置唯一ID?

Bar*_*ica 29 android view uniqueidentifier

我正在我的应用程序中创建一堆程序化View的.因为看起来它们默认都是一样的id=-1.为了使用它们,我需要生成唯一的id.

我已经尝试了几种方法 - 随机数生成和基于当前时间,但无论如何没有100%保证不同的视图将具有不同的ID

只是想知道是否有更可靠的方法来生成独特的方法?可能有特殊的方法/类?

Xia*_*ang 54

只想添加到Kaj的答案,从API级别17,你可以打电话

View.generateViewId()

然后使用View.setId(int)方法.

如果您需要低于17级的目标,以下是View.java中的内部实现,您可以直接在项目中使用:

private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);

/**
 * Generate a value suitable for use in {@link #setId(int)}.
 * This value will not collide with ID values generated at build time by aapt for R.id.
 *
 * @return a generated ID value
 */
public static int generateViewId() {
    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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

大于0x00FFFFFF的ID号保留用于/ res xml文件中定义的静态视图.(很可能是我项目中来自R.java的0x7f******.)

从代码中,Android不希望你使用0作为视图的id,并且需要在0x01000000之前翻转它以避免与静态资源ID的混淆.


fan*_*uch 41

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

    }
}
Run Code Online (Sandbox Code Playgroud)

  • @iainmcgin如果可以互换地使用`ViewIdGenerator.generateViewId()`和`View.generateViewId()`,那意味着Build.VERSION.SDK_INT> = 17,所以代码`if(Build.VERSION.SDK_INT <17){...绝不会跑.实际上,在这种情况下它始终使用`View.generateViewId()`.:) (3认同)
  • 实际上,这是不正确的 - 您使用与View.generateViewId()不同的AtomicInteger计数器,因此您不能像在类的文档中断言那样交替使用此类和View.generateViewId().人们需要专门使用这个类. (2认同)

Kaj*_*Kaj 13

创建一个具有原子整数的单例类.Bump整数,并在需要视图ID时返回值.

在执行进程期间,id将是唯一的,但在重新启动进程时将重置.

public class ViewId {

    private static ViewId INSTANCE = new ViewId();

    private AtomicInteger seq;

    private ViewId() {
        seq = new AtomicInteger(0);
    }

    public int getUniqueId() {
        return seq.incrementAndGet();
    }

    public static ViewId getInstance() {
        return INSTANCE;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果视图"图形"中已存在具有ID的视图,则id可能不是唯一的.你可以尝试从一个Integer.MAX_VALUE数字开始,然后减去它而不是从1 - > MAX_VALUE

  • 这是一种方式..但正如Xiaochao Yang所说,从API 17你可以使用方法View.generateViewId() (6认同)

小智 13

从支持库27.1.0开始,ViewCompat中有generateViewId()

ViewCompat.generateViewId()