ListView Updating a single row - java

I want to update a single row in my listview with different content once i press a button. I know i can use notifydatasetchanged() but that would update the whole listView.
I have read this answer and it fits perfectly for what I want to do.
I have done a listview with 5 rows and when I press the button I want to update the 4th row with a different text. I dont want to set the text programatically since this is just a dummy project just to see if refreshing a single row is possible and my real project is much more complex than just a textview.
So my question is: can i use getView() to update a single row in a listview?
Here is my code:
my Activity:
public class MainActivity extends Activity {
public ListView list1;
public listAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list1 = (ListView) findViewById(R.id.my_list);
adapter = new listAdapter(this);
list1.setAdapter(adapter);
Button button1 = (Button) findViewById(R.id.my_button);
button1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
adapter.setText("Different text");
View row2Update = list1.getChildAt(3);
list1.getAdapter().getView(3, row2Update, list1);
}
});
}
}
My adapter :
public class listAdapter extends BaseAdapter{
public Activity activity;
public String text="Normal Text";
public listAdapter(Activity activity){
this.activity = activity;
}
public void setText(String text){
this.text = text;
}
public int getCount() {
return 5;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = activity.getLayoutInflater();
LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.row_layout, null);
TextView textView = (TextView) rowView.findViewById(R.id.row_text);
textView.setText(text);
return rowView;
}
}
This is what the activity looks like:
But when I press my button nothing changes

You cannot call the getView() method of the adapter yourself. The adapter's getView() method is is only called, when
The listview is create
when the user scrolls the list view
when notifysetdatachanged() is called.
All these are done by the OS. GetView() is called for all the rows in the listview. It is not called for just a single row. So, if you want to change the rows, you have to provide the data again in a String[], ArrayList<> etc
If you want different text to appear for for a single row, onClick() of a button - you can do this
public class listAdapter extends BaseAdapter{
public Activity activity;
public ArrayList<String> text;
public listAdapter(Activity activity){
this.activity = activity;
}
public void setText(ArrayList<String> text){
this.text = text;
}
public int getCount() {
return 5;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = activity.getLayoutInflater();
LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.row_layout, null);
TextView textView = (TextView) rowView.findViewById(R.id.row_text);
textView.setText(text[position]);
return rowView;
}
}
And in your Activity :
list1 = (ListView) findViewById(R.id.my_list);
adapter = new listAdapter(this);
String[] entries={"Normal Text","Normal Text","Normal Text","Normal text","Normal text"};
ArrayList<String> text=Arrays.asList(entries);
adapter.setText(text);
list1.setAdapter(adapter);
Button button1 = (Button) findViewById(R.id.my_button);
button1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
text.set(3,"Different Text");
adapter.setText(text);
list1.setAdapter(adapter);
}
});
There is another way of doing it also as #Andy suggested in one of the comments :
listViewPeople.setOnItemClickListener(new ListView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View v, int position, long l) {
//IF YOU WANT TO CHANGE THE CONTENT OF THE ROW CLICKED
if(position == someNumber) {
text.set(position,"different Text");
list1.setAdapter(text);
}
}
});
Sorry for the bold text. For some reason the CTRL+K is not working for the above code.

Related

How to change multiple image at once in gridview in Android?

I'm working on AndroidStudio with Java.
I have many imageviews inside gridview.
and I'm trying to apply click event which affects multiple imageviews at the same time
what I want to do is :
when one imageview is clicked another imageview, which is not been clicked to change its image.
for example, there is two imageview A and B in same gridview. if I click A imageview, both A and B imageview set to different imagesources.
what I can do is change only clicked imageview.
I want to know how to access the unclicked items in gridview.
I made onclick listener inside adapter.
public View getView(int position, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.ingrid,parent,false);
ImageView blackorwhite = convertView.findViewById(R.id.blackOrWhite);
Integer val = mData.get(position);
blackorwhite.setImageResource(blockColor.get(val));
blackorwhite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
blackorwhite.setImageResource(R.color.white);
}
});
you can make an interface callback to know which item gets clicked for example this is ur interface
interface OnClickListener {
void onClick(int position)
}
and pass this interface to ur Adapter,
and in the getView method whenever a view get clicked u can call the onClick method of the interface
this is example code
interface OnClickListener {
void onClick(int position);
}
public class GridViewAdapter extends BaseAdapter {
private List<String> list;
private OnClickListener listener;
private Context context;
public GridViewAdapter(Context context,List<String> list,OnClickListener listener){
this.listener = listener;
this.context = context;
this.list = list;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(ur layout);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onClick(position);
}
});
return view;
}
}
To initiate The adapter, u can use this code,
GridViewAdapter adapter = new GridViewAdapter(context, imageList, new OnClickListener() {
#Override
public void onClick(int position) {
// this method called every time an view get clicked
// and u can change the DataSet which now is imageList
// imageList.set(position,"something new ");
// after the change of DataSet u should cal the notifyDataSetChanged
adapter.notifyDataSetChanged();
}
});

update the text of a listView row

I want my listView to be updated after clicking on a row (or any event, but let's focus on click).
I did something, but it updates more than one row (maybe it updates the first visible row and the one after the last visible...).
Here is the full code
Activity code
DatabaseHandler colisageBase;
ListView listView;
List<Site> sites;
String id_tournee;
SiteAdapter siteAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_site_choice);
Intent intent = getIntent();
id_tournee = intent.getStringExtra("idTourneeSelectionnee");
this.listView = findViewById(R.id.list_view_site);
this.colisageBase = new DatabaseHandler(this);
sites = colisageBase.selectAllSite(id_tournee);
siteAdapter = new SiteAdapter(SiteChoiceActivity.this, sites);
listView.setAdapter(siteAdapter);
colisageBase.closeDB();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Site selectedSite = sites.get(position);
selectedSite.setIsBarred(true);
sites.set(position, selectedSite);
siteAdapter.notifyDataSetChanged();
//goToOperationActivity(selectedSite.SiteOut());
}
});
Adapter code
public class SiteAdapter extends ArrayAdapter<Site> {
public SiteAdapter(Context context, List<Site> sites) {
super(context, 0, sites);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_site,parent, false);
}
SiteViewHolder viewHolder = (SiteViewHolder) convertView.getTag();
if(viewHolder == null){
viewHolder = new SiteViewHolder();
viewHolder.heure_supposee = convertView.findViewById(R.id.heure_supposee);
viewHolder.libelle_site = convertView.findViewById(R.id.libelle_site);
viewHolder.logo_telephone = convertView.findViewById(R.id.logo_phone);
convertView.setTag(viewHolder);
}
Site site = getItem(position);
viewHolder.heure_supposee.setText(site.getHeure_supposee());
viewHolder.libelle_site.setText(site.getLibelle_site());
viewHolder.logo_telephone.setVisibility(View.INVISIBLE);
if (site.getSur_appel().equals("O")) viewHolder.logo_telephone.setVisibility(View.VISIBLE);
if (site.isBarred()) viewHolder.libelle_site.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG);
return convertView;
}
#Override
public void notifyDataSetChanged()
{
super.notifyDataSetChanged();
}
private class SiteViewHolder{
public TextView heure_supposee;
public TextView libelle_site;
public ImageView logo_telephone;
}
}
Please suggest what's wrong with the code.
The answer was given in the comments by I_A_Mok, but i have to add more details:
In the case of a cell, when you do an action in an "if" condition , you usually have to do the opposite in an "else" condition.
In my case, after my condition where I strike through text, I had to add an else condition where I don't strike through text.
if (site.isBarred()){
viewHolder.libelle_site.setPaintFlags(viewHolder.libelle_site.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}else {
viewHolder.libelle_site.setPaintFlags(viewHolder.libelle_site.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
}

Update view inside custom adapter, after pressing the button

I need to update progress bar after i press the button inside my custom adapter.
Only when i declared view value as final i can do that. But it doesn't suit me.
What are the right solutions to do this ?
My custom adapter source:
public class DownloadListAdapter extends BaseAdapter implements DownloadManagerListener{
Context ctx;
LayoutInflater lInflater;
ArrayList<Product> objects;
View view;
DownloadListAdapter(Context context, ArrayList<Product> products) {
ctx = context;
objects = products;
lInflater = (LayoutInflater) ctx
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
view = convertView;
if (view == null) {
view = lInflater.inflate(R.layout.item, parent, false);
}
Product p = getProduct(position);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
progressBar.setProgress(p.size);
Button btSet = (Button) view.findViewById(R.id.btSet);
btSet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//this does not work
progressBar.setProgress(100);
//this doesn't work too, it will work only when view will declared as final
ProgressBar pb = (ProgressBar) view.findViewById(R.id.progressBar);
pb.setProgress(100);
}
});
return view;
}
#Override
public void OnDownloadStarted(long taskId) {
//This method should also have access to view
}
#Override
public int getCount() {
return objects.size();
}
#Override
public Object getItem(int position) {
return objects.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
Product getProduct(int position) {
return ((Product) getItem(position));
}
}
As I understood when I read your code, you want to start download indicator (in this case, indicator is your progress bar). So you can try this way:
1. I assume that this is your DownloadManagerListener or you can change yours to this:
public interface DownloadManagerListener {
void OnDownloadStarted(long taskId, View view);
}
2. Change your button listener like this:
btSet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ProgressBar progress = ((LinearLayout) v.getParent())
.findViewById(R.id.progressBar);
OnDownloadStarted(0, progress);
}
});
In this I assumed that your layout (R.layout.item) like that:
<LinelearLayout>
...
<ProgressBar android:id="#+id/progressBar"/>
...
<Button android:id="#+id/btSet"/>
</LinearLayout>
3. Finally your method OnDownloadStarted like this:
public void OnDownloadStarted(long taskId, View view) {
ProgressBar progressBar = (ProgressBar) view;
progressBar.setProgress(0);
}
UPDATE 1:
Base on author comment. I suggest following point:
1. Remove View view; from member off class and in getview method. Because when list view is populated, view reference to last item that has been call getView. So view member of adapter class is meaningless.
2. Change class which like this:
public class DownloadListAdapter extends BaseAdapter implements DownloadManagerListener{
Context ctx;
LayoutInflater lInflater;
ArrayList<Product> objects;
HashMap<Integer, ProgressBar> mProductDownloaderMap = new HashMap<Integer, ProgressBar>();
3. Chang getView() method like this:
if (convertView == null) {
convertView = lInflater.inflate(R.layout.item, parent, false);
}
Product p = getProduct(position);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
Button btSet = (Button) view.findViewById(R.id.btSet);
mProductDownloaderMap.put(position, progressBar);
btSet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
OnDownloadStarted(position);// position is indicated taskID
}
});
4. On your dowload method:
public void OnDownloadStarted(long taskId) {
ProgressBar progressBar = mProductDownloaderMap.get(taskId);
progressBar.setProgress(0);
//Your download code here
}
Please let me know if I missunderstand your code/your purpose!
Also dont forget to mark this is anwsers if my answers is right for your question
Hope that help!
The view variable is global in the class so no need to make it final.
You should make the progressBar as final and change its progress inside button onClick method

How to use notifySetDataChange in adapter for refresh listview

I used fragment in my app and i'm using SQLite to save local data. But when I finished saving data, and I swipe the page, my listView is not refreshed with new data (Only showing old data). I have tried to provide a method notifyDataSetChanged() on my adapter, but it's not working.
My Base Adapter class :
public class LocalDataAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<LocalDataBean> data;
private static LayoutInflater inflater = null;
public LocalDataAdapter(Activity a, ArrayList<LocalDataBean> d) {
activity = a;
data = d;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public void setItem(ArrayList<LocalDataBean> data){
this.data = data;
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = inflater.inflate(R.layout.list_item, null);
TextView nama_konsumen = (TextView) v.findViewById(R.id.nama_konsumen);
TextView no_telp = (TextView) v.findViewById(R.id.no_telp);
TextView no_hp_cdma = (TextView) v.findViewById(R.id.no_hp_cdma);
TextView no_hp_gsm = (TextView) v.findViewById(R.id.no_hp_gsm);
LocalDataBean obj = (LocalDataBean) getItem(position);
nama_konsumen.setText(obj.getNamaKonsumen());
no_telp.setText(obj.getNoTelp());
no_hp_cdma.setText(obj.getNoCMDA());
no_hp_gsm.setText(obj.getNoGSM());
return v;
}
}
My fragment class :
public class LocalDataFragment extends Fragment {
View view;
Activity act;
SQLHandlerBean utilSql;
ArrayList<LocalDataBean> localdatabean = new ArrayList<LocalDataBean>();
LocalDataAdapter adapter;
ListView list;
public static final String TAG = LocalDataFragment.class.getSimpleName();
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.layout_local_data, null);
act = getActivity();
list = (ListView) view.findViewById(R.id.listViewLocalData);
utilSql = new SQLHandlerBean(this.act);
adapter = new LocalDataAdapter(act, localdatabean);
localdatabean = new ArrayList<LocalDataBean>();
list.setAdapter(adapter);
if (utilSql.ReadAllLocalData().size() < 1) {
Toast.makeText(act, "DATA EMPTY!", Toast.LENGTH_LONG).show();
} else {
localdatabean = utilSql.ReadAllLocalData();
Log.e(TAG, "TOTAL DATA : "+localdatabean.size());
adapter.setItem(localdatabean);
adapter.notifyDataSetChanged();
}
return view;
}
}
Is adapter.notifyDataSetChanged() placement correct?
No, the placement is not in the right place.
As you have placed the notifyDataSetChanged() inside of the onCreateView() method. It will be only invoked 1st time the fragment is launched.
Rather you can add a refresh button in your layout (or in you action bar). And along with the insertion/deletion method of the data, place the notifyDataSetChanged() at the bottom of the click event of that button.
By doing this user can refresh the page whenever they want.
And if you want to refresh the page by swipping the view then, SwipeRefreshLaoyout could be a perfect alternative.
You can check this blog.

Android Refresh ListActivity from BaseAdapter

I have a ListActivity and a custom adapter that extends BaseAdapter.
On each row of the ListView, there is a button and a few more views. onClickListener is declared in the adapter.
How can I refresh list view after button is clicked ?
Here is the code
List Activity:
.........
super.onCreate(savedInstanceState);
here im reading content from a file and then creating adapter with that content
adapter = new UvArrayAdapter(this, strarray3, strarray2, intarray);
setListAdapter(adapter);
..........
Adapter:
.......
public class UvArrayAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater linflater;
private TextView txt_1, txt_2, txt_3;
private ProgressBar pr1;
private String[] str1;
private String[] str2;
private String[] str3;
private Integer[] int1;
private class OnItemClickListener implements OnClickListener{
private int mPosition;
OnItemClickListener(int position){
mPosition = position;
}
#Override
public void onClick(View arg0) {
Log.v("TAG", "onItemClick at position" + mPosition);
}
}
public UvArrayAdapter(Context context, String[] s1, String[] s2, Integer[] i1) {
mContext = context;
str1 = s1;
str2 = s2;
int1 = i1;
linflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return str1.length;
}
#Override
public Object getItem(int arg0) {
return str1[arg0];
}
#Override
public long getItemId(int arg0) {
return arg0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = linflater.inflate(R.layout.uv_rowlayout, null);
}
convertView.setOnClickListener(new OnItemClickListener(position));
txt_1 = (TextView) convertView.findViewById(R.id.textView1);
pr1 = (ProgressBar) convertView.findViewById(R.id.progressBar1);
pr1.setProgress(int1[position]);
txt_1.setText(str1[position]);
txt_2 = (TextView) convertView.findViewById(R.id.textView2);
txt_2.setText(str2[position]+"mV");
Button btn = (Button) convertView.findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
Log.v("onClickListener", "button - clicked at position " position);
do some changes in mentioned file and after that i need to update the list view with new data
}});
return convertView;
}
}
adapter.notifyDataSetChanged(); // to notify the adapter that your data has been updated
Note: If you get any errors with the above line, you could try the following code (where mListView is the name of my ListView object)
((BaseAdapter) mListView.getAdapter()).notifyDataSetChanged();
Another way would be to invalidate the List so that it is redrawn form the updated data set once again.
mListView=(ListView) findViewById(R.id.MyListView);
mListView.invalidate();
Use notifyDataSetChanged()
adapter = new UvArrayAdapter(this, strarray3, strarray2, intarray);
setListAdapter(adapter);
UvArrayAdapter.notifyDataSetChanged();
// To make the adapter aware of the changes

Categories

Resources