অ্যান্ড্রয়েড কার্সর পুনরাবৃত্তি করার সর্বোত্তম উপায় কোনটি?


291

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

Cursor cursor = db.rawQuery(...);
cursor.moveToFirst();
while (cursor.isAfterLast() == false) 
{
    ...
    cursor.moveToNext();
}
Cursor cursor = db.rawQuery(...);
for (boolean hasItem = cursor.moveToFirst(); 
     hasItem; 
     hasItem = cursor.moveToNext()) {
    ...
}
Cursor cursor = db.rawQuery(...);
if (cursor.moveToFirst()) {
    do {
        ...                 
    } while (cursor.moveToNext());
}

এগুলি আমার কাছে অত্যধিক দীর্ঘ-বায়ুযুক্ত বলে মনে হয়, প্রতিটি Cursorপদ্ধতিতে একাধিক কল রয়েছে । অবশ্যই একটি সুন্দর উপায় আছে?


1
এর উদ্দেশ্য কী ছিল? আপনি এটি পোস্ট করার এক মিনিটের মধ্যে নিজেই এটির উত্তর দিয়েছেন ...
বারাক

10
আমি এটি জিজ্ঞাসা করার সাথে সাথে উত্তর দিয়েছি ।
গ্রাহাম বোরল্যান্ড

1
আহ, এর আগে এই লিঙ্কটি কখনও দেখেনি। আপনার কাছে ইতিমধ্যে ইতিমধ্যে একটি উত্তর ছিল এমন কোনও প্রশ্ন জিজ্ঞাসা করার মতো বোকামি মনে হয়েছিল।
বারাক

5
@ বারাক: আমার মনে হয় তিনি দুর্দান্ত পোস্টটি স্থাপন করেছেন - এখন আমি কিছু করার কিছুটা সূক্ষ্ম উপায় জানি যা আমি অন্যথায় জানতাম না।
জর্জ

4
আমার কাছে এটি স্পষ্ট বলে মনে হয়েছে যে আপনি যে কেউ এসেছেন তাদের সহায়তা করতে আপনি এটি পোস্ট করেছেন। এর জন্য আপনাকে প্রপস এবং সহায়ক টিপটির জন্য ধন্যবাদ!
muttley91

উত্তর:


515

সবচেয়ে সহজ উপায় হ'ল:

while (cursor.moveToNext()) {
    ...
}

কার্সারটি প্রথম ফলাফলের সারির আগে শুরু হয় , সুতরাং প্রথম পুনরাবৃত্তির উপর এটি উপস্থিত থাকলে এটি প্রথম ফলাফলে চলে যায় । যদি কার্সারটি খালি থাকে, বা শেষ সারিটি ইতিমধ্যে প্রক্রিয়া করা হয়েছে, তবে লুপটি খুব সুন্দরভাবে প্রস্থান করবে।

অবশ্যই, কার্সারটি একবার সম্পন্ন করার পরে বন্ধ করতে ভুলবেন না, বিশেষত একটি finallyধারাতে।

Cursor cursor = db.rawQuery(...);
try {
    while (cursor.moveToNext()) {
        ...
    }
} finally {
    cursor.close();
}

আপনি যদি API 19+ টার্গেট করেন তবে আপনি সংস্থান-ব্যবহারগুলি ব্যবহার করতে পারেন।

try (Cursor cursor = db.rawQuery(...)) {
    while (cursor.moveToNext()) {
        ...
    }
}

19
সুতরাং আপনি যদি পূর্বে কোনও অভ্যাসগত অবস্থানে একটি কার্সার দিয়ে এই পুনরাবৃত্তিটি করতে চান, তবে আপনি কিছুক্ষণ লুপের আগে কার্সার.মোভটোপজিশন (-1) ব্যবহার করবেন?
স্যাম

43
এটি বন্ধ করতে ভুলবেন না!
সাইমন

13
একটি এসকিউএল ডাটাবেস কোয়েরি কখনই বাতিল হয় না। কোনও ফলাফল না পাওয়া গেলে এটি একটি খালি কার্সার ফিরিয়ে দেবে। কনটেন্টপ্রোভাইডার ক্যোয়ারীগুলি মাঝে মাঝে নালায় ফিরে আসতে পারে।
গ্রাহাম বোরল্যান্ড

8
কেবল কয়েক সেন্ট যুক্ত করার জন্য ... কার্সারে পুনরাবৃত্তি করার আগে মুভিটোফার্স্ট () কল করে কার্সারের ডেটা রয়েছে কিনা তা যাচাই করবেন না - আপনি প্রথম এন্ট্রি হারাবেন
এভারিন

47
যদি কোনও ব্যবহার করে থাকেন তবে CursorLoaderঅবশ্যই cursor.moveToPosition(-1)পুনরাবৃত্তি করার আগে আপনি কল করেছেন তা নিশ্চিত করুন , কারণ স্ক্রিনের ওরিয়েন্টেশন পরিবর্তনের সাথে সাথে লোডার কার্সারটিকে পুনরায় ব্যবহার করে। এই সমস্যাটি ট্র্যাক করে এক ঘন্টা ব্যয় করুন!
ভিকি চিজওয়ানি

111

কার্সারের মধ্য দিয়ে যাওয়ার জন্য আমি দেখতে সবচেয়ে ভাল উপায়টি হল:

Cursor cursor;
... //fill the cursor here

for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
    // do what you need with the cursor here
}

কার্সারটি পরে বন্ধ করতে ভুলবেন না

সম্পাদনা: প্রদত্ত সমাধানটি দুর্দান্ত যদি আপনার কোনও দায়িত্বে না এমন কোনও কার্সার পুনরায় করা দরকার। একটি ভাল উদাহরণটি হ'ল, যদি আপনি কোনও পদ্ধতিতে কার্সারটিকে আর্গুমেন্ট হিসাবে নিচ্ছেন এবং কার্সারের বর্তমান অবস্থান সম্পর্কে চিন্তা না করে আপনাকে একটি নির্দিষ্ট মানের জন্য কার্সারটি স্ক্যান করতে হবে।


8
কেন আপনি তিনটি ভিন্ন পদ্ধতি কল করবেন যখন আপনি কেবল একটি দিয়ে এটি করতে পারেন? কেন আপনি ভাল মনে করেন?
গ্রাহাম বোরল্যান্ড

11
আপনি যদি পূর্ব-বিদ্যমান কার্সারটি পুনরায় লোড করে থাকেন এবং আপনার পুনরাবৃত্তিটি শুরু থেকেই শুরু হয় তা নিশ্চিত করতে চাইলে এটি যাওয়ার নিরাপদতম উপায়।
মাইকেল ইলার্স স্মিথ 5'13

9
আমি একমত যে এটি সহজ বিকল্পের চেয়ে পরিষ্কার। আমি সাধারণত ব্রিভিটির কাছে স্পষ্টতার পক্ষে favor যখন লুপ সঙ্গে একই প্রকরণ - android.codota.com/scenarios/51891850da0a87eb5be3cc22/...
drorw

কার্সারগুলির সাথে আরও কিছুটা খেলে, আমি আমার উত্তর আপডেট করেছি। প্রদত্ত কোডটি নিশ্চিত যে কোনও কার্সর পুনরুক্ত করার সবচেয়ে কার্যকর উপায় নয় তবে এর ব্যবহারগুলি রয়েছে ages (সম্পাদনা দেখুন)
অ্যালেক্স স্টাইল

@ অ্যালেক্সস্টাইল হ্যাঁ, এটি সত্যই! এতে আমার বিচক্ষণতা বাঁচল!
আলেসান্দ্রো

45

আমি ঠিক তৃতীয় বিকল্পটি চিহ্নিত করতে চাই যা কার্সার শুরুর অবস্থানে না থাকলে এটিও কাজ করে:

if (cursor.moveToFirst()) {
    do {
        // do what you need with the cursor here
    } while (cursor.moveToNext());
}

1
একটি অপ্রয়োজনীয় চেক আছে। আপনি যদি + ডু-ওয়েল প্রতিস্থাপন করতে পারেন তবে গ্রহণযোগ্য সমাধান হিসাবে দেওয়া সহজ, যা আরও সহজ / আরও পঠনযোগ্য।
এমটিকে

6
@ এমটিকে না, এটি নিরর্থক নয়, এটাই মূল বিষয় - যদি কার্সারটি পুনরায় ব্যবহার করা হয় তবে এটি একটি অবস্থানে থাকতে পারে, তাই স্পষ্টভাবে মুভিটফর্স্টকে কল করার দরকার ছিল
মাইক রেপাস

লগিং সহ যদি আপনার অন্য কোনও বিবৃতি থাকে তবে এটি কেবলমাত্র কার্যকর; অন্যথায় গ্রাহাম বোরল্যান্ডের উত্তর আরও সংক্ষিপ্ত।
আরডিএস

5
ভিকি চিজওয়ানির মন্তব্য যেমন উল্লেখ করেছে, বাস্তব বিশ্বের ব্যবহারে গ্রাহাম বোরল্যান্ডের উত্তরটি অনিরাপদ এবং প্রয়োজন moveToPosition(-1)। সুতরাং উভয় উত্তর সমানভাবে বিবেচনাযুক্ত হিসাবে তাদের উভয় দুটি কার্সার কল রয়েছে। আমি মনে করি এই জবাবটি বোরল্যান্ডের উত্তরটি কেবলমাত্র বের করে দিয়েছে কারণ এর জন্য -1যাদু সংখ্যার প্রয়োজন হয় না ।
বেনিয়ামিন

আমি আসলে এটির ক্ষেত্রে এটি দরকারী বলে মনে করি আপনি এটি জানতে চেয়েছেন যে কার্সারের কোনও মূল্য ছিল না কারণ এটি সহজ এবং এখানে বিবৃতিতে অন্য কোনও যোগ করার জন্য এটি বোধগম্য।
চাকম

9

ফোরচ লুপ ব্যবহার সম্পর্কে কীভাবে:

Cursor cursor;
for (Cursor c : CursorUtils.iterate(cursor)) {
    //c.doSth()
}

তবে আমার সংস্করণকারীগুলির সংস্করণটি কম কুশল হওয়া উচিত তবে এটি স্বয়ংক্রিয়ভাবে কার্সারটি বন্ধ করে দেয়:

public class CursorUtils {
public static Iterable<Cursor> iterate(Cursor cursor) {
    return new IterableWithObject<Cursor>(cursor) {
        @Override
        public Iterator<Cursor> iterator() {
            return new IteratorWithObject<Cursor>(t) {
                @Override
                public boolean hasNext() {
                    t.moveToNext();
                    if (t.isAfterLast()) {
                        t.close();
                        return false;
                    }
                    return true;
                }
                @Override
                public Cursor next() {
                    return t;
                }
                @Override
                public void remove() {
                    throw new UnsupportedOperationException("CursorUtils : remove : ");
                }
                @Override
                protected void onCreate() {
                    t.moveToPosition(-1);
                }
            };
        }
    };
}

private static abstract class IteratorWithObject<T> implements Iterator<T> {
    protected T t;
    public IteratorWithObject(T t) {
        this.t = t;
        this.onCreate();
    }
    protected abstract void onCreate();
}

private static abstract class IterableWithObject<T> implements Iterable<T> {
    protected T t;
    public IterableWithObject(T t) {
        this.t = t;
    }
}
}

এটি একটি দুর্দান্ত শীতল সমাধান, তবে এটি Cursorলুপের প্রতিটি পুনরাবৃত্তিতে একই উদাহরণটি ব্যবহার করছে এমন সত্যটি লুকিয়ে রাখে ।
npace

8

নীচে আরও ভাল উপায় হতে পারে:

if (cursor.moveToFirst()) {
   while (!cursor.isAfterLast()) {
         //your code to implement
         cursor.moveToNext();
    }
}
cursor.close();

উপরের কোডটি নিশ্চিত করে যে এটি পুরো পুনরাবৃত্তির মধ্য দিয়ে যাবে এবং প্রথম এবং শেষ পুনরাবৃত্তিটি এড়ায় না।


6
import java.util.Iterator;
import android.database.Cursor;

public class IterableCursor implements Iterable<Cursor>, Iterator<Cursor> {
    Cursor cursor;
    int toVisit;
    public IterableCursor(Cursor cursor) {
        this.cursor = cursor;
        toVisit = cursor.getCount();
    }
    public Iterator<Cursor> iterator() {
        cursor.moveToPosition(-1);
        return this;
    }
    public boolean hasNext() {
        return toVisit>0;
    }
    public Cursor next() {
    //  if (!hasNext()) {
    //      throw new NoSuchElementException();
    //  }
        cursor.moveToNext();
        toVisit--;
        return cursor;
    }
    public void remove() {
        throw new UnsupportedOperationException();
    }
}

উদাহরণ কোড:

static void listAllPhones(Context context) {
    Cursor phones = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
    for (Cursor phone : new IterableCursor(phones)) {
        String name = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
        String phoneNumber = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
        Log.d("name=" + name + " phoneNumber=" + phoneNumber);
    }
    phones.close();
}

সুন্দর এবং কমপ্যাক্ট বাস্তবায়নের জন্য +1। ত্রুটির সমাধান সহ: iterator()এছাড়াও পুনঃগণনা করা উচিত toVisit = cursor.getCount();আমি ব্যবহার class IterableCursor<T extends Cursor> implements Iterable<T>, Iterator<T> {...করে একটি বর্গ যে পায় extends CursorWrapper implements MyInterfaceযেখানে MyInterface ডাটাবেসের বৈশিষ্ট্যের জন্য getters সংজ্ঞায়িত করে। এই পদ্ধতি আমি ভিত্তিক ইটারেটর <MyInterface> একটি কার্সার আছে
k3b

4

ডু / করার সময় সমাধানটি আরও মার্জিত, তবে আপনি যদি উপরে পোস্ট করা ঠিক যখন সলিউশনটি ব্যবহার করেন তবে মুভটোপজিশন (-1) ছাড়াই আপনি প্রথম উপাদানটি (কমপক্ষে যোগাযোগের অনুসন্ধানে) মিস করবেন।

আমার পরামর্শ:

if (cursor.getCount() > 0) {
    cursor.moveToPosition(-1);
    while (cursor.moveToNext()) {
          <do stuff>
    }
}

2
if (cursor.getCount() == 0)
  return;

cursor.moveToFirst();

while (!cursor.isAfterLast())
{
  // do something
  cursor.moveToNext();
}

cursor.close();

2

কার্সার ইন্টারফেস যে একটি প্রতিনিধিত্ব করে 2-dimensionalকোনো ডেটাবেসের টেবিল।

আপনি যখন SELECTবিবৃতি ব্যবহার করে কিছু তথ্য পুনরুদ্ধার করার চেষ্টা করেন , তখন ডাটাবেস 1 ম সর্দার অবজেক্ট তৈরি করে আপনার কাছে তার রেফারেন্স ফিরিয়ে দেয়।

এই ফিরে আসা রেফারেন্সের পয়েন্টারটি 0 তম অবস্থানটির দিকে নির্দেশ করছে যা অন্যথায় কার্সারের প্রথম অবস্থানের আগে বলা হয়, সুতরাং আপনি যখন কার্সার থেকে ডেটা পুনরুদ্ধার করতে চান তখন আপনাকে 1 ম রেকর্ডে স্থানান্তর করতে হবে যাতে আমাদের ব্যবহার করতে হবে moveToFirst

আপনি যখন কার্সারেmoveToFirst() পদ্ধতিটি চালু করেন তখন এটি কার্সার পয়েন্টারটিকে 1 ম স্থানে নিয়ে যায়। এখন আপনি 1 ম রেকর্ডে উপস্থিত ডেটা অ্যাক্সেস করতে পারেন

দেখার সেরা উপায়:

কার্সার কার্সার

for (cursor.moveToFirst(); 
     !cursor.isAfterLast();  
     cursor.moveToNext()) {
                  .........
     }

0

প্রাথমিকভাবে কার্সারটি প্রথম সারির শোতে নেই এটি ব্যবহার করে moveToNext()আপনি কার্সারটি পুনরাবৃত্তি করতে পারবেন যখন রেকর্ডের অস্তিত্ব থাকে না return false, তা না হলে return true,

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