Reputation: 41129
I have a view pager in which each page is a custom view ( ...and not a Fragment
) that I'm inflating using a LayoutInflator
. Each custom view has an ImageView
inside it that is populated with an image from web using the Glide
library.
My task is while the user scrolls throw the view pager each time he changes pages I need to retrieve the Bitmap
that is populating the currently shown ImageView
.
I tried using the set the OnPageChangeListener
on the view pager and use the onPageSelected
method to get the current view using the viewPager.getChildAt()
method or viewPager.getFocusedChild()
.
Here is the code:
Activity:
public class TimelineMomentActivity extends ActivityBase implements ViewPager.OnPageChangeListener, View.OnClickListener,
TimelineCommentsGetRequest.Callback, CreativeHandler.CreativeHandleCallback {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppInstance.sharedInstance().getBus().register(this);
mShouldSaveToDB = AppInstance.sharedInstance().isSelf();
mStory = getIntent().getParcelableExtra(StoryDB.KEY_NAME);
final String storyID = getIntent().getStringExtra(KEY_STORY_ID);
final String momentID = getIntent().getStringExtra(KEY_MOMENT_ID);
mSelectedIndex = getIntent().getIntExtra(ARG_SELECTED_INDEX, 0);
if (!mShouldSaveToDB) {
if (mStory == null) {
sendRequest(storyID, momentID);
} else {
mMoments = mStory.getMoments();
setViewPager();
}
} else {
if (mStory != null) {
mStoryDB = DBManager.getStory(mStory.getID());
} else {
mStoryDB = DBManager.getStory(storyID);
}
if (mStoryDB == null) {
sendRequest(storyID, momentID);
} else {
setGlobalDataWithStoryDB();
setViewPager();
}
}
mCreativeHandler = new CreativeHandler(this, this);
File cacheDir = Glide.getPhotoCacheDir(this, MyGlideModule.DISK_IMAGE_CACHE_NAME);
File[] filesList = cacheDir.listFiles();
for (File cachedFile : filesList) {
Log.d(TAG, "cachedFileName = " + cachedFile.getName() + " ,path = " + cachedFile.getAbsolutePath());
}
}
@Override
public Toolbar setToolbar() {
Toolbar mToolbar = (Toolbar) findViewById(R.id.mToolbar);
mToolbar.setBackgroundColor(getResources().getColor(R.color.black_color));
mToolbar.setVisibility(View.VISIBLE);
return mToolbar;
}
@Override
public void findViews() {
setContentView(R.layout.timeline_moment_activity);
mVp = (HackyViewPager) findViewById(R.id.mVp);
mTvName = (TextView) findViewById(R.id.mTvName);
mTvContent = (TextView) findViewById(R.id.mTvVpContent);
mTvDate = (TextView) findViewById(R.id.mTvUsername);
mTvNumberOfLikes = (TextView) findViewById(R.id.mTvNumberOfLikes);
mBtnLike = (ImageView) findViewById(R.id.mBtnLike);
mTvNumberOfComments = (TextView) findViewById(R.id.mTvNumberOfComments);
mBtnComments = (ImageView) findViewById(R.id.mBtnComments);
mTvNumberOfShares = (TextView) findViewById(R.id.mTvNumberOfShares);
mBtnShare = (ImageView) findViewById(R.id.mBtnShare);
mBtnLike.setOnClickListener(this);
mTvNumberOfLikes.setOnClickListener(this);
mBtnShare.setOnClickListener(this);
mTvNumberOfShares.setOnClickListener(this);
mBtnComments.setOnClickListener(this);
mTvNumberOfComments.setOnClickListener(this);
}
…..
private void setGlobalDataWithStoryDB () {
if (mStoryDB == null) {
return;
}
mMomentsDB = mStoryDB.getMoments();
mStory = mStoryDB.converter();
mMoments = mStory.getMoments();
}
// MARK: View Pager
private void setViewPager() {
mAdapter = new TimelineMomentPagerAdapter(this, mMoments, mStoryDB);
mVp.setOffscreenPageLimit(-1);
mVp.addOnPageChangeListener(this);
mVp.setAdapter(mAdapter);
mVp.setCurrentItem(mSelectedIndex);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (mMoments.isEmpty()) {
return;
}
/*View currentView = mVp.getChildAt(position);
if (currentView != null) {
mAdapter.setBitmap(currentView);
} else {
currentView = mVp.getFocusedChild();
if (currentView != null) {
mAdapter.setBitmap(currentView);
}
}*/
mSelectedIndex = position;
final MomentPojo moment = mMoments.get(position);
if (getSupportActionBar() != null)
getSupportActionBar().setTitle(mStory.getTitle() + " " + (position + 1) + "/" + mMoments.size());
mTvNumberOfShares.setText(""); // TODO: No API for number of shares
handleLikeState(moment);
handleComments(moment);
mTvName.setText(moment.getOwnerName());
if (moment.getTimestamp() != null) {
mTvDate.setText(Utility.timestampToDateString(moment.getTimestamp()));
} else {
mTvDate.setVisibility(View.INVISIBLE);
}
if (moment.getTitle().equals("")) {
mTvContent.setVisibility(View.GONE);
} else {
mTvContent.setVisibility(View.VISIBLE);
mTvContent.setText(moment.getTitle());
}
}
@Override
public void onPageSelected(int position) {
View currentView = mVp.getChildAt(1);
if (currentView != null) {
mAdapter.setBitmap(currentView);
} else {
currentView = mVp.getFocusedChild();
if (currentView != null) {
mAdapter.setBitmap(currentView);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
private void handleComments(MomentPojo moment) {
final int comments = Integer.parseInt(moment.getCommentsNumber());
if (comments > 0) {
mTvNumberOfComments.setText(Utility.showNumInNumK(comments));
} else {
mTvNumberOfComments.setText("");
}
}
private void handleLikeState(MomentPojo moment) {
if (moment.wasLiked()) {
mBtnLike.setImageResource(R.drawable.ic_favorite_clicked);
} else {
mBtnLike.setImageResource(R.drawable.ic_favorite_unclicked);
}
final int likes = Integer.parseInt(moment.getLikesNumber());
if (likes > 0) {
mTvNumberOfLikes.setText(Utility.showNumInNumK(likes));
} else {
mTvNumberOfLikes.setText("");
}
}
// MARK: OnClick and OnClick actions
@Override
public void onClick(View v) {
final MomentPojo moment = mMoments.get(mSelectedIndex);
if (v == mBtnComments || v == mTvNumberOfComments) {
actionComment(mMoments.get(mSelectedIndex).getID());
} else if (v == mBtnLike || v == mTvNumberOfLikes) {
actionLike(moment);
} else if (v == mBtnShare || v == mTvNumberOfShares) {
actionShare();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
mCreativeHandler.onActivityResult(requestCode, resultCode, result);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case Crop.REQUEST_PICK:
beginCrop(result.getData());
break;
case Crop.REQUEST_CROP:
handleEdit(resultCode, result, cropFileUri);
break;
}
}
super.onActivityResult(requestCode, resultCode, result);
}
private void actionShare() {
MomentPojo momentPojo = mMoments.get(mVp.getCurrentItem());
MomentOptions.actionShare(this, momentPojo);
}
private void actionComment(String momentID) {
ProgressBarClass.startLoading(this);
new TimelineCommentsGetRequest(momentID, this);
}
private void actionLike(MomentPojo moment) {
new LinkerLikePostRequest(LinkerPojo.KEY_SOURCE_TYPE_MOMENT, moment.getID(), new LinkerLikePostRequest.Callback() {
@Override
public void onErrorResult(String err) {
// TODO: handle error
}
});
Utility.d("like state: " + moment.wasLiked());
final int likes = Integer.parseInt(moment.getLikesNumber());
if (moment.wasLiked()) {
moment.setWasLiked(false);
moment.setLikesNumber((likes - 1) + "");
mBtnLike.setImageResource(R.drawable.ic_favorite_unclicked);
} else {
moment.setWasLiked(true);
moment.setLikesNumber((likes + 1) + "");
mBtnLike.setImageResource(R.drawable.ic_favorite_clicked);
}
handleLikeState(moment);
if (mShouldSaveToDB) {
MomentDB momentDB = mMomentsDB.get(mSelectedIndex);
if (momentDB.wasLiked()) {
momentDB.setWasLiked(false);
momentDB.setLikesNumber((likes - 1) + "");
} else {
momentDB.setWasLiked(true);
momentDB.setLikesNumber((likes + 1) + "");
}
momentDB.save();
}
mMoments.set(mSelectedIndex, moment);
AppInstance.sharedInstance().getBus().post(new TimelineBusMomentChanged(moment, TimelineBusMomentChanged.KEY_STATE_LIKED));
}
@Override
public void onFinishedImageEditing(Uri outputFilePath) {
handleEdit(RESULT_OK, null, outputFilePath);
}
// MARK: Comments
@Override
public void onMomentResult(ArrayList<CommentPojo> comments) {
final LinkerPojo pojo = new LinkerPojo(mMoments.get(mSelectedIndex));
ProgressBarClass.dismissLoading();
CommentsActivity.setInstance(this, pojo, comments);
}
@Override
public void onErrorResult(String err) {
ProgressBarClass.dismissLoading();
MyToast.makeText(getString(R.string.gen_Something_went_wrong), MyToast.KEY_TYPE_RED).show();
}
// MARK: Settings
private class SettingsDialog implements ImageRotatePutRequest.Callback {
private MomentDB mMomentDB;
private ArrayList<String> mOptions;
public SettingsDialog(MomentDB momentDB) {
this.mMomentDB = momentDB;
final String type = momentDB.getType();
setOptions(type);
createDialog();
}
private void setOptions(String type) {
mOptions = new ArrayList<>();
switch (type) {
case TimelineUtils.KEY_TYPE_IMAGE:
mOptions.add(getString(R.string.rotate_left));
mOptions.add(getString(R.string.rotate_right));
//mOptions.add(getString(R.string.timeline_moment_crop));
mOptions.add(getString(R.string.timeline_moment_edit));
break;
case TimelineUtils.KEY_TYPE_TEXT:
break;
case TimelineUtils.KEY_TYPE_LINK:
break;
case TimelineUtils.KEY_TYPE_VIDEO:
break;
}
mOptions.add(getString(R.string.gen_Delete));
}
private void createDialog() {
final ListViewDialog dialog = new ListViewDialog(TimelineMomentActivity.this);
dialog.setOnItemClickListener(mOptions, new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int i, long id) {
final String option = mOptions.get(i);
if (option.equals(getString(R.string.gen_Delete))) {
actionDelete();
} else if (option.equals(getString(R.string.rotate_left))) {
actionRotate(false);
} else if (option.equals(getString(R.string.rotate_right))) {
actionRotate(true);
} /*else if (option.equals(getString(R.string.timeline_moment_crop))) {
actionCrop();
}*/ else if (option.equals(getString(R.string.timeline_moment_edit))) {
actionEdit();
}
dialog.dismiss();
}
});
dialog.show();
}
private void actionEdit() {
File bitmapFile = mAdapter.getBitmap();
if (bitmapFile != null) {
mCreativeHandler.startFeather(Uri.fromFile(bitmapFile));
}
//final MomentPojo momentPojo = mMoments.get(mVp.getCurrentItem());
//final String picUrl = Utility.getImageBySize(momentPojo.getContent(), MediaUtils.SIZE_MEDIUM, MediaUtils.SIZE_ORIGINAL);
//Uri picUri = Uri.parse(picUrl);
//mCreativeHandler.startFeather(picUri);
//File imageFile = DBManager.getImageFile(TimelineMomentActivity.this, momentPojo.toMomentDB(mStoryDB));=
}
private void actionDelete() {
MomentPojo currentMomentPojo = mMoments.get(mVp.getCurrentItem());
MomentOptions.actionDeleteMoment(TimelineMomentActivity.this, currentMomentPojo, mMoments.size(), mStory.getID());
finish();
}
private void actionRotate(boolean isClockWise) {
MomentPojo momentPojo = mMoments.get(mVp.getCurrentItem());
new ImageRotatePutRequest(momentPojo.getID(), isClockWise, this);
float currentRotation = Float.parseFloat(mMomentDB.getRotation());
if (isClockWise) {
currentRotation += 90;
} else {
currentRotation -= 90;
}
if (mShouldSaveToDB) {
mMomentDB.setRotation(currentRotation + "");
mMomentDB.save();
momentPojo = mMomentDB.converter();
}
momentPojo.setRotation(currentRotation + "");
mMoments.set(mSelectedIndex, momentPojo);
setViewPager();
AppInstance.sharedInstance().getBus().post(new TimelineBusMomentChanged(momentPojo, TimelineBusMomentChanged.KEY_STATE_ROTATE));
}
@Override
public void onImageRotateResult() {
Utility.d("image rotated ");
}
@Override
public void onErrorResult(String err) {}
}
@Override
protected void onDestroy() {
AppInstance.sharedInstance().getBus().unregister(this);
super.onDestroy();
}
….
// MARK: Crop
private void beginCrop(Uri source) {
Crop.of(source, cropFileUri).asSquare().start(this);
}
…..
}
Adapter:
public class TimelineMomentPagerAdapter extends PagerAdapter {
…
public TimelineMomentPagerAdapter(Context mContext, List<MomentPojo> mArray, StoryDB aStoryDB) {
this.mContext = mContext;
this.mArray = mArray;
this.mStoryDB = aStoryDB;
}
public File getBitmap() {
convertBitmapToFile();
return mCurrentBitmapFile;
}
public void setBitmap(View aView) {
ImageView imageView = (ImageView) aView.findViewById(R.id.mIvVpContent);
if (imageView != null) {
mCurrentImageViewBitmap = getBitmap(imageView);
}
}
private void convertBitmapToFile() {
/*View currentPagerView = mVp.getChildAt(mVp.getCurrentItem());
ImageView contentView = (ImageView) currentPagerView.findViewById(R.id.mIvVpContent);
Bitmap bitmap = getBitmap(contentView);*/
final File bitmapFolder = new File(mContext.getCacheDir(), "bitmap");
if (!bitmapFolder.exists()) {
bitmapFolder.mkdir();
}
mCurrentBitmapFile = new File(bitmapFolder, "currentBitmap");
try {
if (mCurrentBitmapFile.exists()) {
mCurrentBitmapFile.delete();
}
mCurrentBitmapFile.createNewFile();
FileOutputStream stream = new FileOutputStream(mCurrentBitmapFile);
if (mCurrentImageViewBitmap != null) {
mCurrentImageViewBitmap.compress(Bitmap.CompressFormat.JPEG, 75, stream);
}
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public int getCount() {
return mArray.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((RelativeLayout) object);
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View v = inflater.inflate(R.layout.timeline_moment_viewpager, container, false);
final MomentPojo momentPojo = mArray.get(position);
mIvContent = (ImageView) v.findViewById(R.id.mIvVpContent);
mTvContent = (TextView) v.findViewById(R.id.mTvVpContent);
mIvPlay = (ImageView) v.findViewById(R.id.mIvPlay);
mPbProgressBar = (ProgressBar) v.findViewById(R.id.pbProgress);
final String type = momentPojo.getType();
final String content = momentPojo.getContent();
switch (type) {
case TimelineUtils.KEY_TYPE_IMAGE: //---------------------------------------------------IMAGE
mIvPlay.setVisibility(View.GONE);
mIvContent.setVisibility(View.VISIBLE);
mTvContent.setVisibility(View.GONE);
final String contentHigherQuality = momentPojo.getContentHigherQuality();
final String newContent;
if (JavaUtils.isNotNullNotEmptyNotWhiteSpaceOnly(contentHigherQuality)) {
newContent = contentHigherQuality;
} else if (JavaUtils.isNotNullNotEmptyNotWhiteSpaceOnly(content)) {
newContent = content;
} else {
newContent = momentPojo.getLocalPath();
}
mPbProgressBar.setVisibility(View.VISIBLE);
Glide.with(BaseApplication.getInstance()).load(newContent).asBitmap().placeholder(R.drawable.ic_action_picture).into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
if (bitmap != null) {
mIvContent.setImageBitmap(bitmap);
}
mPbProgressBar.setVisibility(View.INVISIBLE);
}
@Override
public void onLoadFailed(final Exception e, final Drawable errorDrawable) {
mPbProgressBar.setVisibility(View.INVISIBLE);
}
});
setImageRotation(momentPojo.getRotation());
if (position == 0 && !mWasCurrentImageBitmapInitialized) {
mCurrentImageViewBitmap = getBitmap(mIvContent);
mWasCurrentImageBitmapInitialized = true;
}
break;
case TimelineUtils.KEY_TYPE_TEXT: //---------------------------------------------------TEXT
case TimelineUtils.KEY_TYPE_LINK: //---------------------------------------------------LINK
….
break;
case TimelineUtils.KEY_TYPE_AUDIO: //---------------------------------------------------AUDIO
case TimelineUtils.KEY_TYPE_VIDEO: //---------------------------------------------------VIDEO
…
break;
case TimelineUtils.KEY_TYPE_PDF: //-----------------------------------------------------PDF
….
break;
case TimelineUtils.KEY_TYPE_YOUTUBE: //---------------------------------------------------VIDEO
….
break;
}
container.addView(v);
return v;
}
….
public Bitmap getBitmap(ImageView aImageView) {
Bitmap image = null;
if (aImageView == null) return null;
Drawable drawable = aImageView.getDrawable();
if (drawable != null) {
if (drawable instanceof GlideBitmapDrawable) {
GlideBitmapDrawable bitmapDrawable = (GlideBitmapDrawable) aImageView.getDrawable();
image = bitmapDrawable.getBitmap();
} else if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) aImageView.getDrawable();
image = bitmapDrawable.getBitmap();
}
}
return image;
}
….
}
This code works but not always, there are cases in which currentView is null after passing this method. After some debugging session I figured out that while onPageSelected
gives me the real index that can be for example 10 the view pager holds it's view always in the 0-2 positions. so, on swiping all three item are swapped but they remain in their 0-2 positions.
How can I achieve my task?
Upvotes: 2
Views: 581
Reputation: 30985
First, get rid of all the code in the OnPageChangeListener
that modifies something in the adapter.
Add a map of bitmaps to the adapter:
private Map<Integer, Bitmap> mBitmapMap;
private Map<Integer, View> mViewMap;
In instantiateItem()
after inflation:
mViewMap.put(position, v);
In your callback onResourceReady()
:
mBitmap.put(position, bitmap); // position is final
In destroyItem()
:
mBitmapMap.put(position, null); // remove from map
mViewMap.put(position, null);
Then implement new methods:
public Bitmap getBitmapAt(int position) {
return mBitmapMap.get(position);
}
public View getViewAt(position) {
return mViewMap.get(position);
}
Call from activity:
bitmap = mAdapter.getBitmapAt(mVp.getCurrentItem());
view = mAdapter.getViewAt(mVp.getCurrentItem());
Now you can leave the offscreen page limit at its default.
Upvotes: 2