একটি ইমেজ গ্যালারির বিস্তারিত ভিউ নেভিগেট করতে swipe view pattern একটি চমৎকার উপায়। একটি PagerAdapter দ্বারা সমর্থিত একটি ViewPager ব্যবহার আপনি এই প্যাটার্ন বাস্তবায়ন করতে পারেন। কিন্তু এর চেয়ে বেশী উপযুক্ত ব্যাকিং দেয়া অ্যাডাপটর হচ্ছে সাবক্লাস FragmentStatePagerAdapter যা ViewPager এর মধ্যে Fragments এর স্টেট স্বয়ংক্রিয়ভাবে ধ্বংস এবং সেভ করে যেভাবে তারা অফ-স্ক্রিন দৃশ্যমান করে, মেমরী ব্যবহার নীচে রাখে।
নোট: আপনার যদি অল্প সংখ্যক ইমেজ থাকে এবং আপনি যদি আত্মবিশ্বাসি হোন যে সবগুলোই অ্যাপলিকেশন মেমরী সীমার মধ্যে ফিট করবে, তাহলে একটি নিয়মিত PagerAdaptere বা FragmentPagerAdapter ব্যবহার করাটা অধিক যুক্তিযুক্ত হবে।
এখানে ImageView চিলড্রেন সহকারে একটি ViewPager এর বাস্তাবায়ন আছে। মেইন একটিভিটি ViewPager এবং অ্যাডাপটর ধারন করে:
public class ImageDetailActivity extends FragmentActivity {
public static final String EXTRA_IMAGE = "extra_image";
private ImagePagerAdapter mAdapter;
private ViewPager mPager;
// A static dataset to back the ViewPager adapter
public final static Integer[] imageResIds = new Integer[] {
R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_detail_pager); // Contains just a ViewPager
mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}
public static class ImagePagerAdapter extends FragmentStatePagerAdapter {
private final int mSize;
public ImagePagerAdapter(FragmentManager fm, int size) {
super(fm);
mSize = size;
}
@Override
public int getCount() {
return mSize;
}
@Override
public Fragment getItem(int position) {
return ImageDetailFragment.newInstance(position);
}
}
}
এখানে বিস্তারিত Fragment এর একটি বাস্তবায়ন আছে যা imageView চিলড্রেন ধারন করে। এটা মনে হতে পারে একটি পুরাপুরি যুক্তিসংগত অ্যাপ্রোচ, কিন্তু আপনি কি এই বাস্তবায়নের ড্রব্যাক দেখতে পাচ্ছে? এটা কীভাবে উন্নত হবে?
public class ImageDetailFragment extends Fragment {
private static final String IMAGE_DATA_EXTRA = "resId";
private int mImageNum;
private ImageView mImageView;
static ImageDetailFragment newInstance(int imageNum) {
final ImageDetailFragment f = new ImageDetailFragment();
final Bundle args = new Bundle();
args.putInt(IMAGE_DATA_EXTRA, imageNum);
f.setArguments(args);
return f;
}
// Empty constructor, required as per Fragment docs
public ImageDetailFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mImageNum = getArguments() != null ? getArguments().getInt(IMAGE_DATA_EXTRA) : -1;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// image_detail_fragment.xml contains just an ImageView
final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
mImageView = (ImageView) v.findViewById(R.id.imageView);
return v;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final int resId = ImageDetailActivity.imageResIds[mImageNum];
mImageView.setImageResource(resId); // Load image into ImageView
}
}
আশা করা যায় যে আপনি এই ইস্যুটি লক্ষ্য করেছেন: ইমেজ ইউআই থ্রেডে রিসোর্স থেকে পড়া হচ্ছে. যা একটি অ্যাপলিকেশনকে ঝুলে থাকা বা জোর পূর্বক বন্ধ হয়ে যাওয়ার দিকে নিয়ে যায়। Processing Bitmaps Off the UI Thread অনূশীলনীতে যেভাবে আলোচনা করা হয়েছে সেভাবে একটি AsyncTask ব্যবহার, একটি ব্যাকগ্রাউন্ড থ্রেডে ইমেজ লোড এবং প্রসেস করতে করানোটা সোজাসাপ্টা:
public class ImageDetailActivity extends FragmentActivity {
...
public void loadBitmap(int resId, ImageView imageView) {
mImageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
task.execute(resId);
}
... // include BitmapWorkerTask class
}
public class ImageDetailFragment extends Fragment {
...
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (ImageDetailActivity.class.isInstance(getActivity())) {
final int resId = ImageDetailActivity.imageResIds[mImageNum];
// Call out to ImageDetailActivity to load the bitmap in a background thread
((ImageDetailActivity) getActivity()).loadBitmap(resId, mImageView);
}
}
}
যে কোন অতিরক্তি প্রসেস (যেমন, নেটওয়ার্ক থেকে ইমেজ রিসাইজ করা বা নিয়ে আসা) মেইন ইউআই এর রেসপনসিভনেস কে কোনভাবে প্রভাবিত না করইে BitmapWorkerTask এর মধ্যে সংঘটিত করতে পারে। যদি ব্যাকগ্রাউন্ড থ্রেড সরাসরি ডিস্ক থেকে একটি ইমেজ লোড করার চাইতেও বেশী কিছু করে, এটা একটি মেমরী এবং /বা ডিস্ক ক্যাশে যুক্ত করে লাভবান হতে পারে, যেভাবে Caching Bitmaps অনুশীলনীতে আলোচনা করা হয়েছে। এখানে একটি মেমরী ক্যাশের অতিরিক্ত পরিবর্তন দেয়া আছে:
public class ImageDetailActivity extends FragmentActivity {
...
private LruCache<String, Bitmap> mMemoryCache;
@Override
public void onCreate(Bundle savedInstanceState) {
...
// initialize LruCache as per Use a Memory Cache section
}
public void loadBitmap(int resId, ImageView imageView) {
final String imageKey = String.valueOf(resId);
final Bitmap bitmap = mMemoryCache.get(imageKey);
if (bitmap != null) {
mImageView.setImageBitmap(bitmap);
} else {
mImageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
task.execute(resId);
}
}
... // include updated BitmapWorkerTask from Use a Memory Cache section
}
সকল অংশ একসাথে করা ন্যুনতম লোডিং ল্যাটেন্সি (কোন কিছু প্রসেস করার সময়কাল) এবং আপনার ইমেজে যতটুকু দরকার সেই মতে কম বা বেশী ব্যাকগ্রাউন্ড প্রসেসিং করার সামর্থ সহ আপনাকে একটি রেসপনসিভ ViewPager বাস্তবায়ন প্রদান করবে।