I have a ViewPager which swipes between Fragments. I'm using a FragmentStatePagerAdapter to feed the Fragments to the ViewPager. If the user swipes left at a normal pace, and then swipes right very quickly, they can get the ViewPager into a weird state where it shows multiple Fragments.
For example, if the user is on Fragment A, then swipes left to Fragment B at a normal pace, and then quickly swipes right to go back to Fragment A, then on screen shows both Fragments A & B.
Anybody have any ideas on why this is happening or a good way to prevent it?
Here's what it looks like:
Here's my ViewPager definition in XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.company.views.CustomActionBar android:id="@+id/customActionBar" android:layout_width="match_parent" android:layout_height="@dimen/height_actionbar" android:layout_alignParentTop="true"/> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/customActionBar"/>
Also, I logged output from my onPageChangeListener() and noticed that when the ViewPager gets stuck in between views, it's reporting a positionOffset of 0. Here's what the ViewPager's values look like as it transitions from STATE_DRAGGING to STATE_SETTLING to STATE_IDLE when it lands in this weird state:
state = 0 prevState: 2 position: 1 positionOffset: 0.0
state = 1 prevState: 0 position: 1 positionOffset: 0.0
state = 2 prevState: 1 position: 1 positionOffset: 0.4069444
state = 0 prevState: 2 position: 2 positionOffset: 0.0
So it appears as if the ViewPager is reporting the wrong positionOffset back to me.
Full sample code Activity and Adapter:
public class ActivityBagelProfileViewer extends CustomAbstractFragmentActivity implements CustomActionBarContract, ListenerProgress, ListenerSync { public static final String EXTRA_BAGEL_INDEX = "BAGEL"; public static final int REQUEST_CODE_BAGEL_PROFILE_VIEWER = 4000; public static final int RESULT_GO_TO_PASS_FLOW = 12; public static final int RESULT_GO_TO_LIKE_FLOW = 14; public static final int RESULT_GO_TO_SEE_MORE_BAGELS = 16; private ViewPager mProfilesViewPager; private CustomActionBar mCustomActionBar; private int mViewPagerPosition; private DialogProgress mDialogProgress; private BagelViewPagerAdapter mAdapterBagelViewPager; private List<Bagel> mListBagels; @Override protected void onCreate(Bundle savedInstanceState) { Logger.d("ENTER"); super.onCreate(savedInstanceState); if (ManagerGive.IS_BRANCH_SESSION_OPEN == false) { ManagerGive.initializeBranchMetricsSession(); } setContentView(R.layout.activity_with_viewpager); mCustomActionBar = (CustomActionBar) findViewById(R.id.customActionBar); mCustomActionBar.setMenu(this); mProfilesViewPager = (ViewPager) findViewById(R.id.viewPager); if (getIntent().getExtras() != null) { mViewPagerPosition = getIntent().getExtras().getInt(EXTRA_BAGEL_INDEX, 0); } } @Override protected void onStop() { super.onStop(); ManagerGive.closeBranchMetricsSession(); } public void onIconClick(View view) { Logger.d("ENTER"); finishWithAnimation(); } private void finishWithAnimation() { setResult(RESULT_OK); finish(); overridePendingTransition(R.anim.slide_in_from_left, R.anim.slide_out_to_right); } @Override public void onBackPressed() { if (!super.handleBackPressedEvent()) { finishWithAnimation(); } } private void setupNewAdapter() { mListBagels = Bakery.getInstance().getManagerBagel().getCopyOfBagelsWithoutCurrent(); mAdapterBagelViewPager = new BagelViewPagerAdapter(getSupportFragmentManager(), mListBagels, this); mProfilesViewPager.setAdapter(mAdapterBagelViewPager); mProfilesViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { setActionBar(position); mViewPagerPosition = position; } @Override public void onPageScrollStateChanged(int state) { } }); mProfilesViewPager.setCurrentItem(mViewPagerPosition, false); } @Override protected void onResume() { Logger.d("ENTER"); super.onResume(); Bakery.getInstance().getManagerSyncData().addListener(this); if (mProfilesViewPager.getAdapter() == null) { Logger.d("Adapter null. Setting new adapter"); setupNewAdapter(); } else { if (mProfilesViewPager.getAdapter().getCount() != Bakery.getInstance().getManagerBagel().getCopyOfBagelsWithoutCurrent().size()) { Logger.d("Bagel list in Bakery changed size. Setting new adapter"); setupNewAdapter(); } } if (mListBagels.size() > 0) { setActionBar(mViewPagerPosition); mDialogProgress = new DialogProgress(this); } else { //kv Something has gone terribly wrong if we don't have any Bagels, just finish finish(); } } private void setActionBar(int bagelIndex) { Logger.d("bagelIndex=" + bagelIndex); Bagel bagel = mListBagels.get(bagelIndex); //kv If this is our current bagel and we haven't taken action yet, then show timer if (Bakery.getInstance().getManagerBagel().getCurrentBagel() == bagel && bagel.getAction() != Bagel.ACTION_LIKED && bagel.getAction() != Bagel.ACTION_PASSED) { Logger.d("Setting up #timer in action bar"); mCustomActionBar.startTimeLeftTimer(DateUtils.getMillisFromUtc(bagel.getEndDate()), this, new ListenerTimer() { @Override public void onTimerExpired() { Logger.d("ENTER"); Bakery.getInstance().getManagerSyncData().performSync(null, false); } }, mCustomActionBar.getTextViewTimeLeft(), R.string.timer_blank); mCustomActionBar.setLabel(R.string.time_left); mCustomActionBar.hideTitle(); } //kv Otherwise show date else { mCustomActionBar.setTitle(DateUtils.getLocalizedDateFromStringDate(bagel.getStartDate(), DateUtils.DATE_WITH_TIME_PATTERN)); mCustomActionBar.stopTimeLeftTimer(); mCustomActionBar.hideTimeLeft(); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(EXTRA_BAGEL_INDEX, mViewPagerPosition); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { Logger.d("ENTER"); super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState.containsKey(EXTRA_BAGEL_INDEX)) { mViewPagerPosition = savedInstanceState.getInt(EXTRA_BAGEL_INDEX); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Logger.d("requestCode=" + requestCode + ", resultCode=" + resultCode + ", data=" + data); switch (requestCode) { case ActivityBeanShop.REQUEST_CODE: if (resultCode == Activity.RESULT_OK && data != null) { //fp user purchased sufficient beans to resume their transaction PurchaseType interruptedPurchaseType = (PurchaseType) data.getSerializableExtra(ActivityBeanShop.EXTRA_PURCHASE_TYPE); switch (interruptedPurchaseType) { case BONUS_BAGEL: case OPEN_SESAME: case REMATCH: Bundle bundle = new Bundle(); bundle.putSerializable(ManagerPurchase.EXTRA_PURCHASE_TYPE, interruptedPurchaseType); ManagerEvents.notifyListeners(EventType.BEAN_TRANSACTION_FOR_FEATURE_UNLOCK_COMPLETE, bundle); Logger.d("Notified listeners about #purchase bean transaction, can now resume feature #purchase"); break; default: Logger.w("Unrecognized purchase type: " + interruptedPurchaseType.getItemName()); } } break; default: Logger.w("Could not recognize code: " + requestCode); } } @Override public int getTitleId() { return R.string.bagel_action_checked; } @Override public int getIconId() { return R.drawable.selector_icon_up; } @Override public void showProgress(int stringId) { mDialogProgress.setText(stringId); mDialogProgress.show(); } @Override public void dismissProgress() { ViewUtils.safelyDismissDialog(mDialogProgress); } public void setActionBar() { setActionBar(mViewPagerPosition); } @Override public void onSyncComplete() { Logger.d("ENTER"); mListBagels = Bakery.getInstance().getManagerBagel().getCopyOfBagelsWithoutCurrent(); mAdapterBagelViewPager.setBagels(mListBagels); } public boolean isShowingThisBagel(Bagel bagel) { Bagel currentlyShownBagel = mListBagels.get(mViewPagerPosition); return bagel == currentlyShownBagel; } private static class BagelViewPagerAdapter extends FragmentStatePagerAdapter { private List<Bagel> mBagels; private ListenerProgress mListenerProgress; public BagelViewPagerAdapter(FragmentManager fragmentManager, List<Bagel> bagels, ListenerProgress listenerProgress) { super(fragmentManager); Logger.d("bagels=" + bagels); this.mBagels = bagels; mListenerProgress = listenerProgress; } @Override public Fragment getItem(int i) { Logger.d("i=" + i); UserProfile myProfile = Bakery.getInstance().getManagerUserProfile().getMyOwnProfile(); FragmentProfile fragment = FragmentProfile.newInstance(mBagels.get(i), false, myProfile); fragment.setListenerProgress(mListenerProgress); return fragment; } @Override public int getCount() { return mBagels.size(); } public void setBagels(List<Bagel> bagels) { mBagels = bagels; notifyDataSetChanged(); } } }
And here's the XML layout code for the layout of each Fragment (had to cut some out b/c of SO char limit):
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/scrollView"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="-0.5dp" android:orientation="vertical" android:animateLayoutChanges="true" android:id="@+id/profile_top_container"> <!-- Photos section with pager/carousel --> <FrameLayout android:id="@+id/photoViewpagerContainer" android:layout_width="match_parent" android:layout_height="wrap_content"> <com.coffeemeetsbagel.views.CustomAsShitViewPager android:id="@+id/pager_profile_images" xmlns:android="http://schemas.android.com/apk/res/android" app:aspectRatio="@integer/photo_ratio_height_over_width" android:layout_width="match_parent" android:layout_height="wrap_content"/> <LinearLayout android:id="@+id/linearLayout_bulletsAndFriendsContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="bottom"> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/textView_stamp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" app:customFont="Raleway-Bold.ttf" android:layout_gravity="end" android:textSize="@dimen/text_stamp" android:paddingTop="@dimen/margin_large" android:layout_marginEnd="@dimen/margin_xxxxxsmall" android:layout_marginRight="@dimen/profile_margin_smaller"/> <!-- photo circle indicators --> <com.viewpagerindicator.CirclePageIndicator android:id="@+id/bullet_indicators" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/circle_indicator_margin_bottom" android:clickable="false" app:fillColor="@color/blue_cmb" app:pageColor="@color/gray_background" app:radius="@dimen/circle_indicator_radius" app:strokeWidth="0dp"/> <!-- container for mutual friends strip --> <RelativeLayout android:id="@+id/relativeLayout_mutual_friends_container" android:layout_width="match_parent" android:layout_height="@dimen/baseline_grid_component_touchable" android:background="@color/white_transparent" android:visibility="gone"> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/textView_mutual_friends_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_alignParentLeft="true" style="@style/profile_mutual_friends_text"/> <LinearLayout android:id="@+id/linearLayout_mutual_friends_icons" android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_marginEnd="@dimen/baseline_grid_small" android:layout_marginRight="@dimen/baseline_grid_small" android:layout_centerVertical="true"> <ImageView android:id="@+id/imageView_icon0" android:layout_width="@dimen/baseline_grid_component_touchable" android:layout_height="@dimen/baseline_grid_component_touchable" android:padding="@dimen/typography_smallest" android:background="@color/transparent" android:visibility="gone"/> <ImageView android:id="@+id/imageView_icon1" android:layout_width="@dimen/baseline_grid_component_touchable" android:layout_height="@dimen/baseline_grid_component_touchable" android:background="@color/transparent" android:padding="@dimen/typography_smallest" android:visibility="gone"/> <ImageView android:id="@+id/imageView_icon2" android:layout_width="@dimen/baseline_grid_component_touchable" android:layout_height="@dimen/baseline_grid_component_touchable" android:background="@color/transparent" android:padding="@dimen/typography_smallest" android:visibility="gone"/> </LinearLayout> </RelativeLayout> </LinearLayout> </FrameLayout> <!-- Buttons section with User Actions for pass / like--> <LinearLayout android:id="@+id/linearLayout_buttons_pass_like" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/baseline_grid_smaller" android:layout_marginLeft="@dimen/baseline_grid_small" android:layout_marginRight="@dimen/baseline_grid_small" android:layout_marginTop="@dimen/baseline_grid_medium" android:orientation="horizontal" android:visibility="gone"> <ImageView android:id="@+id/button_pass" android:layout_width="0dp" android:layout_height="@dimen/profile_action_button_height" android:layout_weight="1" android:background="@drawable/ripple_button_pass" android:clickable="true" android:src="@drawable/icon_pass_pressed" android:scaleType="center" android:layout_marginRight="@dimen/margin_small"/> <ImageView android:id="@+id/button_like" android:layout_width="0dp" android:layout_height="@dimen/profile_action_button_height" android:layout_weight="1" android:background="@drawable/ripple_button_like" android:clickable="true" android:src="@drawable/icon_like_pressed" android:scaleType="center" android:layout_marginLeft="@dimen/margin_small"/> </LinearLayout> <!-- Buttons section with User Actions for rematch / give--> <LinearLayout android:id="@+id/linearLayout_buttons_rematch_give" android:layout_width="match_parent" android:layout_height="@dimen/give_ten_button_height" android:layout_marginBottom="@dimen/baseline_grid_smaller" android:layout_marginLeft="@dimen/baseline_grid_small" android:layout_marginRight="@dimen/baseline_grid_small" android:layout_marginTop="@dimen/baseline_grid_medium" android:orientation="horizontal" android:gravity="center" android:visibility="gone"> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/textView_rematch" android:layout_width="@dimen/zero_dip" android:layout_height="match_parent" android:layout_marginRight="@dimen/give_take_button_margin_side" android:layout_weight="1" style="@style/button_give_take_rematch" android:text="@string/rematch"/> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/text_view_give_with_rematch" android:layout_width="@dimen/zero_dip" android:layout_weight="1" android:layout_height="match_parent" style="@style/button_give_take_rematch" android:text="@string/give"/> </LinearLayout> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/textView_they_like_you" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@drawable/icon_like_alert" android:drawablePadding="@dimen/margin_xxsmall" style="@style/profile_info_item_value" android:layout_marginLeft="@dimen/margin_med" android:paddingTop="@dimen/baseline_grid_smaller"/> <ViewStub android:id="@+id/viewStub_profile_feedback" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout="@layout/profile_feedback"/> <!-- Profile information table --> <!-- Name --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/profile_info_item_layout_margins" android:paddingTop="@dimen/baseline_grid_smaller" android:orientation="horizontal"> <com.coffeemeetsbagel.views.CustomTextView android:text="@string/profile_info_label_name" style="@style/profile_info_item_label" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/profile_info_value_name" style="@style/profile_info_item_value" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2"/> </LinearLayout> <!-- Age --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/profile_info_item_layout_margins" android:orientation="horizontal"> <com.coffeemeetsbagel.views.CustomTextView android:text="@string/profile_info_label_age" style="@style/profile_info_item_label" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/profile_info_value_age" style="@style/profile_info_item_value" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2"/> </LinearLayout> <!-- Location --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/profile_info_item_layout_margins" android:orientation="horizontal"> <com.coffeemeetsbagel.views.CustomTextView android:text="@string/location" style="@style/profile_info_item_label" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/profile_info_value_location" style="@style/profile_info_item_value" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2"/> </LinearLayout> <!-- Ethnicity --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/profile_info_item_layout_margins" android:orientation="horizontal"> <com.coffeemeetsbagel.views.CustomTextView android:text="@string/profile_info_label_ethnicity" style="@style/profile_info_item_label" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/profile_info_value_ethnicity" style="@style/profile_info_item_value" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2"/> </LinearLayout> <!-- Height --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/profile_info_item_layout_margins" android:orientation="horizontal"> <com.coffeemeetsbagel.views.CustomTextView android:text="@string/profile_info_label_height" style="@style/profile_info_item_label" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/profile_info_value_height" style="@style/profile_info_item_value" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2"/> </LinearLayout> <!-- Religion --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/profile_info_item_layout_margins" android:orientation="horizontal"> <com.coffeemeetsbagel.views.CustomTextView android:text="@string/profile_info_label_religion" style="@style/profile_info_item_label" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/profile_info_value_religion" style="@style/profile_info_item_value" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2"/> </LinearLayout> <!-- Occupation --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/profile_info_item_layout_margins" android:orientation="horizontal"> <com.coffeemeetsbagel.views.CustomTextView android:text="@string/profile_info_label_occupation" style="@style/profile_info_item_label" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <com.coffeemeetsbagel.views.CustomTextView android:id="@+id/profile_info_value_occupation" style="@style/profile_info_item_value" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2"/> </LinearLayout> <!-- Employer --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/profile_info_item_layout_margins" android:orientation="horizontal">
...
I've noticed that I see this issue if I have some animations given by the animateLayoutChanges. Just deactivating it in the xml file, prevents the pages to be stuck in the middle.
Try the following sample code and modify it as per your requirement(I guess your are loading the image on main UI thread and not caching it, its just a guess). In this code i am downloading and caching the images from the internet : Create a Activity class named SomeFragTest
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.app.ActivityManager; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.util.LruCache; import android.support.v4.view.ViewPager; import android.util.Log; import android.widget.ImageView; public class SomeFragTest extends FragmentActivity{ private LruCache<String, Bitmap> cache; private List<String> strings; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_layout); ViewPager mViewPager = (ViewPager)findViewById(R.id.viewPager); strings=new ArrayList<String>(); setData(); int memClass = ( ( ActivityManager )getSystemService( Context.ACTIVITY_SERVICE ) ).getMemoryClass(); int cacheSize = 1024 * 1024 * memClass / 8; cache=new LruCache<String, Bitmap>(cacheSize){ @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount()/1024; } }; mViewPager.setOffscreenPageLimit(strings.size()); mViewPager.setAdapter(new MyPageAdapter(getSupportFragmentManager())); } private void setData() { for (int i = 1; i <= 10; i++) { strings.add("http://dummyimage.com/600x400/000/0011ff.png&text="+i); } } public void loadBitmap(int position , ImageView imageView) { imageView.setImageResource(R.drawable.ic_launcher); imageView.setTag(strings.get(position)); BitmapDownloaderTask task = new BitmapDownloaderTask(imageView); task.execute(strings.get(position)); } class MyPageAdapter extends FragmentPagerAdapter { public MyPageAdapter(FragmentManager fm) { super(fm); // TODO Auto-generated constructor stub } @Override public Fragment getItem(int arg0) { Fragment fragment=new ChildFrag(); Bundle bundle=new Bundle(); bundle.putInt("POS", arg0); fragment.setArguments(bundle); return fragment; } @Override public int getCount() { return strings.size(); } } class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> { public String url; private final WeakReference<ImageView> imageViewReference; public BitmapDownloaderTask(ImageView imageView) { imageViewReference = new WeakReference<ImageView>(imageView); } @Override // Actual download method, run in the task thread protected Bitmap doInBackground(String... params) { // params comes from the execute() call: params[0] is the url. url=params[0]; if(cache.get(url)!=null){ Log.e("FROM ", "CACHE"); return cache.get(url); } return downloadBitmap(params[0]); } private Bitmap downloadBitmap(String url) { Log.e("FROM ", "URL"); HttpClient client=new DefaultHttpClient(); //final AndroidHttpClient client = AndroidHttpClient.newInstance("Android"); final HttpGet getRequest = new HttpGet(url); try { HttpResponse response = client.execute(getRequest); final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url); return null; } final HttpEntity entity = response.getEntity(); if (entity != null) { InputStream inputStream = null; try { inputStream = entity.getContent(); //final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); return decodeBitmapWithGiveSizeFromResource(inputStream); } finally { if (inputStream != null) { inputStream.close(); } entity.consumeContent(); } } } catch (Exception e) { // Could provide a more explicit error message for IOException or IllegalStateException getRequest.abort(); Log.w("ImageDownloader", "Error while retrieving bitmap from " + url); Log.e("ERROR", " " +e.getLocalizedMessage()); } finally { if (client != null) { //client.close(); } } return null; } /***************/ private void copy(InputStream inputStream,ByteArrayOutputStream arrayOutputStream) { byte[] buffer = new byte[1024]; int len; try { while ((len = inputStream.read(buffer)) > -1 ) { arrayOutputStream.write(buffer, 0, len); } arrayOutputStream.flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private Bitmap decodeBitmapWithGiveSizeFromResource(InputStream inputStream) { //BufferedInputStream bufferedInputStream=new BufferedInputStream(inputStream); final BitmapFactory.Options options = new BitmapFactory.Options(); ByteArrayOutputStream out = new ByteArrayOutputStream(); copy(inputStream,out); InputStream in2 = new ByteArrayInputStream(out.toByteArray()); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(inputStream, null, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; Bitmap bitmap=BitmapFactory.decodeStream(in2,null, options); try { inputStream.close(); in2.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return scaleDown(bitmap,false); } private Bitmap scaleDown(Bitmap realImage, boolean filter) { Bitmap newBitmap = Bitmap.createScaledBitmap(realImage, 100, 100, filter); Bitmap output = Bitmap.createBitmap(newBitmap.getWidth(), newBitmap .getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, newBitmap.getWidth(), newBitmap.getHeight()); final RectF rectF = new RectF(rect); final float roundPx = 10; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(newBitmap, rect, rect, paint); return output; } private int calculateInSampleSize(BitmapFactory.Options options) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > 100 || width > 100) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) >100 && (halfWidth / inSampleSize) >100) { inSampleSize *= 2; } } return inSampleSize; } @Override // Once the image is downloaded, associates it to the imageView protected void onPostExecute(Bitmap bitmap) { if (isCancelled()) { bitmap = null; } if (imageViewReference != null) { cache.put(url, bitmap); ImageView imageView = imageViewReference.get(); // BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); // Change bitmap only if this process is still associated with it if (((String)imageView.getTag()).equalsIgnoreCase(url)) { imageView.setImageBitmap(bitmap); } } } } }
After this create the xml for it, named activity_layout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
Now we have create the Fragment class that we want to inflate in the ViewPager: Create a class named ChildFrag as follows
import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; public class ChildFrag extends Fragment { private int index; private ImageView imageView; @Override @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragtest, container, false); index = getArguments().getInt("POS"); ((TextView) view.findViewById(R.id.textView1)).setText("" + index); imageView = (ImageView) view.findViewById(R.id.imageView1); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ((SomeFragTest) getActivity()).loadBitmap(index, imageView); } }
Now we have create the xml for the fragment as fragtest:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Large Text" android:textAppearance="?android:attr/textAppearanceLarge" /> <ImageView android:id="@+id/imageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /> </LinearLayout>
Add the following permission in the AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With