অ্যান্ড্রয়েড: ভিউ.সেটআইডি (ইন আইডি) প্রোগ্রামগতভাবে - কীভাবে আইডি সংঘাত এড়ানো যায়?


334

আমি টেক্সটভিউগুলিকে প্রোগ্রামিং হিসাবে একটি লুপে যুক্ত করছি এবং সেগুলি একটি অ্যারেলিস্টে যুক্ত করছি।

আমি কীভাবে ব্যবহার করব TextView.setId(int id)? আমি কোন পূর্ণসংখ্যা আইডি নিয়ে এসেছি যাতে এটি অন্যান্য আইডির সাথে বিরোধ না করে?

উত্তর:


146

Viewডকুমেন্টেশন অনুযায়ী

সনাক্তকারীর এই ভিউয়ের শ্রেণিবিন্যাসে অনন্য হতে হবে না। সনাক্তকারী একটি ধনাত্মক সংখ্যা হওয়া উচিত।

সুতরাং আপনি আপনার পছন্দ মতো কোনও ইতিবাচক পূর্ণসংখ্যা ব্যবহার করতে পারেন তবে এই ক্ষেত্রে সমতুল্য আইডির সাথে কিছু মতামত থাকতে পারে। আপনি যদি setTagকিছু মূল বিষয়বস্তুতে কলকরণের শ্রেণিবিন্যাসের কিছু ভিউ সন্ধান করতে চান তবে তা কার্যকর হতে পারে।


2
আকর্ষণীয়, আমি জানতাম না যে আইডিগুলির অনন্য হওয়া দরকার? তাহলে findViewByIdকোনও গ্যারান্টি দেয় না কি একই আইডির সাথে একাধিক যদি থাকে তবে কোন ভিউটি ফিরে আসে? দস্তাবেজগুলি কিছুই উল্লেখ করে না।
ম্যাথিয়াস

26
আমি মনে করি ডকগুলি এ সম্পর্কে কিছু উল্লেখ করেছে। একই শ্রেণিবিন্যাসে যদি আপনার একই আইডির সাথে মতামত থাকে তবে findViewByIdএটি খুঁজে পাওয়া প্রথমটি ফিরিয়ে দেবে।
কানদা 7'12

2
@ ড্যানিওয়াই আমি নিশ্চিত যে আপনি কী বলতে চাইছেন তা সঠিকভাবে বুঝতে পারছি কিনা not আমি যা বলতে চেষ্টা ছিল যে লেআউট সাথে সেট যদি setContentView()এর, বলে একই আইডি নম্বরে তাদের আইডি সেট দিয়ে 10 মতামত দিন হয়েছে একই অনুক্রমের , তারপর একটি কল findViewById([repeated_id])যে এক পুনরাবৃত্তি আইডি সহ প্রথম দৃশ্য সেট ফিরে আসবে। যে আমি বোঝানো কি.
কানদা

51
-1 আমি এই উত্তরের সাথে একমত নই কারণ অন-সেভইনস্ট্যান্সস্টেট এবং অনরেস্টোরইন্সট্যান্সস্টেটের দর্শনক্রমক্রমের অবস্থা সংরক্ষণ / পুনরুদ্ধার করতে সক্ষম হওয়ার জন্য একটি অনন্য আইডি প্রয়োজন। দুটি মতামতের যদি একই আইডি থাকে, তবে তাদের মধ্যে একটির অবস্থা হারিয়ে যাবে। সুতরাং আপনি যদি ভিউ স্টেটটি সংরক্ষণ না করেন তবে আপনার নিজের ডুপ্লিকেট আইডি থাকা ভাল ধারণা নয়।
ইমানুয়েল মোকলিন

3
আইডি অনন্য হওয়া উচিতএপিআই স্তরের 17 থেকে শুরু করে ভিউ ক্লাসে একটি স্ট্যাটিক পদ্ধতি রয়েছে যা এভিড আইডি হিসাবে এটি ব্যবহার করতে একটি এলোমেলো আইডি উত্পন্ন করে। এই পদ্ধতিটি নিশ্চিত করে যে উত্পন্ন আইডিটি নির্মাণের সময় অপ্ট সরঞ্জাম দ্বারা ইতিমধ্যে তৈরি করা অন্য কোনও ভিউ আইডিটির সাথে সংঘর্ষে নেমে না যায়। বিকাশকারী.অ্যান্ড্রয়েড.
মাহমুদ

576

১ level এবং ততোধিক স্তরের এপিআই স্তর থেকে আপনি কল করতে পারেন: দেখুন.জেনারেটভিউআইডি ()

তারপরে View.setId (int) ব্যবহার করুন ।

যদি আপনার অ্যাপ্লিকেশনটি এপিআই স্তরের চেয়ে 17 টির চেয়ে কম টার্গেট করা থাকে তবে ভিউকম্প্যাট.জেনারেটভিউ আইডি () ব্যবহার করুন


2
আমি এটিকে আমার উত্স কোডে রেখেছি কারণ আমরা নিম্ন API স্তরের সমর্থন করতে চাই। এটি কাজ করছে তবে অসীম লুপটি কোনও ভাল অনুশীলন নয়।
এসএক্সসি

5
@ সিমোনক্সিন চেং অসীম লুপগুলি একটি সাধারণ প্যাটার্ন যা অ ব্লকিং অ্যালগরিদমে ব্যবহৃত হয়। উদাহরণস্বরূপ AtomicIntegerপদ্ধতি বাস্তবায়নের উপর নজর রাখুন ।
আইডলন

7
দুর্দান্ত কাজ! একটি নোট: আমার পরীক্ষাগুলির উপর ভিত্তি করে, আপনাকে বিদ্যমান লেআউটে ভিউ যুক্ত করার আগে আপনাকে অবশ্যই সেটআইডি () কল করতে হবে, না হলে অনক্লিকলিস্টনার সঠিকভাবে কাজ করবে না।
লুক

4
আপনাকে ধন্যবাদ খুব ছোট হবে তবে আপনাকে ধন্যবাদ। প্রশ্ন, যা for(;;)আমি এর আগে কখনও দেখিনি। এটাকে কী বলা হয়?
আগ্রাসী

5
@ অ্যাগ্রেসার: এটি লুপের জন্য ফাঁকা।
sid_09

142

আপনি R.idকোনও আইএমএল রিসোর্স ফাইল ব্যবহার করে ক্লাসে আইডি সেট করতে পারেন এবং সংকলনের সময় অ্যান্ড্রয়েড এসডিকে তাদের অনন্য মূল্য দিতে দিন।

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

20
যখন আমার কাছে অজানা সংখ্যক উপাদান থাকবে তখন আমি এইডগুলি বরাদ্দ করব এটি কাজ করে না।
44-এ হাঁস মুচছে

1
@ মুভিংডাক আমি জানি এটি এক বছর দেরীতে, তবে যখন আমাকে রান অ্যাসিডে অজানা সংখ্যক উপাদান সহ অনন্য আইডি নির্ধারণ করতে হবে তখন আমি কেবল ব্যবহার করি "int currentId = 1000; whateverView.setId(currentId++);- যা প্রতিটি সময় currentId++ব্যবহার করা হয় আইডিটি বাড়িয়ে তোলে, একটি অনন্য আইডি নিশ্চিত করে আমি সংরক্ষণ করতে পারি পরে অ্যাক্সেসের জন্য আমার অ্যারেলিস্টে আইডি।
মাইক ম্যাক SAT

3
@ মাইকিনস্যাট: এটি কেবল গ্যারান্টি দেয় যে তারা নিজেদের মধ্যে অনন্য। এটি এটি তৈরি করে না "সুতরাং এটি অন্যান্য আইডির সাথে বিরোধ করে না", যা প্রশ্নের মূল অংশ।
মিনিটে হাঁসকে মোচ দেওয়া হচ্ছে

1
এটি বিজয়ী উত্তর কারণ অন্যরা অ্যান্ড্রয়েড স্টুডিওর কোড বিশ্লেষণ সরঞ্জামকে একটি এস --- ফিট দিয়েছিল এবং আমার এমন একটি আইডি দরকার যা পরীক্ষাগুলি অন্য ভেরিয়েবলটি যুক্ত না করেই জানে। তবে অ্যাড <resources>
ফিলিপ

62

এছাড়াও আপনি নির্ধারণ করতে পারেন ids.xmlমধ্যে res/values। আপনি অ্যান্ড্রয়েডের নমুনা কোডে একটি সঠিক উদাহরণ দেখতে পাবেন।

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

15
এখানে এই পদ্ধতির সঙ্গে একটি উত্তর stackoverflow.com/questions/3216294/...
Ixx

রেফারেন্সের জন্য, আমি ফাইলটি খুঁজে পেয়েছি: /sample/android-15/ApiDemos/src/com/example/android/apis/view/RadioGroup1.java
টেলর


25

এটি আমার পক্ষে কাজ করে:

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

এটি কিছুটা জটিল তবে আমি বাজি ধরব এটি কার্যকর হবে। মাল্টিথ্রেডেড পরিবেশে বিশ্বব্যাপী ভেরিয়েবলগুলি ব্যবহার করা অবশ্যই কোনও দিন অবশ্যই ব্যর্থ হবে, বিশেষত একাধিক কোর সহ।
মার্টিনাস

3
এছাড়াও, জটিল লেআউটগুলির জন্য এটি সম্ভবত ধীর নয়?
ড্যানিয়েল রদ্রিগেজ

15
findViewById()একটি মন্থর অপারেশন। পদ্ধতির কাজ, কিন্তু কর্মক্ষমতা ব্যয়।
কিরিল আলেকসান্দ্রভ

10

(এটি দ্বিধাগ্রস্থ উত্তর দেওয়ার জন্য একটি মন্তব্য ছিল তবে এটি অনেক দীর্ঘ হয়েছে ... হি)

অবশ্যই এখানে একটি স্ট্যাটিক প্রয়োজন হয় না। আপনি স্থিতিশীল পরিবর্তে, সংরক্ষণ করার জন্য SharedPreferences ব্যবহার করতে পারেন। যেভাবেই হোক, কারণটি হ'ল বর্তমান অগ্রগতিটি সংরক্ষণ করা যাতে জটিল লেআউটের জন্য এটি খুব ধীর না হয়। কারণ, বাস্তবে, এটির একবার ব্যবহার করার পরে এটি পরে দ্রুত হবে। যাইহোক, আমি এটি করার একটি ভাল উপায় বলে মনে করি না কারণ যদি আপনাকে আবার আপনার পর্দা পুনর্নির্মাণ করতে হয় তবে (বলুনonCreate আবার বলা হয়), তবে আপনি সম্ভবত স্থিরতার প্রয়োজনীয়তা বাদ দিয়ে কোনওভাবেই শুরু থেকে শুরু করতে চান। সুতরাং, এটি স্থির পরিবর্তে একটি উদাহরণ পরিবর্তনশীল করুন।

এখানে একটি ছোট সংস্করণ দেওয়া হয়েছে যা কিছুটা দ্রুত চালিত হয় এবং এটি পড়তে আরও সহজ হতে পারে:

int fID = 0;

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

উপরের এই ফাংশনটি পর্যাপ্ত হওয়া উচিত। কারণ, যতদূর আমি বলতে পারি, অ্যান্ড্রয়েড-উত্পাদিত আইডিগুলি বিলিয়নে রয়েছে, সুতরাং এটি সম্ভবত 1প্রথমবারে ফিরে আসবে এবং সর্বদা বেশ দ্রুত হবে। কারণ, এটি বাস্তবে অব্যবহৃত কোনও সন্ধানের জন্য ব্যবহৃত আইডিটি শেষ করে দেবে না। তবে লুপটি হ'ল সেখানে এটি আসলে একটি ব্যবহৃত আইডি হবে।

তবে, আপনি যদি এখনও আপনার অ্যাপ্লিকেশনটির পরবর্তী বিনোদনগুলির মধ্যে অগ্রগতিটি সংরক্ষণ করতে চান এবং স্থিতিশীল ব্যবহার এড়াতে চান। এখানে 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;
}

অনুরূপ প্রশ্নের এই উত্তরটি আপনাকে অ্যান্ড্রয়েড সহ আইডি সম্পর্কে যা জানা দরকার তা আপনাকে জানাতে হবে: https://stackoverflow.com/a/13241629/693927

সম্পাদনা / ফিক্স: ঠিক বুঝতে পেরেছি যে আমি পুরোপুরি সংরক্ষণকে এগিয়ে নিয়েছি। আমি অবশ্যই মাতাল ছিলাম।


1
এটি শীর্ষ উত্তর হওয়া উচিত। ++ কীওয়ার্ড এবং খালি বিবৃতিগুলির দুর্দান্ত ব্যবহার;)
অ্যারন গিলিয়ন

9

'কমপ্যাট' লাইব্রেরি এখন generateViewId()17 স্তরের পূর্ববর্তী স্তরের জন্য পদ্ধতিটিকে সমর্থন করে ।

কেবল Compatযে লাইব্রেরির একটি সংস্করণ রয়েছে তা নিশ্চিত করে নিন27.1.0+

উদাহরণস্বরূপ, আপনার build.gradleফাইলে, রাখুন:

implementation 'com.android.support:appcompat-v7:27.1.1

তারপরে আপনি ক্লাসের পরিবর্তে ক্লাস generateViewId()থেকে নিম্নলিখিতটি অনুসরণ করতে পারেন:ViewCompatView

//Will assign a unique ID myView.id = ViewCompat.generateViewId()

শুভ কোডিং!


6

@Fantomlimb এর উত্তরে কেবল একটি সংযোজন,

যদিও View.generateViewId()এপিআই স্তর> = 17 প্রয়োজন,
এই সরঞ্জামটি সমস্ত 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();
        }

    }
}

@ কনই কোড স্নিপেট for (;;) { … }অ্যান্ড্রয়েড উত্স কোড থেকে আসে।
কল্পনা

আমার বোধগম্যতা অনুসারে সমস্ত উত্পন্ন আইডি 0x01000000 number0xffffffff নম্বর স্থানটি দখল করে, তাই আপনি অ-সংঘর্ষের নিশ্চয়তা পেয়েছেন তবে আমি এটি কোথায় পড়েছি তা মনে করতে পারছি না।
অ্যান্ড্রু ওয়াইল্ড

কীভাবে পুনরায় সেট করবেন ..generateViewId()
reegan29

@ একনির একটি পয়েন্ট রয়েছে, এটি ভিউ ক্লাসের মধ্যে উত্পন্ন আইডির সাথে সংঘর্ষ করতে পারে। আমার উত্তর দেখুন :)
গীত

else { return View.generateViewId(); }এটি 17 ডিভাইসের চেয়ে ছোট এপিআই স্তরের জন্য অসীম লুপে যাবে?
ওকরাকোজে

3

পরিবর্তনশীল আইডি ফর্ম এপিআই 17 ব্যবহারের উত্পন্ন করতে

generateViewId ()

যা ব্যবহারের জন্য উপযুক্ত মান উত্পন্ন করবে setId(int)। এই মানটি অ্যাডের জন্য বিল্ড টাইমে উত্পন্ন আইডি মানগুলির সাথে সংঘর্ষ করবে না R.id


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

1

আমি ব্যবহার করি:

public synchronized int generateViewId() {
    Random rand = new Random();
    int id;
    while (findViewById(id = rand.nextInt(Integer.MAX_VALUE) + 1) != null);
    return id;
}

এলোমেলো নম্বর ব্যবহার করে আমার সর্বদা প্রথম প্রয়াসে অনন্য আইডি পাওয়ার বিশাল সুযোগ থাকে।


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

আপনার উত্তরটির মূল্য নির্ধারণ করতে ভবিষ্যতের দর্শকদের কাছে এটি স্পষ্টরূপে আপনার উত্তরে যথাযথ বিবরণ যুক্ত করুন। কোড-কেবল উত্তরগুলি ভ্রান্ত হয় এবং পর্যালোচনা চলাকালীন মোছা যায়। ধন্যবাদ!
Luís ক্রুজ

-1

আমার পছন্দ:

// Method that could us an unique id

    int getUniqueId(){
        return (int)    
                SystemClock.currentThreadTimeMillis();    
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.