i want to show an circle before updating the listview , everything is working fine, while doinbackground of async task fetch the data from server it shows the progressbar but while updating the listview it freezes for sometime and then listview is shown, i want to remove that freezing of progressbar before updating, here is my code
public class feeds extends AsyncTask<Void, Void, ArrayList<HashMap<String, String>>>{
protected void onPreExecute() {
// SHOW THE SPINNER WHILE LOADING FEEDS
linlaHeaderProgress.setVisibility(View.VISIBLE);
}
#Override
protected ArrayList<HashMap<String, String>> doInBackground(Void... params) {
new_request_feeds(); //here i am fetching data from server
return fetch;
}
protected void onPostExecute(ArrayList<HashMap<String, String>> result) {
// HIDE THE SPINNER AFTER LOADING FEEDS
linlaHeaderProgress.setVisibility(View.GONE);
if(result.size()!=0)
{
adapter=new CustomListAdapter(getActivity(), R.id.list_ongoing, result);
list.setAdapter(adapter);
}
else
{
Toast.makeText(getActivity(), "no feeds", 3000).show();
}// Here if you wish to do future process for ex. move to another activity do here
}
my getview()
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos=position;
System.out.println(position);
View v = convertView;
final ViewHolder holder;
if (v == null) {
LayoutInflater vi =
(LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.feed_row, null);
holder = new ViewHolder();
holder.like=(ImageButton) v.findViewById(R.id.like);
holder.share=(ImageButton) v.findViewById(R.id.share);
holder.report=(ImageButton) v.findViewById(R.id.report);
holder.headline_text = (TextView) v.findViewById(R.id.lar);
holder.topic_text = (TextView) v.findViewById(R.id.mt);
holder.count_likes = (TextView) v.findViewById(R.id.count_likes);
holder.count_shares = (TextView) v.findViewById(R.id.count_shares);
holder.image = (ImageView) v.findViewById(R.id.img1);
holder.image2 = (ImageView) v.findViewById(R.id.img2);
v.setTag(holder);
}
else
holder=(ViewHolder)v.getTag();
mSharedPreferences= v.getContext().getSharedPreferences("mypref", 0);
holder.headline_text.setText(" "+entries.get(pos).get(TAG_FFN)+" had a chance with "+entries.get(pos).get(TAG_IFN)+"! ");
holder.topic_text.setText(entries.get(pos).get(TAG_TOPIC));
holder.image.setTag(entries.get(pos).get(TAG_FTID));
holder.image2.setTag(entries.get(pos).get(TAG_ITID));
holder.count_likes.setText(entries.get(pos).get(TAG_LIKERS)+" likes");
holder.count_shares.setText(entries.get(pos).get(TAG_SHARERS)+" shares");
if(entries.get(pos).get(TAG_LIKED).equals("True"))
{
holder.like.setImageResource(R.drawable.like);
holder.like.setTag("True");
}
else
{
holder.like.setTag("False");
}
if(entries.get(pos).get(TAG_SHARED).equals("True"))
{
holder.share.setImageResource(R.drawable.share);
holder.share.setEnabled(false);
}
//=======================setting image of user==========================================//
// Loader image - will be shown before loading image
// whenever you want to load an image from url
// call DisplayImage function
// url - image url to load
// loader - loader image, will be displayed before getting image
// image - ImageView
imgLoader.DisplayImage((image_url.getimage(Long.parseLong(entries.get(pos).get(TAG_FTID))))[0],loader, holder.image);
imgLoader.DisplayImage((image_url.getimage(Long.parseLong(entries.get(pos).get(TAG_ITID))))[0],loader, holder.image2);
//====================================================================================//
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if((holder.image.getTag()).equals(mSharedPreferences.getString("USERID", null)))
{
Toast.makeText(v.getContext(), "Your profile", Toast.LENGTH_LONG).show();
}
else
{
Intent i=new Intent(v.getContext(),OtherProfilePage.class);
i.putExtra("Image_id",entries.get(pos).get(TAG_FTID));
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
(v.getContext()).startActivity(i);
}
}
});
holder.image2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(holder.image2.getTag().equals(mSharedPreferences.getString("USERID", null)))
{
Toast.makeText(v.getContext(), "Your profile", Toast.LENGTH_LONG).show();
}
else
{
Intent i=new Intent(v.getContext(),OtherProfilePage.class);
i.putExtra("Image_id", entries.get(pos).get(TAG_ITID));
(v.getContext()).startActivity(i);
}
}
});
holder.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(holder.like.getTag()=="True")
{
holder.like.setImageResource(R.drawable.like_pressed);
holder.like.setTag("False");
new sendlikes().execute("link");
}
else
{ holder.like.setImageResource(R.drawable.like);
holder.like.setTag("True");
new sendlikes().execute("link");
}
}
});
holder.share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.share.setImageResource(R.drawable.share);
holder.share.setEnabled(false);
new sendlikes().execute("http://gangster.cloudapp.net/share/",entries.get(pos).get(TAG_CID),mSharedPreferences.getString("person_id",null));
}
});
return v;
}
imageloader is a class that i used for caching the images.
Try to put this line linlaHeaderProgress.setVisibility(View.GONE); after if and else blocks. Hope this will work for you.
I think the issue could lie in a couple places:
1) You're doing a good deal of pre-processing of data in you Adapter's constructor.
Remember that everything in onPostExecute() runs on the application UI thread, so if your constructor for your adapter does some heavy processing, it could lock up the UI thread.
Creating an adapter can be done in doInBackground and then passed as the result to onPostExecute so that the setAdapter call is the only call there.
2) Your getView() method in your adapter isn't very efficient.
When you call setAdapter, the AdapterView must call getView for every cell that's going to be shown on screen. If there are a lot of cells and you're doing a lot of expensive operations like inflating views or findingViewsById, you could be locking up the UI thread for that initial load.
How's your scrolling performance? If it's lacking, the getView() would be the first place to start and I would watch Romain Guy's great talk on ListView performance for recommendations on how to create a good, efficient adapter.
http://www.youtube.com/watch?v=wDBM6wVEO70
add a listener when onpostexecute is completed in listener onsuccess method in your activity set adpater and then dismiss progress it will work
in you activity add this interface
public interface asyncListener{
public void onSucess(Object object);
public void onFailure(Exception exception);
}
and add a varible
asyncListener as= new asyncListener() {
#Override
public void onSucess(Object object) {
// TODO Auto-generated method stub
}
#Override
public void onFailure(Exception exception) {
// TODO Auto-generated method stub
}
};
send this varible(listenr) in construtor in your asynctask contruct asign this to yourlistener in onpostexecute write yourlistener.onSucess(result);
Related
I am working on an Application in Android where I shut down all of my servers. Therefore, I use an ArrayAdapter and a Listview.
In a background process, I iterate over the IP - Addresses and shutdown all of my servers.
Now, I want when iterating over my servers to color each row in the ListView in Green ( means still working on it to shut it down ) or Red as soon as the server is shut down.
I am able to color each row in a different color when extending the ArrayAdapter and then in the getView method coloring them all differently.
But how can I do that when iterating over each row during the background process?
My adapter is being set during the call of my Activity class.
Do I have to put the setAdapter method in my backgroundprocess, too, or something like that?
Here is my code:
protected void onCreate(Bundle savedInstanceState) {
initComponents();
}
private void initComponents() {
model = new SharedPreferenceModel(getBaseContext());
mydb = new DatabaseHelper(this);
array_list = mydb.getAllCotacts();
hostsOnline = new ArrayList<String>();
btnShutdown = findViewById(R.id.btnShutdown);
lv = (ListView) findViewById(R.id.listView);
CustomArrayAdapter custom = new CustomArrayAdapter(this, android.R.layout.simple_list_item_1, array_list);
lv.setAdapter(custom);
}
private void addListeners(final ShutdownServers shutdownServers) {
btnShutdown.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new AsyncTask<Integer, String, Void>() {
#Override
protected Void doInBackground(Integer... params) {
try {
for(int i = 0; i<array_list.size(); i++){
posInArray++;
String host = array_list.get(i);
if(host.equals("192.168.1.1"))
publishProgress("Shutdown " + host);
else
executeRemoteCommand(getBaseContext(), host);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onProgressUpdate(String... values) {
hostsOnline.add(values[0]);
custom.setNotifyOnChange(true);
custom.notifyDataSetChanged();
}
}.execute(1);
}
});
}
Thanks for your help!
You can use setNotifyOnChange(boolean) method and corresponding add(), remove etc. methods to control list state (adding, removing, changing items). Keep in mind, that changing state of backing array field won't trigger UI changes automatically without that. If you want to control changes manually, you can use notifyDataSetChanged() method of ArrayAdapter.
It's all because ArrayAdapter tries to instantiate views only once and reuse them for different array elements when scrolling down. View's state should be only modified in getView() which normally would be called only once per array element, when it's about to be rendered on screen first time. However, you can force 'redraw' using notifyDataSetChanged() at any time to keep UI state consistent with backing array field.
lv.setBackgroundResource(R.drawable.your file)// from drawable
lv.setBackgroundResource(Color.BLACK)// from color by default
Now I was able to solve the colouring problem. Here is my solution:
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// Get the current item from ListView
View view = super.getView(position,convertView,parent);
if(notifyCalling==1 && position == getPos()){
Log.d("getView - if - position", String.valueOf(position));
view.setBackgroundColor(Color.GREEN);
}else if(notifyCalling ==1 && position < getPos()){
Log.d("getView - elseif - position", String.valueOf(position));
view.setBackgroundColor(Color.RED);
}else if (position % 2 == 1) {
view.setBackgroundColor(Color.LTGRAY);
} else {
view.setBackgroundColor(Color.WHITE);
}
return view;
}
private void addListeners(final ShutdownServers shutdownServers) {
btnShutdown.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
btnShutdown.setClickable(false);
new AsyncTask<Integer, String, Void>() {
#Override
protected Void doInBackground(Integer... params) {
try {
for(int i = 0; i<array_list.size(); i++){
String host = array_list.get(i);
publishProgress(host);
executeRemoteCommand(getBaseContext(), host);
setIndex(i+1);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onProgressUpdate(String... values) {
custom.setNotifyOnChange(true);
custom.notifyDataSetChanged(getIndex());
}
}.execute(1);
}
});
}
I have an activity class that calls my custom adapter class which extends a base adapter. Inside my getView method I have a button.setOnClickListener within which there is a thread which downloads data. I want to set the button text to "downloading" when the user clicks, then after the download is finished, set the button text to "finished". How can I do this?
public class MyActivity extends Activity {
//some code here
private void setAdapter(ArrayList arrayList) {
listView.setAdapter(new UserAdapter(context,arrayList));
}
}
public class UserAdapter extends BaseAdapter {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder = new Holder();
holder.button = (Button) view.findViewById(R.id.button);
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(new Runnable() {
#Override
public void run() {
try{
//set button text to "downloading"
//establish an http connection and download data
//after download done, if successfull set button text to downloaded
//if download failed, set button text to failed.
} catch (Exception exception) {
}
}
}
).start();
}
});
return view;
}
private class Holder {
private Button button;
}
}
In order to update a view fron inside the thread use runOnUithread inside the getView method like this. Inside the activity you can use directly but outside the activity you have to use the context.
context.runOnUiThread(new Runnable(){
public void run() {
//If there are stories, add them to the table
try{
}
} catch (final Exception ex) {
Log.i("---","Exception in thread");
}
}
});
For http request you can use asyncTask.
I'm building a chat application, so I'm using two ListViews: one that shows the online friends and one for the chat itself, that receives the messages and so on. I'm using the XMPP protocol and the Smack Library for Android.
The Smack Library give me Listeners which are activated every time a friend status changes(online/offline) and the other one when the user receives a message. Here's how I declare the adapter and call an AsyncTask when the user press a button:
peopleList = (ListView) findViewById(R.id.peopleList);
adapter = new MyAdapter(this, people);
peopleList.setAdapter(adapter);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new ConnectAndLoad(MainActivity.this).execute();
}
});
Inside the AsyncTask, I connect to the server inside the doInBackground method and inside the onPostExecute I create the listener which adds the user to the array list of the listview and call adapter.notifyDataSetChanged();
public class ConnectAndLoad extends AsyncTask<String, Integer, Boolean> {
private ProgressDialog dialog;
public ConnectAndLoad(Activity activity)
{
this.dialog = new ProgressDialog(activity);
this.dialog.setTitle("Loading..");
this.dialog.setMessage("Connecting to the server..");
dialog.show();
}
#Override
protected Boolean doInBackground(String... arg0) {
MyConnectionManager.getInstance().setConnectionConfiguration(getApplicationContext());
MyConnectionManager.getInstance().connect();
MyConnectionManager.getInstance().login();
return true;
}
protected void onPostExecute(Boolean boo)
{
MyConnectionManager.getInstance().bored();
Roster roster = Roster.getInstanceFor(MyConnectionManager.getInstance().getConnection());
try
{
if (!roster.isLoaded()) roster.reloadAndWait();
}
catch (Exception e)
{
Log.e(TAG, "reload");
}
roster.addRosterListener(new RosterListener() {
public void entriesDeleted(Collection<String> addresses) {
}
public void entriesUpdated(Collection<String> addresses) {
}
public void entriesAdded(Collection<String> addresses) {
}
#Override
public void presenceChanged(Presence presence) {
people.add(new People(presence.getFrom(), presence.getStatus()));
adapter.notifyDataSetChanged();
}
});
dialog.dismiss();
}
}
And below is my Custom Adapter:
public class PeopleAdapter extends ArrayAdapter<People> {
private ArrayList<People> events_list = new ArrayList<>();
Context context;
public PeopleAdapter(Context context, ArrayList<People> users) {
super(context, 0, users);
this.context = context;
this.events_list = users;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
People user = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.people_list, parent, false);
}
TextView tvName = (TextView) convertView.findViewById(R.id.name);
TextView tvStatus = (TextView) convertView.findViewById(R.id.status);
tvName.setText(user.name);
tvStatus.setText(user.status);
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "You Clicked " + events_list.get(position).name, Toast.LENGTH_SHORT).show();
Intent i = new Intent(context, ConversationActivity.class);
i.putExtra("user", events_list.get(position).name);
context.startActivity(i);
}
});
return convertView;
}
}
I mean what I want to do I think it's a simple thing, every single chat app does it, is basically update the list view automatically but I'm having two problems:
The listview ONLY updates after I click on it. So it basically works
but I have to click on the listview..
I receive this error every time the list view updates (the app keeps working though):
Exception in packet listener: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
I can give you a simple solution. Make local Activity variable in the ConnectAndLoad class
private Activity activity;
public ConnectAndLoad(Activity activity)
{
...
activity.activity= activity;
}
Instead on directly calling adapter.notifyDataSetChanged(); use
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
}
});
It seems like presenceChanged() called in another thread. But be careful and make sure you delete RosterListener when activity gets destroyed or it can lead to the memory leaks i.e activity is already destroyed but you keep getting notifications about presence change.
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131296513, class xyz.ScrollDetectableListView) with Adapter(class android.widget.HeaderViewListAdapter)]
I am getting above exception sometimes while scrolling through the dynamic listview and then clicking on item.I researched a lot but unable to find the exact reason that why i am getting this error sometimes and how it can be resolved?
private ScrollDetectableListView mFListView;
public FAdapter mFAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_feed_view, container, false);
View headerView = getActivity().getLayoutInflater().inflate(R.layout.view_feed_header, null);
try{
mFListView = (ScrollDetectableListView) rootView.findViewById(R.id.feed_list_view);
mFContainer = (SwipeRefreshLayout) rootView.findViewById(R.id.feed_container);
mFListView.addHeaderView(headerView);
mFListView.setEmptyView(rootView.findViewById(R.id.empty_view));
mFContainer.setColorSchemeResources(R.color.green, R.color.pink, R.color.fbcolor,
R.color.instagramcolor, R.color.googlecolor, R.color.flickrcolor);
mFView = getActivity().getLayoutInflater().inflate(R.layout.view_footer, null);
ImageView rotateImageView = (ImageView) mFooterView.findViewById(R.id.spinner);
Animation rotation = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate);
rotation.setFillAfter(false);
rotateImageView.startAnimation(rotation);
mFContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh()
{
initializeFListView();
}
});
initializeFListView();
mProgressDialog.setVisibility(View.VISIBLE);
mHActivity.setDataChangedListener(new DataChangedListener() {
#Override
public void onDataChanged() {
mFContainer.setRefreshing(true);
mProgressDialog.setVisibility(View.GONE);
initializeFListView();
}
});
}catch(Exception e){}
return rootView;
}
public void initializeFListView()
{
FApi.getTrending(getActivity(), xyz, new APIResponseListener() {
#Override
public void onResponse(Object response) {
setFeedAdapter((List<Video>) response);
}
#Override
public void onError(VolleyError error) {
if (error instanceof NoConnectionError) {
String errormsg = getResources().getString(R.string.no_internet_error_msg);
Toast.makeText(getActivity(), errormsg, Toast.LENGTH_LONG).show();
}
}
});
}
private void setFAdapter(List<Video> response)
{try {
List<Video> videos = response;
mFAdapter = new FAdapter(getActivity(), videos, mProfileClickListener, mCommentClickListener);
mFListView.setOnScrollListener(new EndlessScrollListenerFeedView(getActivity(), mFListView, mFView, mFAdapter, videos, mFType, ""));
mFListView.setAdapter(mFAdapter);
mProgressDialog.setVisibility(View.GONE);
if (mFContainer.isRefreshing()) {
mFContainer.setRefreshing(false);
}
if (mFAdapter.getCount() < mCount) {
mFView.setVisibility(View.GONE);
mFListView.removeFooterView(mFooterView);
}
}catch(Exception e){}
}
}
My suggestion try to set ur list adapter on UI Thread,,,
private void setFAdapter(List<Video> response)
{
try {
List<Video> videos = response;
mFAdapter = new FAdapter(getActivity(), videos, mProfileClickListener, mCommentClickListener);
mFListView.setOnScrollListener(new EndlessScrollListenerFeedView(getActivity(), mFListView, mFView, mFAdapter, videos, mFType, ""));
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
mFListView.setAdapter(mFAdapter);
}
});
mProgressDialog.setVisibility(View.GONE);
if (mFContainer.isRefreshing()) {
mFContainer.setRefreshing(false);
}
if (mFAdapter.getCount() < mCount) {
mFView.setVisibility(View.GONE);
mFListView.removeFooterView(mFooterView);
}
}catch(Exception e){}
}
}
Keep one singleton class object in hand. So that you can synchronize two thread on it. Care to be taken to not to block the ui thread.
Reduce number of interfaces to only one method to start preparing data for your list and only one method to call your notifydatasetchanged/setAdapter on list.
Means there should be only one method like prepareData() which will be executed by a background thread. synchronise this method on your singleton object.
MyListAdaper adapter = null;
// Call this from a background thread
public void prepareData() {
synchronized (SingleTonProvider.getInstance()) {
List<AnyDataTypeYouWant> data = null;
// populate data here by your application logic.
adapter = new MyListAdaper(data);
}
}
And have only one method to refresh list.
// Also Call this from a background thread only
public void refreshList() {
synchronized (SingleTonProvider.getInstance()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mFListView.setAdapter(adapter);
}
});
}
}
have no other code on any place to prepare data and set data on list.
Call the methods I mentioned from a background thread only.
I just gave general solution to your problem. You have to work on your specific case by yourself.
I have an activity whose only purpose is to display a list view. There is a custom adapter to serve up the views for each element in the array.
I have break points all over and when I debug, it stops in "count" a number of times - the first few times the return value is zero, then it changes to 3 (the correct value in this case). Then we stop in "getView" - all the right stuff happens, and after we're through with all the break points, then presto magico all three records display on the screen. Yea!
So then I try to run the app outside of the debugger. I get the log message that it's visited "count", and the log message displays the return value so I know it's correct - but "getView" never gets called!!
I'm not sure which bits of code are relevant to this question & don't want to pollute the question with the entire project; please let me know if there's a specific section that would be helpful. I've researched all the "getView not called" questions but those consistently are for a case where getView never gets called, which clearly mine can beā¦sometimes :(
EDIT: Adapter code
public class DivisionAdapter extends BaseAdapter {
private static final String TAG = "DIV_ADAPT";
private ArrayList<Division> divisionList;
private Context context;
public DivisionAdapter(Context c, ArrayList<Division> divList) {
divisionList = divList;
context = c;
}
#Override
public int getCount() {
Integer count = 0;
if (divisionList != null) count = divisionList.size();
Log.v(TAG,count.toString());
return count;
}
#Override
public Object getItem(int position) {
Object o = null;
if (divisionList != null)
o = divisionList.get(position);
return o;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.v(TAG,"getView");
if (divisionList == null)
return null;
LinearLayout divisionView = null;
Division thisDiv = divisionList.get(position);
if (convertView == null) {
divisionView = new LinearLayout(context);
LayoutInflater li = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
li.inflate(R.layout.division_item, divisionView, true);
} else {
divisionView = (LinearLayout) convertView;
}
Log.v(TAG,thisDiv.name());
TextView v = (TextView) divisionView.findViewById(R.id.divisionName);
v.setText(thisDiv.name());
v = (TextView) divisionView.findViewById(R.id.divisionRegion);
v.setText(thisDiv.region());
return divisionView;
}
public void setList(ArrayList<Division> newList) {
divisionList = null;
divisionList = newList;
}
}
And just in case it's useful, some snippets from the activity class:
#Override
public void onResume() {
super.onResume();
refreshList();
}
private void refreshList() {
// use the class static query method to get the list of divisions
Division.query(Division.class,
new StackMobQuery().fieldIsEqualTo("status", "ACTIVE"),
new StackMobQueryCallback<Division>() {
#Override
public void failure(StackMobException arg0) {
// TODO Auto-generated method stub
Log.v(TAG, "query fail");
}
#Override
public void success(List<Division> arg0) {
Log.v(TAG, "query success");
divAdapt.setList((ArrayList<Division>) arg0);
divAdapt.notifyDataSetChanged();
}
});
}
EDIT 2/11:
I found this question: Markers not showing on map after stackmob query which reveals the hitherto unknown fact that stack mob queries run on a background thread. I'm starting to research the relationship between threads and adapters and thought I'd share this clue in case it helps anyone else figure out what's going on here faster than I can. TIA.
idk why this EVER worked in the debugger - that turned out to be a red herring.
As discovered, the StackMobModel static query method does run in a background thread, from which calling NotifyDataSetChanged() is completely ineffectual.
I ended up replacing the success method in the StackMobQueryCallback as follows:
#Override
public void success(final List<Division> arg0) {
Log.v(TAG, "query success");
runOnUiThread(new Runnable() {
public void run() {
updateList((ArrayList<Division>) arg0);
}
});
}
and then added this new method
private void updateList(ArrayList<Division> newList) {
divAdapt.setList(newList);
divAdapt.notifyDataSetChanged();
}
now, when the query returns, the adapter update is directed to run on the proper thread, and hooray, everything looks stitched together just fine and dandy.
whew!