How can I prevent my findViewById method from being called too early? - java

So I've got a Dialog, which contains some editText fields (these are spread over 3 fragments, shown by a viewpager, in case this info matters). For an edit action, I want to create that dialog with some values already put in.
At the moment I'm trying to do it like this:
editButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
GeneralSettingsInitialInputDialog GSIID = new GeneralSettingsInitialInputDialog();
Bundle args = new Bundle();
args.putString("name", TitleTV.getText().toString());
args.putString("ip", IPaddressET.getText().toString());
args.putString("port", PortET.getText().toString());
args.putString("username", UsernameET.getText().toString());
args.putString("pass", PasswordET.getText().toString());
Log.d(tag, args.toString());
GSIID.setArguments(args);
GSIID.show(((Activity) context).getFragmentManager(), "GSIID");
This shows the onClickListener for the edit button (which is contained in a recyclerView. This particular bit comes from my Adapter).
After that, I tried this in the onCreateDialog method for the GSIID dialogFragment:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
ma = (MainActivity) getActivity();
dbHandler = DBHandler.getInstance(getActivity());
view = inflater.inflate(R.layout.fragment_generalsettingsviewpager, null);
mPager = (ViewPager) view.findViewById(R.id.pager);
mPager.setOffscreenPageLimit(3);
mPagerAdapter = new TestAdapter();
mPager.setAdapter(mPagerAdapter);
if (getArguments() != null) {
((EditText) view.findViewById(R.id.IDName)).setText(getArguments().getString("name"));
((EditText) view.findViewById(R.id.IDIPaddress)).setText(getArguments().getString("ip"));
((EditText) view.findViewById(R.id.IDPort)).setText(getArguments().getString("port"));
((EditText) view.findViewById(R.id.IDUsername)).setText(getArguments().getString("username"));
((EditText) view.findViewById(R.id.IDPassword)).setText(getArguments().getString("pass"));
}
// Build Dialog
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view)
.setTitle("Setup Device")
.setMessage("Please add all required details for your Raspberry Pi here.")
.setPositiveButton("Next", null)
.setNegativeButton("Cancel", null);
return builder.show();
}
This returned a NPE, saying I was trying to use setText on a null, so view.findViewById() is returning null. I thought I'd fix that by moving this code to the onStart() method, to make sure everything is there before I try to set stuff on it, but I'm still getting the same error.
All this time, I'm noticing that the dialog does NOT open before the error occurs, so I'm guessing the findViewById() method is still called too soon, but I don't know how to fix that.
I have tested to make sure my code is not broken, by having the above code run when a button on the GSIID dialog is pressed (so the dialog is opened then). This did indeed work.
So, basically: How can I prevent this findViewById method from being called too early?

Most likely by looking up views in onCreateView() by calling the lookups on the view you're returning from this method.

You need to master the life-cycle of an Activity in android this link and this link can help you to understand the sequence of function calls in each step of the life-cycle.
In most cases you have your views in onCreatView() so it is reasonable to put your findViewById there but in other cases you should make sure the view has been inflated before you call findViewById

Well, my day is saved, thanks to this post.
Basically, you just need a method inside your custom PagerAdapter that returns the view for the index you give it.
CustomAdapter
New: Constructor (I believe that's what it's called)
private View view0 = null;
private View view1 = null;
private View view2 = null;
private View viewError = null;
public TestAdapter(LayoutInflater inflater) {
view0 = inflater.inflate(R.layout.fragment_generalsettingsinputdialog1, null);
view1 = inflater.inflate(R.layout.fragment_generalsettingsinputdialog2, null);
view2 = inflater.inflate(R.layout.fragment_generalsettingsinputdialog3, null);
viewError = inflater.inflate(R.layout.fragment_viewpagererror, null);
}
Changed: instantiateItem()
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View instView = getViewAtPosition(position);
instView.setTag("layoutThingy"+position);
container.addView(instView);
instView.requestFocus();
return instView;
}
New: getViewAtPosition()
public View getViewAtPosition(int position) {
View view = null;
switch(position) {
case 0:
view = view0;
break;
case 1:
view = view1;
break;
case 2:
view = view2;
break;
default:
view = viewError;
}
return view;
}
Other stuff
When initialising PagerAdapter, make sure you pass a LayoutInflater as an argument. For me it was like this: mPagerAdapter = new TestAdapter(getActivity().getLayoutInflater());
Now, I did this in my onStart() method, but I'm guessing you can do this pretty much everywhere.
View page1 = mPagerAdapter.getViewAtPosition(0);
View page2 = mPagerAdapter.getViewAtPosition(1);
View page3 = mPagerAdapter.getViewAtPosition(2);
if (getArguments() != null) {
((EditText) page1.findViewById(R.id.IDName)).setText(getArguments().getString("name"));
((EditText) page2.findViewById(R.id.IDIPaddress)).setText(getArguments().getString("ip"));
((EditText) page2.findViewById(R.id.IDPort)).setText(getArguments().getString("port"));
((EditText) page3.findViewById(R.id.IDUsername)).setText(getArguments().getString("username"));
((EditText) page3.findViewById(R.id.IDPassword)).setText(getArguments().getString("pass"));
}
This properly finds all my EditText's, and should properly find everything I put in my ViewPager. Great! Thanks all for trying to help me, and of course a big thank you to cYrixmorten, with his great post.

Related

How to change the background color of every item in a ListView?

I am developing an app which has a text message interface (something like Facebook Messenger, Whatsapp, etc). I want to be able to change the background color of all the chat bubbles (a ListView of TextViews) sent by the user when they pick a new color (in a NavigationView).
However, with the current code that I have, I only am able to change the color after the EditText used to compose the message is clicked again. Or I am able to only edit the first bubble sent, but as soon as the color is changed.
Here's what I tried :
ItemColor1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Toast.makeText(activity, "Couleur mise à jour", Toast.LENGTH_SHORT).show();
currentTheme = position;
SharedPreferences.Editor editor = pref.edit();
editor.putInt("indexColorSelected",currentTheme);
editor.apply();
chatAdapter.notifyDataSetChanged();
//the following changes only the first message sent
for(int i=0; i<chatAdapter.getCount(); i++){
ChatData message = chatMessageList.get(position);
TextView msg = activity.findViewById(R.id.text);
msg.setText(message.body);
msg.setBackgroundResource(R.drawable.user_color1);
}
}
});
ChatData is a custom Class that I created which looks like this :
public class ChatAdapter extends BaseAdapter {
private static LayoutInflater inflater = null;
private ArrayList<ChatData> chatMessageList;
private Context mContext;
ChatAdapter(Activity activity, ArrayList<ChatData> list) {
mContext = activity;
chatMessageList = list;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
...
}
Color drawable:
<corners
android:bottomRightRadius="5dp"
android:radius="40dp"/>
<gradient
android:angle="45"
android:endColor="#01f1fa"
android:startColor="#0189ff"
android:type="linear" />
</shape>
getView() method of the Adapter:
public View getView(int position, View convertView, ViewGroup parent) {
ChatData message = chatMessageList.get(position);
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.msglist, parent, false);
TextView msg = vi.findViewById(R.id.text);
msg.setText(message.body);
LinearLayout layout = vi.findViewById(R.id.message_layout);
LinearLayout parent_layout = vi.findViewById(R.id.message_layout_parent);
inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// if message is mine then align to right
if (message.isMine) {
layout.setGravity(Gravity.RIGHT);
int couleurBubble = getCouleurSelectionnee();
switch(couleurBubble){
case R.color.c1: msg.setBackgroundResource(R.drawable.user_color1); break;
case R.color.c2: msg.setBackgroundResource(R.drawable.user_color2); break;
case R.color.c3: msg.setBackgroundResource(R.drawable.user_color3); break;
case R.color.c4: msg.setBackgroundResource(R.drawable.user_color4); break;
case R.color.c5: msg.setBackgroundResource(R.drawable.user_color5); break;
case R.color.c6: msg.setBackgroundResource(R.drawable.user_color6); break;
case R.color.c7: msg.setBackgroundResource(R.drawable.user_color7); break;
case R.color.c8: msg.setBackgroundResource(R.drawable.user_color8); break;
default: break;
}
parent_layout.setGravity(Gravity.RIGHT);
}
// If not mine then align to left
else {
layout.setGravity(Gravity.LEFT);
msg.setBackgroundResource(R.drawable.bot_chat);
parent_layout.setGravity(Gravity.LEFT);
}
return vi;
}
I don't really know where to go from here so any kind of help would be appreciated. If you want me to provide more code, let me know and I will.
Thank you.
I'm sharing how I would do it. Maybe, this can help you.
There's some strange issue because you are calling notifyDataSetChanged(). This would be enough to re-draw all message bubbles.
My ideia is:
Add a int variable to the adapter class (mColorResource). This variable will point to the proper drawable that should be used (like R.drawable.user_color1).
public class ChatAdapter extends BaseAdapter {
int mColorResource;
ChatAdapter(Activity activity, ArrayList<ChatData> list, int initialColorResource) {
mContext = activity;
chatMessageList = list;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// You must receive the color on the construtor
mColorResource = initialColor;
}
// Use this method to update the color (when user select a new color)
public void setColor(int newColorResource) {
mColorResource = newColorResource;
}
public View getView(int position, View convertView, ViewGroup parent) {
...
// Note how this if-else is cleaner now
if (message.isMine) {
layout.setGravity(Gravity.RIGHT);
msg.setBackgroundResource(mColorResource);
parent_layout.setGravity(Gravity.RIGHT);
} else {
layout.setGravity(Gravity.LEFT);
msg.setBackgroundResource(R.drawable.bot_chat);
parent_layout.setGravity(Gravity.LEFT);
}
...
}
}
Then, when a color is selected, find the proper drawable based on the view clicked and pass it to the adapter:
ItemColor1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Toast.makeText(activity, "Couleur mise à jour", Toast.LENGTH_SHORT).show();
currentTheme = position;
SharedPreferences.Editor editor = pref.edit();
editor.putInt("indexColorSelected", currentTheme);
editor.apply();
// Here, you send the proper drawable...
// I'm not sure how you convert color selected to the drawable
// So, add your logic to convert the button clicked to a drawable here
// like R.drawable.user_color1
chatAdapter.setColor(R.drawable.NAME_OF_THE_COLOR);
// Request to re-draw all items from the list (all bubbles)
chatAdapter.notifyDataSetChanged();
}
});
Also, on your activity, you create the adapter with the last used color. Something like:
#Override
protected void onCreate(#Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
// Set a default color (if user is open you app for the first time)
int chatColor = R.drawable.user_color1;
// Add your logic to read the shared preference and convert that last color used to a valid drawable.
// Like chatColor = pref.getInt(indexColorSelected, R.drawable.user_color1) etc....
// Set the color in the adapter.
chatAdapter = newAdapter(this, mChatDataList, chatColor);
}

void android.widget.ImageView.setEnabled(boolean)' on a null object reference

I am using a simple java library file for Undo and Redo text as shown in the tutorial and sample android app but for me when I run the app it shows me the following error
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setEnabled(boolean)' on a null object reference
at com.apps.primalnotes.Fragments.EditorFragment.textAction(EditorFragment.java:1023)
at com.apps.primalnotes.Fragments.EditorFragment.onCreateView(EditorFragment.java:84)
Following is the library and method I am following on GitHub enter link description here
And exactly i am doing the following
EditorFragment extends Pantalla implements TextUndoRedo.TextChangeInfo, View.OnClickListener{
private TextUndoRedo TUR;
private ImageView undo, redo;
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.editor, container, false);
getActivity().setTitle("Editor");
setHasOptionsMenu(true);
imm =(InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
base = new DataBase(context, null);
text = (EditText) view.findViewById(R.id.texto);
undo = (ImageView)view.findViewById(R.id.undo);
redo = (ImageView)view.findViewById(R.id.redo);
TUR = new TextUndoRedo(text, this);
textAction(); "Showing error here"
undo.setOnClickListener(this);
redo.setOnClickListener(this);
}
#Override
public void textAction() {
undo.setEnabled(TUR.canUndo()); "Showing error here"
redo.setEnabled(TUR.canRedo());
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.undo:
TUR.exeUndo();
break;
case R.id.redo:
TUR.exeRedo();
break;
Your code doesn't have a "setContentView(R.layout.{file name of layout})".
Could you check it? It should be performed before using findViewById method.
Here the code from the Github source
btn_undo = (Button) findViewById(R.id.btn_undo);
btn_undo.setOnClickListener(this);
btn_redo = (Button) findViewById(R.id.btn_redo);
btn_redo.setOnClickListener(this);
And here the code from your code :
text = (EditText) view.findViewById(R.id.texto);
undo = (ImageView)view.findViewById(R.id.undo);
redo = (ImageView)view.findViewById(R.id.redo);
TUR = new TextUndoRedo(text, this);
The sample using Button for the undo/redo and you using ImageView. Check what is your ImageView ID in xml. Same with other here, your undo/redo ImageView is Null.
Check your XML. Your ImageView for undo & redo should have an id that looks like this,
android:id="#+id/undo
or
android:id="#+id/redo"

Finding Gridlayout in a Fragment

I have been trying to figure out how to find a Gridlayout in a fragment using findViewById. I've looked everywhere and am surprised to not have found this instructed by anyone in a similar situation of mine. I have used a tab layout in android studios, the tabs are different fragments, and within them are Gridlayouts which have cardviews that open new activities. I have provided the code below to show what I am working with:
public class PCpage extends Fragment {
GridLayout pcGrid;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mainPc = inflater.inflate(R.layout.pc_main, container, false);
return mainPc;
pcGrid = (GridLayout) mainPc.findViewById(R.id.pcGrid);
setSingleEvent(pcGrid);
}
private void setSingleEvent(GridLayout pcGrid){
for(int i =0; i<pcGrid.getChildCount();i++){
CardView cardView = (CardView)pcGrid.getChildAt(i);
final int acterI = i;
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(acterI == 0){
Intent intent = new Intent(PCpage.this.getActivity(), Parsecards.class);
startActivity(intent);
}
else if(acterI == 1){
Intent intent = new Intent(PCpage.this.getActivity(), Parsecards.class);
startActivity(intent);
}
});
}
}
}
The following line doesn't seem to want to work out and is returning an error "unreachable statement":
pcGrid = (GridLayout) mainPc.findViewById(R.id.pcGrid);
Any feedback on why this is happening or how to fix this and make it work would be greatly appreciated!
Anything after your return statement will not be executed; the method returns a value and completes. Move the line to somewhere before your return statement.
You are returning mainPc before doing this:
pcGrid = (GridLayout) mainPc.findViewById(R.id.pcGrid);
setSingleEvent(pcGrid);
so just move the return mainPc as the last line in the onCreateView
i think you must put this line :
return mainPc;
after this line :
setSingleEvent(pcGrid);

Custom adapter's asynchronous behaviour

I have created my own custom adapter class in my android app and I am calling it from one of my activity. I am adding some elements to the view from the adapter class and I need to access those variables from my activity class.
Now, ideally I would expect it to fill the view and then execute the further code in my activity class, but adapter class is taking some time to populate the view and in the meanwhile further code in my activity class is getting executed where no such elements have been added yet.
How do I handle this situation? I come from a js background. Do we have something like promises in java?
According to the answers I have my changed my code to this:
public class HomeActivity extends Activity {
GridView grid;
String text[] = {"Calendar","Uber","Weather","News","Youtube","Clock","Email","Maps","Twitter","Facebook"};
String list_app_name[] = {"calendar","uber","weather","news","youtube","clock","email","maps","twitter","facebook"};
String id_button[] = {"button_calendar","button_uber","button_weather","button_news","button_youtube","button_clock","button_email","button_maps","button_twitter","button_facebook"};
int image[] = {R.drawable.social_icons1,R.drawable.social_icons2,R.drawable.social_icons3,R.drawable.social_icons4,
R.drawable.social_icons5,R.drawable.social_icons6, R.drawable.social_icons7,R.drawable.social_icons8,
R.drawable.social_icons9,R.drawable.social_icons10};
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_home);
//setting up the adapter for gridView
grid = (GridView)findViewById(R.id.simpleGrid);
ImageAdapter ia = new ImageAdapter(this,image,text,id_button);
grid.setAdapter(ia);
ia.notifyDataSetChanged();
try {
initStateOfApps();
} catch (JSONException e) {
e.printStackTrace();
}
}
public void initStateOfApps() throws JSONException {
Log.d("here","here");
ArrayList<String> list = getEnabledApps();
Log.d("apps",list.toString());
for(int i=0;i<list.size();i++) {
String app_name = list.get(i);
ToggleButton button=null;
if(app_name.equals("calendar")) {
button = (ToggleButton)findViewById(R.id.button_calendar);
button.setChecked(true);
}
}
}
}
So what is happening is that I am creating some toggle buttons that are getting populated in the ImageAdapter class that I wrote.
Once the ImageAdapter is called, I call the notifydatasetchanged() on the adapter in order to update the view.
What I am doing inside the adapter is giving each of the toggle buttons some custom ID I wrote in res/values/ids.xml.
After using setId on each of the toggle buttons, I try using that ID in my activity class but it gives me nullPointerException in the initStateOfApps() where I am trying to change the state of button.
So even after using the notifyDataSetChanged it is still behaving the same.
ImageAdapter.java
public class ImageAdapter extends BaseAdapter {
private Context context;
private final int item_image[];
private final String item_text[];
private final String button_id[];
public ImageAdapter(Context context, int item_image[], String[] item_text,String[] button) {
this.context = context;
this.item_image = item_image;
this.item_text = item_text;
this.button_id = button;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
// get layout from custom_gridview.xml
gridView = inflater.inflate(R.layout.item, null);
// set value into imageview
final ImageView image = (ImageView) gridView.findViewById(R.id.item_image);
image.setImageResource(item_image[position]);
// set value into textview
TextView text = (TextView) gridView.findViewById(R.id.item_text);
text.setText(item_text[position]);
final ToggleButton button_ = (ToggleButton) gridView.findViewById(R.id.item_button);
if(position==0) {
button_.setId(R.id.button_calendar);
image.setId(R.id.image_calendar);
}
button_.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton toggleButton, boolean isChecked)
{
if(context.getResources().getResourceEntryName(toggleButton.getId()).equals("button_calendar")) {
if(isChecked) {
try {
setStateOfApp("calendar","true");
} catch (JSONException e) {
e.printStackTrace();
}
Intent intent = new Intent(context, GoogleApp.class);
((Activity) context).startActivityForResult(intent,10);
} else {
try {
setStateOfApp("calendar","false");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
} else {
gridView = (View) convertView;
}
return gridView;
}
}
You are trying to access View which is not a part of Activity's content view. So you can't access that view directly.
button = (ToggleButton)findViewById(R.id.button_calendar); // will return null
This ToggleButton will be null because findViewById will fail to find out ToggleButton in current content view because that view is present in your Adapter not in content view.
And you are getting nullpointerException because you are trying to access property on null view.
button.setChecked(true); // This button is null
In java we have <Future>, but I don't think it's what you're looking for.
The adapter (extending BaseAdaper) behaviour lets you create the adapter and, even in a second moment, change underlying data via getAdapter().setData() or whatever method you choose to add.
From this perspective, the adapter is a "stupid" component acting as A View containers, you should retrieve data elsewhere (CursorAdapter is different).
So, in your Activity, fill the adapter with needed data and, when finished, call adapter.notifyDatasetChanged(). This will inform the adapter that its own data has changed and it must refresh views
Yes, ideally, the population of the adapter should be coming from the outside. The adapter should really just take in a list of data and map that data to the views. For example, some method or task in the Activity could produce a list of data (probably asynchronously...since you mentioned it) that you then pass into the adapter and then you can notifyDataSetChanged() if you need to.
I can't see your code, but if for some reason the data is truly required to be populated from inside the adapter, you could use an event bus and subscribe to it in the Activity. I would recommend going with the first option, but here are some links if you choose to use an event bus:
https://github.com/greenrobot/EventBus
http://square.github.io/otto/
As per my understanding with your question
You are not properly managed the adapter data in your activity.
If any of the data or code interlinked with your adapter data or values
Then you can start those code after you retrieve the values or data and update the view in your activity.
Please note that use Viewholders in adapter to avoid slow populating and scrolling in listviews.
Viewholders will smooth your process.
I personally suggest you that
Please go with Recyclerview and RecyclerViewAdapter.
So many Android developers are using it.
If you have background tasks in adapter you can prefer to use RX Java or EventBus
If you provide the code
It's better for us to suggest exact solution

Refresh ListView with ArrayAdapter

I'm parsing a web service to display in a listView backed by my own subclass of ArrayAdapter. The data is static ArrayList<Wait> in Application.java. You'll see it referenced by App.getWaits().
I use a simple refresh method for when there's new data. I've confirmed that it's being updated but it only renders if I navigate away and then return to the view.
In the past I've been able to refresh the listView by calling notifyDataSetChanged() on the adapter but right now none of these have worked for me. Thanks for taking a look... any ideas!?
//1 This is how I'd normally update the listView dynamically, but not tonight.
adapter.notifyDataSetChanged();
//2 It's the same thing really, so no good.
((WaitAdapter) list.getAdapter()).notifyDataSetChanged();
//3 Saw this as the answer to a similar question, doesn't work.
adapter.getWaits().clear();
adapter.getWaits().addAll(App.getWaits());
adapter.notifyDataSetChanged();
//4 Called in onCreate but tried a 2nd time in refresh() to manually reset adapter, doesn't work.
adapter = new WaitAdapter(getHost().getApplicationContext(), App.getWaits());
list.setAdapter(adapter);
//5 Kinda the same thing, new adapter, reset adapter... also no good.
WaitAdapter adapter = new WaitAdapter(getHost().getApplicationContext(), App.getWaits());
list.setAdapter(adapter);
//6 I read ArrayAdapter keeps its own reference to initial data object but this fails too.
adapter = null;
adapter = new WaitAdapter(getHost().getApplicationContext(), App.getWaits());
list.setAdapter(adapter);
*Update to share my WaitAdapter.java.
public class WaitAdapter extends ArrayAdapter<Wait> {
private LayoutInflater inflater;
private ArrayList<Wait> waits;
public WaitAdapter(Context context, ArrayList<Wait> data) {
super(context, R.layout.list_item_wait, data);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
waits = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item_wait, parent, false);
holder = new ViewHolder();
holder.checkpointName = (TextView) convertView.findViewById(R.id.checkpointName);
holder.delayAmount = (TextView) convertView.findViewById(R.id.delayAmount);
holder.timeReported = (TextView) convertView.findViewById(R.id.timeReported);
holder.dateReported = (TextView) convertView.findViewById(R.id.dateReported);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Wait wait = waits.get(position);
holder.checkpointName.setText(wait.getName());
holder.delayAmount.setText(wait.getDelayInMinutes());
holder.timeReported.setText(wait.getTimeLabel());
holder.dateReported.setText(wait.getDateLabel());
return convertView;
}
#Override
public boolean isEnabled(int position) {
return false;
}
static class ViewHolder {
TextView checkpointName;
TextView delayAmount;
TextView timeReported;
TextView dateReported;
}
}
12/14/14 Update: General implementation background.
At launch the App class starts WaitAsyncTask, which parses remote XML to fill its ArrayList waits. I'll access these waits in a few places so this way I keep them global.
WaitFragment, working with WaitAdapter, displays waits in a ListView and listens for changes to waits. User's can post waits to the web service via an AlertDialog. A successful response executes WaitAsyncTask again, updating the waits object, triggering a WaitFragment refresh().
Console logs and the web service confirm this flow of control and that waits gets updated. If I leave WaitFragment then return, it shows the updated waits. The code posted with comments #1-6 are what I've tried inside of the refresh() to update the ListView.
I use this general approach with other data and fragments in this app and their UIs refresh as intended, but none are listViews. I'm not sure I could post more source without redacting most of it but I'll share my findings once I get it working. I haven't had trouble with ListView before, but it'll be something embarrassing for sure. Thanks to everyone who took a little time :)
Just create a method in Adapter class to update/refresh the listview as follows,
public class WaitAdapter extends ArrayAdapter<Wait> {
private LayoutInflater inflater;
private ArrayList<Wait> waits;
public WaitAdapter(Context context, ArrayList<Wait> data) {
super(context, R.layout.list_item_wait, data);
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
waits = data;
}
/**
* Update content
*/
public void updateListContent(ArrayList<Wait> data)
{
waits = data;
notifyDataSetChanged();
}
}
In your acivity class, just call this adapter method to update the content. Refer the below code
Note:Dont clear the array content of the adapter.
//Dont clear the arraylist of adapter
adapter.updateListContent(App.getWaits());
This may help you.

Categories

Resources