how to use preloader in Grid View in android - android

I want to use preloader image in gridview for images when its loading form the remote server.
while its loading from the server at that time i want to show preloader image like this(same like progress bar or progress bar).
I want to show small progress bar there in gridview image item or preloader image I dnt know what i can use which would be easily for me to achieve this.
Can anybody please help me how can do this thing in android.
I want to make this as like IOS. this image is form the IOS.
Here is my android layout xml file :
activity_image_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<include
android:id="#+id/title_bar"
android:layout_alignParentTop="true"
layout="#layout/activity_top_header_bar" />
<GridView
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#id/title_bar"
android:gravity="center"
android:horizontalSpacing="4dip"
android:numColumns="4"
android:padding="5dip"
android:stretchMode="columnWidth"
android:verticalSpacing="4dip" />
</RelativeLayout>
This xml file used for item for each grid in Gridview.
item_grid_image.xml
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="75dp"
android:adjustViewBounds="true"
android:contentDescription="#string/descr_image"
android:scaleType="centerCrop" />
Source code :
public class ImageGridActivity extends BaseActivity {
private static final String TAG = "[ImageGridActivity]";
private DisplayImageOptions options;
private PullToRefreshGridView mPullRefreshGridView;
private GridView mGridView = null;
ArrayList<GallaryImage> mGridViewImagesList;
private ImageAdapter mImageAdapter = null;
private String mImageUrl = null;
private String mGallaryTitle = null;
// private ImageLoader imageLoader = ImageLoader.getInstance();
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_grid);
options = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.photo_default)
.showImageForEmptyUri(R.drawable.photo_default)
.showImageOnFail(R.drawable.ic_error).cacheInMemory()
.cacheOnDisc().bitmapConfig(Bitmap.Config.RGB_565).build();
final Bundle bundle = getIntent().getExtras();
if (bundle != null) {
mImageUrl = bundle.getString(Constants.GALLARY_FETCH_URL);
mGallaryTitle = bundle.getString(Constants.GALLARY_TYPE);
if (mGallaryTitle != null) {
Locale loc = Locale.getDefault();
TextView tvTitleText = (TextView) findViewById(R.id.tv_title_bar_text);
tvTitleText.setText(mGallaryTitle.toUpperCase(loc));
}
mPullRefreshGridView = (PullToRefreshGridView) findViewById(R.id.pull_refresh_grid);
mPullRefreshGridView.setMode(Mode.PULL_FROM_START);
mGridView = mPullRefreshGridView.getRefreshableView();
mGridViewImagesList = Utility.getImagesList(mImageUrl,
ImageGridActivity.this);
if (mGridViewImagesList != null && !mGridViewImagesList.isEmpty()) {
mImageAdapter = new ImageAdapter(mGridViewImagesList);
((GridView) mGridView).setAdapter(mImageAdapter);
} else {
// did refresh after the previous images are loaded in the
// gridview.
if (Utility.checkConnection(ImageGridActivity.this)) {
Log.i(TAG,
"Wifi/Internet Connection found , have to parse the xml");
final FetchImagesAsyncTaskFeed asyncTask = new FetchImagesAsyncTaskFeed();
asyncTask.execute(mImageUrl);
}
}
mGridView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(final AdapterView<?> parent,
final View view, final int position, final long id) {
if (mGridViewImagesList != null
&& !mGridViewImagesList.isEmpty()) {
startImagePagerActivity(mGridViewImagesList, position);
} else {
Log.d(TAG, "There is no image about this grid image");
}
}
});
// Set a listener to be invoked when the list should be refreshed.
mPullRefreshGridView
.setOnRefreshListener(new OnRefreshListener2<GridView>() {
#Override
public void onPullDownToRefresh(
PullToRefreshBase<GridView> refreshView) {
if (mImageUrl != null) {
final FetchImagesAsyncTaskFeed asyncTask = new FetchImagesAsyncTaskFeed();
asyncTask.execute(mImageUrl);
}
}
#Override
public void onPullUpToRefresh(
PullToRefreshBase<GridView> refreshView) {
}
});
}
}
/**
* #param position
*/
private void startImagePagerActivity(
final ArrayList<GallaryImage> mImageAttributesList,
final int position) {
String[] urls = new String[mImageAttributesList.size()];
final Intent intent = new Intent(this, ImagePagerActivity.class);
intent.putExtra(Constants.GALLARY_IMAGE_POSITION_BUNDLE_KEY, position);
for (int i = 0; i < mImageAttributesList.size(); i++) {
urls[i] = mImageAttributesList.get(i).mImageUrl;
}
intent.putExtra(Constants.GALLARY_IMAGES_IMAGE_BUNDLE_KEY, urls);
startActivity(intent);
}
public class ImageAdapter extends BaseAdapter {
ArrayList<GallaryImage> imageList = null;
public ImageAdapter(final ArrayList<GallaryImage> imageAttributesList) {
this.imageList = imageAttributesList;
}
#Override
public int getCount() {
return imageList.size();
}
#Override
public Object getItem(final int position) {
return imageList.get(position);
}
#Override
public long getItemId(final int position) {
return position;
}
#Override
public View getView(final int position, final View convertView,
final ViewGroup parent) {
final ImageView imageView;
if (convertView == null) {
imageView = (ImageView) getLayoutInflater().inflate(
R.layout.item_grid_image, parent, false);
} else {
imageView = (ImageView) convertView;
}
imageLoader.displayImage(imageList.get(position).mImageUrl,
imageView, options);
return imageView;
}
/**
* #param updateData
*/
public void updatedData(ArrayList<GallaryImage> imgList) {
this.imageList = imgList;
notifyDataSetChanged();
}
}
private class FetchImagesAsyncTaskFeed extends
AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(final String... urls) {
try {
Thread.sleep(3000);
final String imageUrl = urls[0];
final GridViewImagesXMLHandler mGallaryXMLHandler = new GridViewImagesXMLHandler();
mGridViewImagesList = mGallaryXMLHandler.getImages(imageUrl);
if (mGridViewImagesList != null
&& !mGridViewImagesList.isEmpty()) {
Utility.setImagesInfromation(imageUrl, mGridViewImagesList,
ImageGridActivity.this);
}
} catch (final Exception e) {
Log.e(TAG, "Exception in fetch images from the url", e);
}
return null;
}
#Override
protected void onPostExecute(final String result) {
if (mGridViewImagesList != null && !mGridViewImagesList.isEmpty()) {
if (mImageAdapter != null) {
mImageAdapter.updatedData(mGridViewImagesList);
mPullRefreshGridView.onRefreshComplete();
} else {
mImageAdapter = new ImageAdapter(mGridViewImagesList);
((GridView) mGridView).setAdapter(mImageAdapter);
}
}
mPullRefreshGridView.onRefreshComplete();
}
}
}

Universal ImageLoader
https://github.com/nostra13/Android-Universal-Image-Loader
rowimage.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/ivv"
android:layout_gravity="center"
android:layout_width="300dp"
android:layout_height="300dp"
/>
<ProgressBar
android:id="#+id/pb"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
In your adapter constructor
ImageLoader imageLoader;
DisplayImageOptions options;
File cacheDir = StorageUtils.getOwnCacheDirectory(a, "MyRaghu");
// Get singletone instance of ImageLoader
imageLoader = ImageLoader.getInstance();
// Create configuration for ImageLoader (all options are optional)
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(a)
// You can pass your own memory cache implementation
.discCacheExtraOptions(1024, 1024, CompressFormat.PNG, 100)
.discCache(new UnlimitedDiscCache(cacheDir)) // You can pass your own disc cache implementation
.discCacheFileNameGenerator(new HashCodeFileNameGenerator())
.enableLogging()
.build();
// Initialize ImageLoader with created configuration. Do it once.
imageLoader.init(config);
//imageLoader.init(ImageLoaderConfiguration.createDefault(a));
// imageLoader=new ImageLoader(activity.getApplicationContext());
options = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.ic_launcher)
.cacheInMemory()
.cacheOnDisc()
.displayer(new RoundedBitmapDisplayer(20))
.build();
In your getview of your custom adapter
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.rowimage, null);
ImageView image=(ImageView)vi.findViewById(R.id.ivv);
ProgressBar pb= (ProgressBar)vi.findViewById(R.id.pb);
display(null, data.get(position).toString(), pb);
//imageLoader.displayImage(data.get(position).toString(), image,options);
return vi;
}
public void display(ImageView img, String url, final ProgressBar spinner)
{
imageLoader.displayImage(url, img, options, new ImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view) {
spinner.setVisibility(View.VISIBLE);
}
#Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
spinner.setVisibility(View.GONE);
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
spinner.setVisibility(View.GONE);
}
#Override
public void onLoadingCancelled(String imageUri, View view) {
}
});
}
Resulting snap shot i have used listview but it should work for gridview also.
First a stub image is displayed along with progress bar. In this case a i have used a launcher icon so it looks stretched
Once image is downloaded progress bar is dismissed and stub image is replaced by the downloaded one. Even caches images.

Try to use Android-Universal-Image-Loader api from github.com
Android-Universal-Image-Loader
I think it help you.
Thanks.

Related

how to remove selected images in grid view when long press happens in android

I am new to android developer, after completing some example apps, I started to work grid view concepts. Here I'm trying to implement the following logics.
1.When long press happened upon images, selected images should be highlighted.
2.Need to know the selected images to delete the selected images.
I have completed to select the images from gallery, Now I need to long press images and delete the same using delete button.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="#+id/btn_browse"
android:text="Browse"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="#+id/btn_delete"
android:text="Delete"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<GridView
android:id="#+id/grid_view"
android:layout_width="match_parent"
android:layout_height="660dp"
android:columnWidth="90dp"
android:gravity="center"
android:horizontalSpacing="10dp"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" />
</LinearLayout>
//Adapter class
class ImageAdapter extends BaseAdapter {
//Context c|ass is use to bind xm| with java
private Context mcontext;
ArrayList<Uri> ImageUriList = new ArrayList<Uri>();
//Right c|ick and generate constructor
//imp|ement methods then auto generate
//Constructor ...Rigth c|ick and generate constructor
public ImageAdapter(Context mcontext, ArrayList<Uri> image) {
this.mcontext = mcontext;
ImageUriList = image;
}
#Override
public int getCount() {
return (ImageUriList == null) ? 0 : ImageUriList.size();
}
#Override
public Object getItem(int position) {
return ImageUriList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView =new ImageView(mcontext);
imageView.setImageURI(ImageUriList.get(position));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(340,340));
return imageView;
}
}
// MainActivity
public class MainActivity extends AppCompatActivity {
public static final int BROWSE_RESULT = 1;
ImageAdapter imageAdapter;
ArrayList<Uri> imagesUri = new ArrayList<Uri>();
GridView gridView;
#Override
protected void onCreate(Bundle savedInstanceState) {
Button btn_browse;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridView= findViewById(R.id.grid_view);
gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
// imagesUri.remove(i) ;
gridView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
//imageAdapter.notifyDataSetChanged();
Toast.makeText(MainActivity.this, i + " Value ", Toast.LENGTH_SHORT).show();
return false;
}
});
btn_browse = findViewById(R.id.btn_browse);
btn_browse.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
f_openImageExplorer();
}
});
}
public void f_openImageExplorer() {
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, BROWSE_RESULT);
}
#Override
protected void onActivityResult(int requestCode, int resultCode,Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == BROWSE_RESULT) {
if (resultCode == MainActivity.RESULT_OK) {
if (data.getClipData() != null) {
Toast.makeText(this,Integer.toString(resultCode) , Toast.LENGTH_SHORT).show();
int imageCount = data.getClipData().getItemCount();
for(int i = 0; i< imageCount;i++){
Uri imageUri = data.getClipData().getItemAt(i).getUri();
imagesUri.add(imageUri);
imageAdapter= new ImageAdapter(getBaseContext(), imagesUri);
gridView.setAdapter(imageAdapter);
imageAdapter.notifyDataSetChanged();
}
}
else
{
Uri singleImageUri = data.getData();
imagesUri.add(singleImageUri);
ImageAdapter imageAdapter= new ImageAdapter(getBaseContext(), imagesUri);
gridView.setAdapter(imageAdapter);
imageAdapter.notifyDataSetChanged();
}
}
}
}
}
In your MainActivity you can track of all clicked images and save their positions in a separated ArrayList - and on your delete Button you can check the positions of clicked items and remove them from the main list - after that action is done , just update your ImageAdapter with the new list:
ArrayList<int> clickedImagesIdx = new ArrayList<int>();
gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
gridView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
...
clickedImagesIdx.add(i);
return false;
}
});
deleteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (clickedImagesIdx.size() > 0) {
for (int i = 0; i < clickedImagesIdx.size(); i++) {
imagesUri.remove(i);
}
clickedImagesIdx.clear();
// here you will need to submit the new Uri list to your adapter
// and use notifyDataSetChange();
}
}
});

Update ActionBar from Adapter

I have a basket icon with count notification on it in actionbar for showing number of goods in shopping basket. also I have a custom view containing a button for add goods to shopping basket. I want that when I click on button (in custom view) notification count on basket icon increases. I use this function in main activity to update notification count but notification does not update.
public static void updateCountBasket(final int number , int id , View view ,Context context) {
if (view.findViewById(id) == null)
return;
TextView t = (TextView)view.findViewById(id);
String dd = t.getText().toString();
((Activity) context).runOnUiThread(new Runnable() {
#Override
public void run() {
if (number == 0)
t.setVisibility(View.INVISIBLE);
else {
t.setVisibility(View.VISIBLE);
t.setText(Integer.toString(number));
}
}
});
}
but when I use non static of that function in main activity with simple button on click, it works fine. but I can't call non static function in base adapter too :( . I checked line by line of the function in static mode all ids are right and it set text too but nothing change or get error!!. please help me to change textview as notification of basket in menubar from base adapter when button in custom view clicks. thanks
I have this base adapter for my custom view list:
public class Goods_ImageAdapter extends BaseAdapter {
private Context context;
private final JSONArray Goods;
private Bagde bagde;
public Goods_ImageAdapter(Context context , JSONArray Goods) {
this.context = context;
this.Goods = Goods;
bagde = Bagde.getInstance();
}
#Override
public int getCount() {
return Goods.length();
}
#Override
public Object getItem(int arg0) {
return null;
}
#Override
public long getItemId(int arg0) {
return 0;
}
public static String doubleToStringNoDecimal(double d) {
DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);;
formatter .applyPattern("#,###");
return formatter.format(d);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
final View bagde_c;
if (convertView == null) {
gridView = new View(context);
gridView = inflater.inflate(R.layout.goodsitem, null);
bagde_c = inflater.inflate(R.layout.badge_counter, null);
try {
TextView goods_textview_Name = (TextView) gridView.findViewById(R.id.goods_textview_Name);
goods_textview_Name.setText(Goods.getJSONObject(position).getString("Name"));
TextView goods_textview_Price = (TextView) gridView.findViewById(R.id.goods_textview_Price);
goods_textview_Price.setText(Goods.getJSONObject(position).getString("Price"));
} catch (JSONException e) {
e.printStackTrace();
}
try {
ImageView goods_imageview = (ImageView) gridView.findViewById(R.id.goods_imageview);
new ImageDownloader(goods_imageview).execute("http://IP/" + Goods.getJSONObject(position).getString("ImageFileName"));
} catch (JSONException e) {
e.printStackTrace();
}
final TextView goods_textview_bagdecounter = (TextView) gridView.findViewById(R.id.goods_textview_bagdecounter);
ImageView goods_buy_plus = (ImageView) gridView.findViewById(R.id.goods_buy_button_plus);
try {
goods_buy_plus.setTag(Goods.getJSONObject(position));
} catch (JSONException e) {
e.printStackTrace();
}
goods_buy_plus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((Activity) context).runOnUiThread(new Runnable() {
#Override
public void run() {
String bagde_counter_text = goods_textview_bagdecounter.getText().toString();
goods_textview_bagdecounter.setText(String.valueOf(Integer.parseInt(bagde_counter_text) + 1));
}
});
com.???.????.Goods_Activity.updateCountBasket(a number for example,R.id.notif,inflater2.inflate(R.layout.badge_counter, null),context);
}
});
ImageView goods_buy_minus = (ImageView) gridView.findViewById(R.id.goods_buy_button_minus);
try {
goods_buy_minus.setTag(Goods.getJSONObject(position));
} catch (JSONException e) {
e.printStackTrace();
}
goods_buy_minus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((Activity) context).runOnUiThread(new Runnable() {
#Override
public void run() {
String bagde_counter_text = goods_textview_bagdecounter.getText().toString();
if(Integer.parseInt(bagde_counter_text)> 0)
goods_textview_bagdecounter.setText(String.valueOf(Integer.parseInt(bagde_counter_text) - 1));
}
});
}
});
} else {
gridView = (View) convertView;
}
return gridView;
}
}
this is (basket with notification on action bar) badge_counter.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="#android:style/Widget.ActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="true"
android:gravity="center"
android:orientation="vertical">
<RelativeLayout
android:id="#+id/badge_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:id="#+id/relative_layout_item_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="#+id/button"
android:layout_width="40dip"
android:layout_height="40dip"
android:background="#drawable/download" />
<TextView
android:id="#+id/notif"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#android:drawable/ic_notification_overlay"
android:text="33"
android:textColor="#FFA"
android:textSize="12sp"
android:textStyle="bold" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
You can achieve this by using interface.
Add an interface in Adapter class
public interface AdapterCallBack
{
public void onChangeBadgeCount();
}
And in constructor, pass a reference to this interface.
public Goods_ImageAdapter(Context context , JSONArray Goods, AdapterCallBack adapterCallback)
{
this.context = context;
this.Goods = Goods;
this.adapterCallback = adapterCallback;
bagde = Bagde.getInstance();
}
And whenever you want to set badge count in ActionBar, just call adapterCallback.onChangeBadgeCount().
And implement this interface in MainActivity.
public class MainActivity implements Goods_ImageAdapter.AdapterCallBack
{
... some code
When your are initializing adapter, just pass this as a last parameter.
Example:
adapter = new Goods_ImageAdapter(this, Goods /* Json data */, this);
...
#override
public void onChangeBadgeCount()
{
// Change your badge count here
}
}
I am printing my array length size in ActionBar from Recycler adapter
((Show_request) mContext).getSupportActionBar().setTitle("Total Stone:- " + array.length());
Using this you can get ActionBar in RecyclerView adapter
((your activity name) context object).getSupportActionBar().setTitle("message"/or pass variable);

Android gridview scrolling bad loading image

I'm using Picasso to load all my images in a Gridview and DBFlow to save in the Local database. But I have a problem when I download the images for the first time and if I'm scrolling in the gridview. The next images have the previous images and 1 second later the good image is loaded. I have to scroll 5 times or more and when all images is loaded I don't have this problem but for the first time yes.
Have you an idea to optimize my code ?
Gridview
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="130dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:background="#color/colorAppBackground"/>
Item Grid
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="130dp">
<ImageView
android:id="#+id/iv_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"/>
<TextView
android:id="#+id/text_thumb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:textColor="#android:color/white"
android:background="#99000000"/>
</RelativeLayout>
Activity
public class GalleryActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
Bundle bundle = getIntent().getExtras();
int idAccount = bundle.getInt("idAccount");
callAdminPictures(idAccount);
}
public void callAdminPictures(final int idAccount){
// Build REST Adapter
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl(Globals.SERVER_NAME)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
// Create the App Service
ApplicationService appService = restAdapter.create(ApplicationService.class);
// Call Get admin pictures WS
Call<AdminPictures> getAdminPicturesWS = appService.getAdminPictures(idAccount);
getAdminPicturesWS.enqueue(new Callback<AdminPictures>() {
#Override
public void onResponse(Call<AdminPictures> call, Response<AdminPictures> response) {
AdminPictures apResponse = response.body();
List<PictureInfos> pictureInfos = apResponse.getPicturesList();
for (PictureInfos infos : pictureInfos) {
if (infos.exists()) {
infos.update();
} else {
infos.save();
}
}
List<PictureInfos> tablePictureInfos = new Select()
.from(PictureInfos.class)
.where(PictureInfos_Table.idAccount.is("" + idAccount))
.orderBy(PictureInfos_Table.idPicture, false)
.queryList();
GridView gridView = (GridView) findViewById(R.id.gridview);
gridView.setAdapter(new ImageAdapter(GalleryActivity.this, tablePictureInfos));
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(GalleryActivity.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onFailure(Call<AdminPictures> call, Throwable t) {
if (t.getMessage() != null) {
Log.e("AdminPictures WS Fail", t.getMessage());
}
}
});
}
Adapter
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mLayoutInflater;
private List<PictureInfos> mPInfoList;
private boolean mToSave;
public ImageAdapter(Context context, List<PictureInfos> pInfoList) {
mContext = context;
mPInfoList = pInfoList;
mLayoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return mPInfoList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view;
final ImageView imageView;
final TextView legend;
if(convertView == null){
view = mLayoutInflater.inflate(R.layout.thumbnail_gallery, parent, false);
}else{
view = convertView;
}
imageView = (ImageView) view.findViewById(R.id.iv_thumbnail);
legend = (TextView) view.findViewById(R.id.text_thumb);
final File file = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES), mPInfoList.get(position).getFilename());
mToSave = !file.exists();
Target target = new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
if(mToSave) {
new Thread(new Runnable() {
#Override
public void run() {
try {
FileOutputStream fileOutput = new FileOutputStream(file);
Log.i("catch", mPInfoList.get(position).getFilename());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutput);
fileOutput.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
imageView.setImageBitmap(bitmap);
if (mPInfoList.get(position).getFilename() != null) {
legend.setText(mPInfoList.get(position).getLegend());
}
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
String pic = Globals.SERVER_NAME+Globals
.ACCOUNT_SERVER_PATH+mPInfoList
.get(position).getFolderPath()+"/"+
VgzTools.addSuffix(mPInfoList.get(position).getFilename(), "-thumb");
imageView.setTag(target);
if(!file.exists()){
Picasso.with(mContext)
.load(pic)
.into(target);
mToSave = true;
}else{
Picasso.with(mContext)
.load(file)
.into(target);
mToSave = false;
}
return view;
}
Inside getView() put this line
imageView.setImageDrawable(null);
The previous image is coming because of view recycling. For each item you don't always get a new view, instead views are recycled to save memory. So once you scrolled the initially visible items, you will get the view from previous item which already has image set in it. So you have to remove it explicitly.
My guess is that because you're not explicitly clearing the imageView in your getView(), it's retaining the current image when it's recycled (IE - when it's passed in as convertView). Picasso will eventually call onBitmapLoaded(), but until then, you're left with the 'old' image.
Try explicitly clearing the image.

NotifyDataSetChanged is not refreshing the ViewPager

I am working on ViewPager Concept. In ViewPager item cell contains two items such as ImageView and TextView.
Initially, i will download Blur Image and show in ViewPager cell. After this was completed, i will download HighResolution Image and show in ViewPager cell respectively.
For example, if i am looking at the first Item in ViewPager as Blur Image and in background it is downloading HighResolution image and then it must refresh the ViewPager and show the HighResolution Image in the respectively view cell.
After swiping two items and then back to the first Item, that time it shows the High Resolution Image.
So my issue is without swiping left or right, i need to refresh the current view if any changes happened in the current view.
ViewPager Activity Class:
public class ViewPagerActivity extends Activity {
ViewPager pager;
String[] _blurImageURL;
PagerAdapter _pagerAdapter;
Context _context;
ViewPagerModel vpModel = new ViewPagerModel();
ArrayList<String> lstQueue=new ArrayList<String>();
Handler _handler=new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_pager);
pager = (ViewPager) findViewById(R.id.pagerView);
_context = this;
_blurImageURL = new String[]{
"http://cdn.connollyphoto.nyc/wp-content/uploads/2014/06/cp_seanbell_portrait_002-800x1200.jpg",
"http://static.wixstatic.com/media/e6f301_7d57a9c0ebdf4d438f88633637aaed77.jpg_srz_930_1395_85_22_0.50_1.20_0.00_jpg_srz",
"http://a4.format-assets.com/image/private/s--TmkImGBO--/c_limit,g_center,h_1200,w_65535/a_auto,fl_keep_iptc.progressive,q_95/31336-7293530-portrait-1_jpg2.jpg",
"http://daviddodgephotography.com/wp-content/uploads/2015/03/Donna_12.jpg",
"http://a3.format-assets.com/image/private/s--W9Flct-g--/c_limit,g_center,h_1200,w_65535/a_auto,fl_keep_iptc.progressive,q_95/173355-8951465-Marvin_Portraits-005.jpg",
"http://www.leifnorman.net/wp-content/uploads/2014/10/IMG_6070.jpg",
"https://dwaynefoong.files.wordpress.com/2012/05/amin-fashion-portrait-dwayne-foong-photography.jpg",
"https://m1.behance.net/rendition/modules/117495331/hd/ce856c4a1fb4c09a5ecec05839f6ddc4.jpg",
"http://www.pcimagenetwork.com/perks/Perks%202013.jpg",
};
_pagerAdapter = new ViewPagerAdapter(_context, vpModel, this);
pager.setAdapter(_pagerAdapter);
// Calling Volley Library to Download the Image for each URLi
for (int i = 0; i < _blurImageURL.length; i++) {
String fileName = String.valueOf(i);
fileName=fileName+"_blurImg";
DownloadImages(_blurImageURL[i], fileName, true);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.view_pager, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void updateView() {
_pagerAdapter.notifyDataSetChanged();
}
public void DownloadQueue(String url_in,String fileName_in)
{
if(lstQueue.contains(fileName_in))
{
Log.i("Duplicate_Request=",fileName_in);
}
else{
lstQueue.add(fileName_in);
DownloadImages(url_in,fileName_in,false);
}
}
void DownloadImages(String imageURL_in, final String fileName_in, final boolean isBlur_in) {
ImageRequest imageRequest = new ImageRequest(imageURL_in,
new Response.Listener<Bitmap>() {
#Override
public void onResponse(final Bitmap response) {
try {
Log.v("Response_Received =",fileName_in);
// Saved in SD Card and getting the Path
String imagePath = SavedInSDCard(response,fileName_in);
//updating the Model
if (isBlur_in) {
vpModel.blurImgLocalPath.add(imagePath);
} else {
vpModel.highResolutionImgLocalPath.add(imagePath);
}
//updating the View
_handler.post(new Runnable() {
#Override
public void run () {
updateView();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}, 0, 0, null, null);
ApplicationController.getInstance().addToRequestQueue(imageRequest);
}
public String SavedInSDCard(Bitmap bitmap, String fileName_in) {
File dir = new File(ApplicationController.getAppContext()
.getExternalFilesDir("ViewPager_POC") + "/Cache");
// Create the storage directory if it does not exist
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, fileName_in);
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
String imgPath = dir + "/" + fileName_in;
return imgPath;
}
}
ViewPager Adapter Class:
public class ViewPagerAdapter extends PagerAdapter {
Context _context;
LayoutInflater inflater;
ViewPagerActivity _vpActivity;
String[] _highResolutionURL = new String[]{
"http://www.monportraitpro.fr/wp-content/uploads/2014/08/Philippe-Vasilescu.jpg",
"http://www.markhicksphotography.com/wp-content/uploads/2012/01/MHP2012_01_04_MHP_DSC0003.jpg",
"http://www.andrew-mason.com/wp-content/uploads/2013/05/portrait-1-3.jpg",
"http://shutterfinger.typepad.com/.a/6a00e551a6244a8833019affd0eb14970d-pi",
"http://www.antonioolmos.com/data/photos/90_1childs_livebooks.jpg",
"http://www.dvdsreleasedates.com/pictures/800/12000/Zachary-Quinto.jpg",
"http://www.glnphotography.com/wp-content/uploads/2013/09/IMG_1347.jpg",
"http://www.dvdsreleasedates.com/pictures/800/12000/Paul-Walker.jpg",
"http://www.antonioolmos.com/data/photos/89_1blairbooks.jpg",
};
ArrayList<String> _blurImgPath;
ArrayList<String> _highResolutionImgPath;
public ViewPagerAdapter(Context context_in, ViewPagerModel vpModel_in, ViewPagerActivity activity_in) {
_context = context_in;
_blurImgPath = vpModel_in.blurImgLocalPath;
_highResolutionImgPath = vpModel_in.highResolutionImgLocalPath;
_vpActivity = activity_in;
}
#Override
public int getCount() {
return _blurImgPath.size();
}
#Override
public void destroyItem(View container, int position, Object object) {
// TODO Auto-generated method stub
((ViewPager) container).removeView((View) object);
}
#Override
public Object instantiateItem(ViewGroup container, final int position) {
// Declare Variables
TextView txtCounter;
final ImageView imgView;
inflater = (LayoutInflater) _context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.view_pager_item, container,
false);
txtCounter = (TextView) itemView.findViewById(R.id.counter);
imgView = (ImageView) itemView.findViewById(R.id.images);
//Setting the values for Image and textview
txtCounter.setText("" + (position + 1));
//Setting the Image
if (position < _highResolutionImgPath.size()) {
//Setting Hi-ResImage
Log.v("HighRes_ImgPath=", "Get Image from Model" );
imgView.setImageBitmap(BitmapFactory.decodeFile(_highResolutionImgPath.get(position)));
} else {
// Generating the request for HighResolution Image
String fileName = String.valueOf(position + 10);
fileName = fileName + "_clearImg";
Log.v("HighRes_ImgPath=", "Sending Request to Queue=" + fileName);
_vpActivity.DownloadQueue(_highResolutionURL[position], fileName);
//Setting the BlurImage
imgView.setImageBitmap(BitmapFactory.decodeFile(_blurImgPath.get(position)));
}
// Add viewpager_item.xml to ViewPager
((ViewPager) container).addView(itemView);
return itemView;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((RelativeLayout) object);
}
}
ViewPager Model:
public class ViewPagerModel {
ArrayList<String> blurImgLocalPath=new ArrayList<String>();
ArrayList<String> highResolutionImgLocalPath=new ArrayList<String>();
}
activity_view_pager.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.poc_viewpager.ViewPagerActivity" >
<android.support.v4.view.ViewPager
android:id="#+id/pagerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
/>
view_pager_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/images"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_alignParentLeft="true" />
<TextView
android:id="#+id/counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="43dp" />
</RelativeLayout>
In this case, I would use Picasso :
For example :
Picasso.with(getActivity())
.load(URL_THUMBNAIL) // thumbnail url goes here
.into(IMAGEVIEW, new Callback() { // Your image view
// On success start loading the full resolution image
#Override
public void onSuccess() {
Picasso.with(getActivity())
.load(FULL_RESOLUTION_URL) // image url goes here
.into(IMAGEVIEW);
}
#Override
public void onError() {
// Manage downloading errors here
}
});
The updateView()is called on the background thread. notifyDataSetChanged() does not work on the background thread. Call the notifyDataSetChanged() method on the UI thread and it should solve your problem

Android, retrieve thumbnail by parsing URL as argument using SimpleCursorAdapter.ViewBinder

i know the title is a bit messy, but here is the problem....
my goal is to retrieve title, and draw thumbnails of my youtube channel videos by using thumbnail URL, to the listView...
so far, i have the textView to display video title properly, but the thumbnail just couldnt be draw anyway..... by the way, i have the json / sqlite stuff classes done properly and they can retrieve data properly, so i dont have to worry about that... the only thing that bothers me is thumbnail wont display, the imageView displays as empty space in the app....
here is my code, please give me a hand. thx
this is the on create method of the activity...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] uiBindFrom = { TutListDatabase.COL_TITLE, TutListDatabase.COL_THUMBNAIL };
int[] uiBindTo = { R.id.title, R.id.thumbnail };
getLoaderManager().initLoader(TUTORIAL_LIST_LOADER, null, this);
adapter = new SimpleCursorAdapter(
getActivity().getApplicationContext(), R.layout.list_item,
null, uiBindFrom, uiBindTo,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
adapter.setViewBinder(new MyViewBinder());
setListAdapter(adapter);
}
and this one is the private class for putting stuff onto listView...
private class MyViewBinder implements SimpleCursorAdapter.ViewBinder{
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
int viewId = view.getId();
switch(viewId){
case R.id.title:
TextView titleTV = (TextView)view;
titleTV.setText(cursor.getString(columnIndex));
break;
// it is not displaying any thumbnail in app....
case R.id.thumbnail:
ImageView thumb = (ImageView) view;
thumb.setImageURI(Uri.parse(cursor.getString(columnIndex)));
break;
}
return false;
}
}
and here is the xml layout file...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal" >
<ImageView
android:id="#+id/thumbnail"
android:layout_width="101dp"
android:layout_height="101dp"
android:src="#drawable/icon" />
<TextView
android:id="#+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="6dp"
android:textSize="24dp" />
</LinearLayout>
I can show you a way that I have used and it worked quite well, first off we need a way to cache the images and the best way I have seen to date, is to use the LruCache as described in the excellent Google IO presentation doing more with less: http://www.youtube.com/watch?v=gbQb1PVjfqM
Here is my implementation of the method described in that presentation.
public class BitmapCache extends LruCache<String, Bitmap> {
public BitmapCache(int sizeInBytes) {
super(sizeInBytes);
}
public BitmapCache(Context context) {
super(getOptimalCacheSizeInBytes(context));
}
public static int getOptimalCacheSizeInBytes(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
int memoryClassBytes = am.getMemoryClass() * 1024 * 1024;
return memoryClassBytes / 8;
}
#Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
}
Next we need to load the images asynchronously with an AsyncTask, the following implementation takes care of loading an image into the given ImageView and dealing with the cache:
public class LoadImageAsyncTask extends AsyncTask<Void, Void, Pair<Bitmap, Exception>> {
private ImageView mImageView;
private String mUrl;
private BitmapCache mCache;
public LoadImageAsyncTask(BitmapCache cache, ImageView imageView, String url) {
mCache = cache;
mImageView = imageView;
mUrl = url;
mImageView.setTag(mUrl);
}
#Override
protected void onPreExecute() {
Bitmap bm = mCache.get(mUrl);
if(bm != null) {
cancel(false);
mImageView.setImageBitmap(bm);
}
}
#Override
protected Pair<Bitmap, Exception> doInBackground(Void... arg0) {
if(isCancelled()) {
return null;
}
URL url;
InputStream inStream = null;
try {
url = new URL(mUrl);
URLConnection conn = url.openConnection();
inStream = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(inStream);
return new Pair<Bitmap, Exception>(bitmap, null);
} catch (Exception e) {
return new Pair<Bitmap, Exception>(null, e);
}
finally {
closeSilenty(inStream);
}
}
#Override
protected void onPostExecute(Pair<Bitmap, Exception> result) {
if(result == null) {
return;
}
if(result.first != null && mUrl.equals(mImageView.getTag())) {
mCache.put(mUrl, result.first);
mImageView.setImageBitmap(result.first);
}
}
public void closeSilenty(Closeable closeable) {
if(closeable != null) {
try {
closeable.close();
} catch (Exception e) {
// TODO: Log this
}
}
}
}
Next you need to create an instance of your BitmapCache in the Activity or Fragment that is hosting the ListView, in onCreate(...) or onActivityCreated(...):
mBitmapCache = new BitmapCache(this); // or getActivity() if your using a Fragment
Now we need to update the SimpleCursorAdapter that shows the image, I have ommited most of the code as its specific to my project, but the idea is you override setViewImage where the value should be a value that is bound to the cursor, I zap the imageview to null to make sure it does not have an odd image from the cache associated to an item.
#Override
public void setViewImage(ImageView iv, String value) {
final String url = value;
iv.setImageBitmap(null);
new LoadImageAsyncTask(mBitmapCache, iv, url).execute();
}
Update
To make it clear, your adapter should look something like this
adapter = new SimpleCursorAdapter(
context, R.layout.list_item,
null, uiBindFrom, uiBindTo,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER) {
#Override
public void setViewImage(ImageView iv, String value) {
final String url = value;
iv.setImageBitmap(null);
new LoadImageAsyncTask(mBitmapCache, iv, url).execute();
}
};
Hope that helps!

Categories

Resources