ฉันเพิ่ม TextViews โดยทางโปรแกรมใน for-loop และเพิ่มลงใน ArrayList
ฉันจะใช้งานTextView.setId(int id)
อย่างไร ฉันควรใช้ Integer ID ใดดังนั้นจึงไม่ขัดแย้งกับรหัสอื่น
ฉันเพิ่ม TextViews โดยทางโปรแกรมใน for-loop และเพิ่มลงใน ArrayList
ฉันจะใช้งานTextView.setId(int id)
อย่างไร ฉันควรใช้ Integer ID ใดดังนั้นจึงไม่ขัดแย้งกับรหัสอื่น
คำตอบ:
ตามView
เอกสารประกอบ
ตัวระบุไม่จำเป็นต้องไม่ซ้ำกันในลำดับชั้นของมุมมองนี้ ตัวระบุควรเป็นจำนวนบวก
ดังนั้นคุณสามารถใช้จำนวนเต็มบวกใด ๆ ที่คุณชอบ แต่ในกรณีนี้อาจมีบางมุมมองที่มี id เทียบเท่า หากคุณต้องการค้นหามุมมองบางอย่างในลำดับชั้นที่เรียกsetTag
ด้วยวัตถุสำคัญบางอย่างอาจมีประโยชน์
findViewById
จะกลับมาเป็นครั้งแรกที่พบ
setContentView()
มี 10 วิวด้วย id ที่ตั้งไปยังหมายเลขไอดีเดียวกันในลำดับชั้นเดียวกันการเรียกใช้findViewById([repeated_id])
จะส่งคืนมุมมองแรกที่ตั้งค่าด้วยไอดีซ้ำ ๆ นั่นคือสิ่งที่ฉันหมายถึง.
จาก API ระดับ 17 ขึ้นไปคุณสามารถโทร: View.generateViewId ()
จากนั้นใช้View.setId (int)
หากแอปของคุณกำหนดเป้าหมายต่ำกว่า API ระดับ 17 ให้ใช้ViewCompat.generateViewId ()
AtomicInteger
วิธีการใช้งาน
for(;;)
ฉันไม่เคยเห็นมาก่อน เรียกว่าอะไร
คุณสามารถตั้งค่า 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);
"int currentId = 1000; whateverView.setId(currentId++);
- เพิ่ม ID นั้นทุกครั้งที่currentId++
ใช้รับรองรหัสที่ไม่ซ้ำกันและฉันสามารถเก็บ ID ใน ArrayList ของฉันเพื่อการเข้าถึงในภายหลัง
<resources>
แต่เพิ่ม
นอกจากนี้คุณสามารถกำหนดในids.xml
res/values
คุณสามารถดูตัวอย่างที่แน่นอนในโค้ดตัวอย่างของ Android
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++;
}
findViewById()
เป็นการทำงานที่ช้า วิธีการทำงาน แต่ค่าใช้จ่ายของประสิทธิภาพ
(นี่เป็นความคิดเห็นต่อคำตอบของ dilettante แต่มันยาวเกินไป ... hehe)
แน่นอนว่าคงไม่จำเป็นต้องใช้ที่นี่ คุณสามารถใช้ SharedPreferences เพื่อบันทึกแทนสแตติก ไม่ว่าจะด้วยวิธีใดเหตุผลคือบันทึกความคืบหน้าปัจจุบันเพื่อไม่ให้ช้าเกินไปสำหรับเค้าโครงที่ซับซ้อน เพราะในความเป็นจริงหลังจากการใช้เพียงครั้งเดียวมันจะค่อนข้างเร็วในภายหลัง อย่างไรก็ตามฉันไม่รู้สึกว่านี่เป็นวิธีที่ดีในการทำเพราะถ้าคุณต้องสร้างหน้าจอใหม่อีกครั้ง (พูดว่าonCreate
ถูกเรียกอีกครั้ง) คุณอาจต้องการเริ่มต้นใหม่ตั้งแต่ต้นอย่างไรก็ตามไม่จำเป็นต้องใช้สแตติก ดังนั้นเพียงแค่ทำให้มันเป็นตัวแปรอินสแตนซ์แทนที่จะเป็นแบบคงที่
นี่คือรุ่นที่เล็กกว่าซึ่งทำงานได้เร็วกว่าเล็กน้อยและอ่านง่ายกว่า:
int fID = 0;
public int findUnusedId() {
while( findViewById(++fID) != null );
return fID;
}
ฟังก์ชั่นด้านบนนี้ควรจะเพียงพอ เพราะเท่าที่ฉันสามารถบอกได้รหัสที่สร้างโดย Android นั้นอยู่ในพันล้านดังนั้นนี่อาจจะกลับมา1
เป็นครั้งแรกและจะค่อนข้างเร็ว เพราะมันจะไม่วนลูปผ่าน 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 ที่ใช้ android: https://stackoverflow.com/a/13241629/693927
แก้ไข / แก้ไข: เพิ่งรู้ว่าฉันโง่ไปหมดบันทึก ฉันต้องเมา
ขณะนี้ไลบรารี 'Compat' ยังรองรับgenerateViewId()
วิธีการสำหรับระดับ API ก่อนหน้า 17
เพียงตรวจสอบให้แน่ใจว่าใช้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(); }
สิ่งนี้จะวนซ้ำไม่สิ้นสุดสำหรับระดับ api ที่เล็กกว่า 17 อุปกรณ์หรือไม่
เพื่อสร้างการใช้แบบฟอร์ม View Id API 17
setId(int)
ซึ่งจะสร้างความคุ้มค่าเหมาะสำหรับใช้ใน ค่านี้จะไม่ชนกับค่า ID ที่สร้างเวลาที่สร้างโดย aapt 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;
}
การใช้หมายเลขสุ่มทำให้ฉันมีโอกาสสูงที่จะได้รับรหัสเฉพาะในครั้งแรก
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();
}
findViewById
นั้นก็รับประกันว่ามุมมองไหนจะถูกส่งคืนถ้ามีมากกว่าหนึ่งอันที่มี ID เดียวกัน? เอกสารไม่ได้พูดถึงอะไรเลย