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
Related
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();
}
});
I want to make a dialog that pops up if you click on a Name TextView in my ListView.
So I've been following this youtube tutorial: https://www.youtube.com/watch?v=ARezg1D9Zd0&t=511s and he makes a dialog that pops up from his MainActivity. But I want to pop it up from my ListView, so from my Adapter.
Because of that I can't call getSupportFragmentManager(). I think it's because my Adapter does extend ArrayAdapter<> instead of AppCompatActivity. Can anyone help me?
It goes wrong when I say: changeNameDialog.show(getSupportFragmetnManager(), "Change Name Dialog");
public class PlayersAdapter extends ArrayAdapter<Player> {
Tournament tournament = new Tournament();
private LayoutInflater Inflater;
public PlayersAdapter(#NonNull Context context, #NonNull List<Player> objects) {
super(context, R.layout.list_players,objects);
Inflater = LayoutInflater.from(context);
}
#NonNull
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
if (convertView == null) {
convertView = Inflater.inflate(R.layout.list_players, parent, false);
}
ImageView profilePictureButtonImageView = convertView.findViewById(R.id.profilePictureButtonImageView);
TextView namePlayerTextView = convertView.findViewById(R.id.namePlayerTextView);
TextView pointsTextView = convertView.findViewById(R.id.pointsTextView);
ImageView deleteButtonImageView = convertView.findViewById(R.id.deleteButtonImageView);
Player player = getItem(position);
profilePictureButtonImageView.setImageResource(player.getProfilePicture());
namePlayerTextView.setText(player.getName());
pointsTextView.setText(tournament.getPlayers().get(position).getTotalPoints() + "");
// Change name
namePlayerTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ChangeNameDialog changeNameDialog = new ChangeNameDialog();
changeNameDialog.show(getSupportFragmetnManager(), "Change Name Dialog");
}
});
return convertView;
}
}
Create an interface with a method in your Adapter class as follows:
public interface OnAdapterInteractionListener {
void showDialog();
}
Change the constructor of your Adapter class and receive your Activity / Fragment as OnAdapterInteractionListener in it. Save it as a global variable in your Adapter class. While calling this constructor from your Activity or Fragment, pass on this for OnAdapterInteractionListener.
private LayoutInflater Inflater;
private OnAdapterInteractionListener mListener;
public PlayersAdapter(#NonNull Context context, #NonNull List<Player> objects, OnAdapterInteractionListener listener) {
super(context, R.layout.list_players,objects);
Inflater = LayoutInflater.from(context);
mListener = listener;
}
Make your Activity / Fragment implement the adapter interface OnAdapterInteractionListener and implement its method as follows:
#Override
public void showDialog() {
ChangeNameDialog changeNameDialog = new ChangeNameDialog();
changeNameDialog.show(getSupportFragmentManager(), "Change Name Dialog");
}
Finally, in your Adapter, amend your onClick() method as follows:
namePlayerTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mListener != null) mListener.showDialog();
}
});
Hope it serves your purpose!
I have created a listview. Each item in list view has two UI elements. One is a textview and other is a number picker. Now the issue is that if i click on first number picker to change value, the fourth one also changes and vice versa. Here is my getview function
private class ViewHolder {
public TextView name;
public NumberPicker numberPicker;
public CustomListener listener;
}
public View getView(final int position, #Nullable View convertView, #NonNull final ViewGroup parent) {
ViewHolder holder;
View listItem = convertView;
currentCell=getItem(position);
currentCell.setPosition(position);
if (listItem == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
listItem = inflater.inflate(R.layout.organ_item, parent, false);
}
holder = new ViewHolder();
holder.name = (TextView) listItem.findViewById(R.id.organName);
holder.numberPicker = (NumberPicker)
listItem.findViewById(R.id.numberPicker);
holder.numberPicker.setMinValue(1);
holder.numberPicker.setMaxValue(10);
holder.numberPicker.setOnValueChangedListener(holder.listener);
holder.numberPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
currentCell=getItem(position);
View parentRow = (View) picker.getParent();
ListView mListView=(ListView)parentRow.getParent().getParent();
ConstraintLayout constraintLayoutView = (ConstraintLayout) mListView.getChildAt(currentCell.getPosition());
RelativeLayout relativeLayout = (RelativeLayout)constraintLayoutView.getChildAt(0);
NumberPicker p = (NumberPicker) relativeLayout.getChildAt(1);
if(position==currentCell.getPosition())
{
p.setValue(newVal);
}
else
{
p.setValue(oldVal);
}
}
});
//Set the name
TextView organName = (TextView)listItem.findViewById(R.id.organName);
organName.setText(QuickMeditationScreenInfo.getInstance().getScreenNameFromIndex(currentCell.getOrgan()));
return listItem;
}
Also even if i comment out the onValueChangeListener even then the same behaviour occurs which i assume is the default behaviour of number picker in a list. I have spent multiple hours on it but couldn't figure out the solution. I have also debugged the code and when i change a value, the debugger comes into the onValueChange code only once.
You need set numberpicker default value every time
holder = new ViewHolder();
holder.name = (TextView) listItem.findViewById(R.id.organName);
holder.numberPicker = (NumberPicker) ;
holder.numberPicker.setValue(defaultValue);//like this
Try to handle click event into adapter using interface like below
for example make one interface into adapter class ..
private onItemClick onItemClick;
public void setOnItemClick(DisplayAllData.onItemClick onItemClick) {
this.onItemClick = onItemClick;
}
public interface onItemClick{
void onItemSelected(int position); // pass your data
}
In getView() method like number listner called all logical code into activity or fragment.
holder.mTvName.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClick.onItemSelected(position);
}
});
In activity or fragment after adapter set into listview or recyclerview then
adapter not null then called below code..
allDataAdapter.setOnItemClick(new DisplayAllData.onItemClick() {
#Override
public void onItemSelected(int position) {
// here called all logical part
allDataAdapter.notifyDataSetChanged();
}
});
I have many ListActivity classes in my app that act pretty much the same : list with a property (TextView) on the left and a value (Button) on the right. When I press the button I want to do something like create a dialog. Because of the repetability, I decided to create a general custom ArrayAdapter like this :
public class GeneralTvBtnAdapter extends ArrayAdapter<SettingsProperty> {
private Context mContext;
private ArrayList<SettingsProperty> mProps;
private int mLayout;
private ButtonListener mListener;
public GeneralTvBtnAdapter(Context context, int tv_btn_layout, ArrayList<SettingsProperty> objects, ButtonListener listener) {
super(context, tv_btn_layout, objects);
mContext = context;
mProps = objects;
mLayout = tv_btn_layout;
mListener = listener;
}
public void updateValue (int position, String newValue) {
mProps.get(position).setValue(newValue);
notifyDataSetChanged();
}
private class ViewHolder {
TextView mName;
Button mValue;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
LayoutInflater mInflater = LayoutInflater.from(mContext);
convertView = mInflater.inflate(mLayout, null);
holder.mName = (TextView) convertView.findViewById(R.id.prop);
holder.mValue = (Button) convertView.findViewById(R.id.value);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.mName.setText(mProps.get(position).getName());
holder.mValue.setText(mProps.get(position).getValue());
holder.mValue.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mListener.onButtonClicked(position);
}
});
return convertView;
}
public interface ButtonListener {
void onButtonClicked (int position);
}
}
I want to know how can I remove the ButtonListeners listeners after the calling activity is destroyed.
P.S :SettingsProperty is a POJO with String name and String value and the tv_btn_layout is a layout with a TextView and a Button as described above.
if your intent is to remove your custom listener, you have to reset it to null. You can create a setter
public void setButtonListener (final ButtonListener listener) {
mListener = listener;
}
and call if from the outside with null. Just to be sure, before accessing mListener, check for null values
If your intention is not to call listener method if activity is destroyed then override your onfinish() of Activity and initialize the boolean flag.
private boolean IsActivityAlive;
#Override
protected void onDestroy() {
IsActivityAlive=true;
super.onDestroy();
}
And inside your interface method just check for boolean flag if it is false do the action required else ignore
void onButtonClicked (int position){
if(!IsActivityAlive){
//Do remaining task }
}
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.