বাংলায় অ্যান্ড্রয়েড সহায়িকা - Bangla Android Guide

কনকারেন্সি চালনা করা

কমন ভিউ কম্পোনেন্ট যেমন ListView এবং GridView অন্য ইস্যু কে শুরু করে যখন AsyncTaskw দিয়ে কনজাঙ্কশনে ব্যবহার করা হয় যেভাবে পূর্ববর্তী সেকশনে দেখানো হয়েছে। মেমরীর সাথে সুসংগঠিত হওয়ার জন্য, এই কম্পোনেন্ট গুলো চাইল্ড ভিউকে ইউজার স্ক্রলের মতো রিসাইকেল করে। যদি প্রতিটা চাইল্ড ভিউ একটি AsyncTask সক্রিয় করে, এখানে কোন নিশ্চয়তা নেই যে যখন এটা শেষ হবে, সহায়তাকারী ভিউ অন্য চাইল্ড ভিউ এ ব্যবহারের জন্য ইতিমধ্যে রিসাইকেল হয় নাই। এছাড়াও, এখানে কোন নিশ্চয়তা নেই যে বিন্যাস যার মধ্যে সিঙক্রোনাস এর কাজ শুরু হয় সেটা সেই বিন্যাস যা তারা সম্পূর্ন করে।

ব্লগ স্পট Multithreading for Performance (http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html) কনকারেন্সি নিয়ে কাজ করা বিষয়ে বিস্তারিত আলোচনা করেছে, এবং একটি সমাধান প্রস্তাব করে যেখানে ImageView একটি রেফারেন্স সদ্য AsyncTask এ স্টোর করে যাকে পরবর্তীতে চেক করা হয় যখন কাজ শেষ হয়। একটি সমপর্যায়ের মেথড ব্যবহার করা, AsyncTask পূর্ববতী সেকশন থেকে একটি সমরূপ বৈশিষ্ট অনুসরন করে AsyncTask সম্প্রসারিত হতে পারে।

ওয়ার্কার টাস্কে ফিরে একটি রেফারেন্স স্টোর করতে একটি নিবেদিত Drawable সাবক্লাস তৈরী করুন। এক্ষেত্রে একটি BitmapDrawable ব্যবহার করা হয় যাতে একটি প্লেস হোল্ডার ইমেজ ImageView এর মধ্যে প্রদর্শিত হতে পারে যখন কাজটি সম্পন্ন হবে:

static class AsyncDrawable extends BitmapDrawable {
    private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

    public AsyncDrawable(Resources res, Bitmap bitmap,
            BitmapWorkerTask bitmapWorkerTask) {
        super(res, bitmap);
        bitmapWorkerTaskReference =
            new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
    }

    public BitmapWorkerTask getBitmapWorkerTask() {
        return bitmapWorkerTaskReference.get();
    }
}

BitmapWorkerTask সম্পাদন করার পূর্বে, আপনি একটি AsyncDrawable তৈরী করেন এবং এটাকে টার্গেট ImageView এ সংযুক্ত করেন:

public void loadBitmap(int resId, ImageView imageView) {
    if (cancelPotentialWork(resId, imageView)) {
        final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
        final AsyncDrawable asyncDrawable =
                new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
        imageView.setImageDrawable(asyncDrawable);
        task.execute(resId);
    }
}

কোড স্যাম্পল এর মধ্যে রেফারেন্স করা cancelPotentialWork মেথড উপরে চেক করে যদি অন্য রানিং কাজ ImageView এর সাথে ইতমধ্যে যুক্ত হয়। যদি তাই হয়, cancel()কল করার মাধ্যমে পূর্ববর্তী কাজ ক্যানসেল করার প্রচেষ্টা চালানো হয়। খুব কম ক্ষেত্রে নতুন টাস্ক ডাটা বিদ্যমান টাস্ক চেক করে এবং আর কিছুই ঘটার প্রয়োজন হয় না। এখানে cancelPotentialWork: এর বাস্তবায়ন আছে:

public static boolean cancelPotentialWork(int data, ImageView imageView) {
    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

    if (bitmapWorkerTask != null) {
        final int bitmapData = bitmapWorkerTask.data;
        if (bitmapData != data) {
            // Cancel previous task
            bitmapWorkerTask.cancel(true);
        } else {
            // The same work is already in progress
            return false;
        }
    }
    // No task associated with the ImageView, or an existing task was cancelled
    return true;
}

একটি সাহাজ্যকারী মেথড, getBitmapWorkerTask(), উপরে ব্যবহার করা হয়েছে একটি বিশেষ ওসধমবঠরবএির সাথে যুক্ত কাজকে পূণরুদ্ধার করতে:

private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
   if (imageView != null) {
       final Drawable drawable = imageView.getDrawable();
       if (drawable instanceof AsyncDrawable) {
           final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
           return asyncDrawable.getBitmapWorkerTask();
       }
    }
    return null;
}

শেষ ধাপ হচ্ছে BitmapWorkerTask এ onPostExecute()আপডেট করা যাতে এটা চেক করতে পারে কাজটি ক্যানসেল হয়েছে কিনা এবং চলতি কাজটি ImageView এর সাথে সম্পর্কিত এককটি ম্যাচ করেছে কিনা:

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    ...

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            final BitmapWorkerTask bitmapWorkerTask =
                    getBitmapWorkerTask(imageView);
            if (this == bitmapWorkerTask && imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

এই বাস্তাবায়ন এখন ListView এবং GridView কম্পোনেন্ট একই সাথে অন্য কম্পোনেন্টে ব্যবহার করার জন্য উপযুক্ত যা তাদের চাইল্ড ভিউ রিসাইকেল করে। সাধারনভাবে loadBitmap কল করুন যেখানে আপনি স্বাভাবিকভাবে আপনার ImageView এ একটি ইমেজ সেট করেছেন। উদাহরণস্বরূপ, একটি getView বাস্তবায়নের মধ্যে এটা ব্যাকিং অ্যাডাপ্টরের getView() মেথডের মধ্যে হতে পারে।