Android gridview scrolling bad loading image - android

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.

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();
}
}
});

First Item of RecyclerView is Missing

I have an Activity. I am creating a File which has some data when activity is created. All the files are properly created and data is correctly written.
Following is my code
public class MyRecordingsActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecordingsAdapter recordingsAdapter;
private ArrayList<Recording> recordingArrayList;
private File userRecordingFile;
private static final String USER_MIX_DIR = "UserMix";
private String lines[]=new String[]{};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_recordings);
for(int i=0;i<5;i++){
try{
userRecordingFile = new File(createRecordingFiles(), "Recording"+i+".txt");
FileWriter writer = new FileWriter(userRecordingFile);
writer.append("DEF"+i+"\nHIJ "+i);
writer.flush();
writer.close();
}
catch (Exception e){
e.printStackTrace();
}
}
getSupportActionBar().hide();
recordingArrayList=new ArrayList<>();
recyclerView=findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setHasFixedSize(true);
readFiles();
Toast.makeText(getApplicationContext(),lines[0],Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(),lines[1],Toast.LENGTH_SHORT).show();
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[0],lines[1]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[2],lines[3]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[4],lines[5]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[6],lines[7]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[8],lines[9]));
recordingsAdapter=new RecordingsAdapter(recordingArrayList);
recyclerView.setAdapter(recordingsAdapter);
}
public File createRecordingFiles() {
File dirRoot = getExternalCacheDir();
File workDir = new File(dirRoot, USER_MIX_DIR);
//Toast.makeText(getApplicationContext(), "HI", Toast.LENGTH_SHORT).show();
if (!workDir.exists()) {
workDir.mkdirs();
File recordingFile = new File(workDir, "Recording File ");
try {
recordingFile.createNewFile();
} catch (IOException e) {
}
}
return workDir;
}
public void readFiles(){
StringBuilder text = new StringBuilder();
BufferedReader br=null;
try {
File dirRoot = getExternalCacheDir();
File workDir = new File(dirRoot, USER_MIX_DIR);
for(int i=0;i<5;i++){
File file = new File(workDir,"Recording"+i+".txt");
br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
lines=text.toString().split("\n");
}
}
br.close() ;
}catch (IOException e) {
e.printStackTrace();
}
}
}
The Toast which i have written correcly displays DEF0 and HIJ 0, but they are not displayed in the recyclerview. Following is screenshot of the screen
Following is my Adapter Class
public class RecordingsAdapter extends RecyclerView.Adapter<RecordingsAdapter.RecyclerViewHolder> {
public static final int TYPE_HEAD=0;
public static final int TYPE_LIST=1;
private ArrayList<Recording> recordingArrayList;
public RecordingsAdapter(ArrayList<Recording> recordingArrayList) {
this.recordingArrayList = recordingArrayList;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
RecyclerViewHolder recyclerViewHolder;
if(viewType == TYPE_LIST){
view= LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_my_recordings,parent,
false);
recyclerViewHolder=new RecyclerViewHolder(view,viewType);
return recyclerViewHolder;
}else if(viewType == TYPE_HEAD){
view= LayoutInflater.from(parent.getContext()).inflate(R.layout.head_layout,parent,
false);
recyclerViewHolder=new RecyclerViewHolder(view,viewType);
return recyclerViewHolder;
}
return null;
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
Recording recording;
if(holder.view_type==TYPE_LIST){
recording=recordingArrayList.get(position);
holder.imageView.setImageResource(recording.getImage_id());
holder.typeTextView.setText(recording.getTitle());
holder.dateTimeTextView.setText(recording.getDatetime());
}else if (holder.view_type == TYPE_HEAD){
holder.typeHeaderTextView.setText("TYPE");
holder.titleHeaderTextView.setText("TITLE");
holder.dateTimeHeaderTextView.setText("DATE/TIME");
}
}
#Override
public int getItemCount() {
return recordingArrayList.size();
}
#Override
public int getItemViewType(int position) {
if(position==0){
return TYPE_HEAD;
}
return TYPE_LIST;
}
public static class RecyclerViewHolder extends RecyclerView.ViewHolder{
int view_type;
ImageView imageView;
TextView typeTextView,dateTimeTextView;
TextView typeHeaderTextView,titleHeaderTextView,dateTimeHeaderTextView;
public RecyclerViewHolder(View itemView, int viewType) {
super(itemView);
if(viewType==TYPE_LIST){
typeTextView=itemView.findViewById(R.id.tv_cell_recording_recording_name);
imageView=itemView.findViewById(R.id.iv_cell_recordings);
dateTimeTextView=itemView.findViewById(R.id.tv_cell_recording_date_time);
view_type=1;
}else if(viewType==TYPE_HEAD){
typeHeaderTextView=itemView.findViewById(R.id.tv_type_head_layout);
titleHeaderTextView=itemView.findViewById(R.id.tv_title_head_layout);
dateTimeHeaderTextView=itemView.findViewById(R.id.tv_date_time_head_layout);
view_type=0;
}
}
}
}
DEf0 and HIJ 0 are not displayed in the recyclerview. I am not able to understand why they are not displaying in my recyclerview. I have no errors in my log. Any help would be greatly appreciated
You are doing it in wrong way....
You are adding five items in recyclerview, but consider first is header.
So this takes your first item as header, and you see other four items.
What you need to do is, pass dummy item as first item and then add your 5 items.
this way you can solve your problem.
You can try this way:
recordingArrayList.add(new Recording(R.drawable.ic_launcher,"", ""));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[0],lines[1]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[2],lines[3]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[4],lines[5]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[6],lines[7]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[8],lines[9]));
or you can also do it as below:
change Adapter code
#Override
public int getItemCount() {
return recordingArrayList.size() + 1;
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
Recording recording;
if(holder.view_type==TYPE_LIST){
recording=recordingArrayList.get(position - 1);
...
}else if (holder.view_type == TYPE_HEAD){
holder.typeHeaderTextView.setText("TYPE");
holder.titleHeaderTextView.setText("TITLE");
holder.dateTimeHeaderTextView.setText("DATE/TIME");
}
}
but you need to verify for empty list in this way
Your recycler view might be hidden under the toolbar. Give a top margin of 56dp.
android:layout_marginTop="56dp"
Try this your first position is set your Title.
Use this
#Override
public int getItemViewType(int position) {
return TYPE_LIST;
}
Instead of this
#Override
public int getItemViewType(int position) {
if(position==0){
return TYPE_HEAD;
}
return TYPE_LIST;
}
What worked for me is that first I remove from the array any null value (since the first element could be null) and then I add null value again. That way I'm avoiding of duplicating null value. I don't use "if" or any adapter implemented methods so I made my app more efficient.
My code is as follow:
myArray.remove(null); // here I remove any preview added null value as first (0 position) element
myArray.add(0, null); //now I add null as first element
//this way I am avoiding showing content with a null values
I hope this helps someone
The toast is displayed because your card is there, but it's hidden by the toolbar. You can add some margin to the RecyclerView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="schemas.android.com/apk/res/android"
xmlns:app="schemas.android.com/apk/res-auto"
xmlns:tools="schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_marginTop:"?android:attr/actionBarSize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recyclerView" />
</RelativeLayout>
If you wants to add Header without passing first blank data from activity, than you need to add blank entry at first position inside your Adapter like this.
Replace this code inside your Adapter:
public RecordingsAdapter(ArrayList<Recording> recordingArrayList) {
this.recordingArrayList = recordingArrayList;
this.recordingArrayList.add(0,null);
}

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);

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

how to use preloader in Grid View in 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.

Categories

Resources