view on dialog doesn't change when it should - android

I have a ListView that when an item is being clicked its create new PlaySongAlertDialog object and passes params to it. Now the problem at the following code is that only at first time its actually changes the text of artistCheckBox and when i click dismiss and then on another ListView row its show me the same text on artistCheckBox.
I can't find the post but i remember that someone said that i should override onPrepareDialog but i cant find such method on AlertDialog.Builder class.
public class PlaySongAlertDialog extends AlertDialog.Builder {
public PlaySongAlertDialog(final Context context, final String songName, final Intent service) {
super(context);
LayoutInflater inflater = LayoutInflater.from(context);
View dialoglayout = inflater.inflate(R.layout.download_song_alert_dialog_check_box, null);
final CheckBox artistCheckBox = (CheckBox) dialoglayout.findViewById(R.id.artist_checkbox);
final CheckBox albumCheckBox = (CheckBox) dialoglayout.findViewById(R.id.album_checkbox);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try{
artistCheckBox.setText("Add artist name (" + getSomethingFromTheWeb.getArtist(songName) +")");
} catch(Exception e){
artistCheckBox.setText("Add artist name (can't found)" );
artistCheckBox.setClickable(false);
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
setMessage("Do you want to play: " + songName);
setView(dialoglayout);
}
Also this is how i create new dialog (this code is on main activity)
DownloadSongAlertDialog dialog = new DownloadSongAlertDialog(this, name, serviceIntent);
dialog.show();
Is there a way to create a real dialog every time instead of reusing the last one, maybe clean the cache or something.

thread.join(); is blocking the UI thread waiting for the other thread to finish. That's the reason why you don't see the dialog updating. To fix you could subclass AsyncTask, and start it in the constructor of your AlertDialog. When onPostExecute is invoked you fill up the View and show it.

Related

Stop Android's adapter.notifyDataSetChanged() from running in parallel with the function that contains the notifyDataSetChanged() code

I have the following singleton running for my Android application
public class ListsApplication extends Application {
public DbxDatastoreManager datastoreManager;
public HashMap<String, ViewItemContainer> itemsSync;
public Typeface Font;
public boolean Fetch;
private static ListsApplication singleton;
public static ListsApplication getInstance() {
return singleton;
}
#Override
public void onCreate() {
super.onCreate();
singleton = this;
itemsSync = new HashMap<>();
Font = Typeface.createFromAsset(getAssets(), "fonts/GoodDog.otf");
Fetch = true;
}}
then from the Home activity I retain the singleton instance through
ListsApplication app = app.getInstance
in the Home activity I setup a listener which is triggered from the datastore online server whenever there's a change in the online datastores through
private void setUpListeners() {
app.datastoreManager.addListListener(new DbxDatastoreManager.ListListener() {
#Override
public void onDatastoreListChange(DbxDatastoreManager dbxDatastoreManager) {
// Update the UI when the list of datastores changes.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
app.Fetch = true;
Home.this.updateList();
app.Fetch = false;
}
}, 7000/* 3sec delay */);
Toast toast = Toast.makeText(getApplicationContext(), "RECEIVED", Toast.LENGTH_SHORT);
toast.show();
}
});
updateList();
app.Fetch = false;
}
I allow some time before running updateList() as the update to the datastore is not atomic so it takes like 2 seconds to have all the rows on the online datastore, ignore the app.Fetch for now, I'm going to explain later.
updateList() clears the ArrayList of items that have to populate the listAdapter and runs adapter.notifyDataSetChanged()
In my custom listAdapter, I've set the getView as follows:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder mHolder;
if (convertView == null) {
/*Toast toast = Toast.makeText(context, "nullConvertView", Toast.LENGTH_SHORT);
toast.show();*/
mHolder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listitem, parent, false);
mHolder.PetName = (TextView) convertView.findViewById(R.id.PetName);
mHolder.BuyFood = (ImageView) convertView.findViewById(R.id.PetBuyFood);
mHolder.PetImage = (RoundedImageView) convertView.findViewById(R.id.PetImage);
convertView.setTag(mHolder);
} else {
mHolder = (ViewHolder) convertView.getTag();
}
updateItem(mHolder, this.getItem(position));return convertView;}
and updateItem(mHolder, this.getItem(position))
public void updateItem(final ViewHolder currentViewFromList, final DbxDatastoreInfo info){
app = ListsApplication.getInstance();
if (app.itemsSync.containsKey(info.id) && !app.Fetch){
/*Toast toast = Toast.makeText(context, "not fetching "+info.title, Toast.LENGTH_SHORT);
toast.show();*/
ViewItemContainer cont = app.itemsSync.get(info.id);
currentViewFromList.PetName.setTypeface(app.Font);
currentViewFromList.PetName.setText(cont.PetName);
currentViewFromList.PetImage.setImageBitmap(cont.PetImage);
if (cont.BuyFood) currentViewFromList.BuyFood.setVisibility(View.VISIBLE);
else currentViewFromList.BuyFood.setVisibility(View.INVISIBLE);
}
else{
ViewItemContainer cont = new ViewItemContainer();
try {
Toast toast = Toast.makeText(context, "entrato"+info.title, Toast.LENGTH_SHORT);
toast.show();
DbxDatastore datastore = app.datastoreManager.openDatastore(info.id);
datastore.sync();
if (info.title!=null){
currentViewFromList.PetName.setTypeface(app.Font);
cont.PetName = info.title;
currentViewFromList.PetName.setText(cont.PetName);
}
DbxTable table = datastore.getTable("ITEMS");
DbxRecord record = table.get("INFO");
if (record!=null && record.hasField("PETPICTURE")){
byte[] b = record.getBytes("PETPICTURE");
//Bitmap picture = Misc.ByteArrayToImg(b);
cont.PetImage = Misc.ByteArrayToImg(b);
if (cont.PetImage!=null) currentViewFromList.PetImage.setImageBitmap(cont.PetImage);
} else currentViewFromList.PetImage.setImageResource(R.drawable.ic_launcher);
if (record!=null){
cont.BuyFood = record.getBoolean("BUYFOOD");
if (cont.BuyFood) currentViewFromList.BuyFood.setVisibility(View.VISIBLE);
else currentViewFromList.BuyFood.setVisibility(View.INVISIBLE);
}
datastore.close();
} catch (DbxException e) {
e.printStackTrace();
}
app.itemsSync.put(info.id,cont);
}
}
basically when the application starts, app.Fetch is set to true, updateList() from Home creates the adapter and calls adapter.notifyDataSetChanged().
At this point the listAdapter getView is called for every item in the list,
checks for the id as key in the hashmap and doesn't find it
so it fetches data from the datastore, and inserts the data in the hashmap and on the view.
Up to this point it's all good. The listview is populated correctly, and when the views are scrolled the data is retrieved correctly from the hashmap instead than being fetched over and over from the datastore.
Then from another phone I add a new datastore, which triggers the listener and on my phone it shows "RECEIVED" toast, which means that the listener has been triggered. app.Fetch goes to true and then updateList() gets called.
If I check the app.Fetch value anywhere in updateList() it's still set to true, while if I check it when the getView code is running, it's set to false so it retrieves the data from the hashmap again instead than fetching the updated online datastores.
I think that the getView code starts to run in parallel with updateList function so it shows the following behaviour:
boolean true
updateList() start
adapter.notifyDataSetChanged() runs
ListAdapter getView start
updateList() ends
boolean false
getView checks boolean and since it's false at this point it retrieves the data from the hashmap.
Is there any way I can get updateList to wait until all the items in the listview run through getView?
Yes- you make sure that you only call notifyDataSetChanged on the UI thread. That way you won't ever call it while the list is loading. If you want to call it on an asychronous thread, use a runOnUiThread block to move that call to the UI thread. This will ensure you never try to update the list while its drawing and avoid the whole problem.

Android using Multiple Progress Dialogs

I am trying to build a class to go to the web, download data and then load it into a database. I have no problem doing this with a single progress dialog but can simply not figure out how to have multiple dialogs. In researching this, I found hundreds of Progress Dialog questions, so it does not seem as straight forward as it should be.
I have tried using handlers and threads but simply cannot ma
I am looking for an example of working code to accomplish this.
Here is the pseudo code that I am attempting:
public class myactivity extends Activity()
{
private WebIO webIO ; // web acess io
private DataIO DataIO ; // database io
public void onCreate( Bundle savedInstanceState ) {
DataIO = new DataIO( this );
WebIO = new WebIO();
DataIO.open();
runProgram();
}
}
private void runProgram() {
startProgressDialog( "Downloading data from web" );
new Thread() {
public void run() {
try{
String vData = webIO.getData();
dismissProgressDialog();
if ( vData.length() > 0 ) {
promptUser( vData );
} } } }
}
private void promptUser( vData ){
if alertdialog_to_prompt_user_to_load(){
{
loadData( pData )
}
private void loadData( String pData ){
startProgressDialog( "Loading data into database" );
new Thread() {
public void run() {
try{
loadDataIntoDatabase();
dismissProgressDialog();
} } } }
}
the only way to have multiple dialogs is to layer them on top of each other, which is an obvious user experience no-no. in android, dialogs are their own window, so there can only be one in focus at a time.
to solve your problem, create a custom dialog with multiple ProgressBar widgets. the simplest way to do that is to start with a DialogFragment and override onCreatedDialog() to return an AlertDialog with a custom view. to set a custom view on an alert dialog, see the setView() method on AlertDialog. e.g.,
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater li = LayoutInflater.from(context);
View layout = = li.inflate(R.layout.my_dialog);
return new AlertDialog.Builder(getActivity())
.setIcon(..)
.setTitle(...)
.setView(layout)
...
.create();
}
it'd be pretty neat to encapsulate all this into a multi-download progress dialog, where you could register additional downloads and have the class automatically add a progress bar and register itself for progress updates.

Android ListView and Adapter

I am working on a Download Manager project, so, to show all downloaded / downloading actions, i prefer to use ListView to show my download list. Suppose that, we have as many as downloading task, so, the progress bars of all tasks must be updated. For background download task, i created a new class that i named it HttpDownloader. So, i pass these progress bars on objects of this class. When a new object is added to my tasklist, so, i call the constructor of HttpDownloader and pass the new item progress bar to it. The thing confused me is When i add a new object to tasklist and call notifyDataSetChanged of adapter, my list is refreshed, so all progress bar reset to default layout values but HTTPDownloader Thread is running in background successfully. So, it is my question that,
1. After calling notifyDataSetChanged, references to old listview's objects are destructs ?
2. If yes, How can i keep old view's reference ?
3. If no, please explain me, why progress bars reset to default and do not change when background process force to passed progressbar to change the value of progress ?
HTTPDownloader class
class HttpDownloader implements Runnable {
public class HttpDownloader (String url, ProgressBar progressBar)
{
this.M_url = url;
this.M_progressBar = progressBar;
}
#Override
public void run()
{
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(this.M_url);
HttpResponse response;
try{
response = client.execute(get);
InputStream is = response.getEntity().getContent();
long contentLength = response().getEntity().getContentLength();
long downloadedLen = 0;
int readBytes = 0;
byte [] buffer = new byte [1024];
while ((readBytes = in.read(buffer, 0, buffer.length)) != -1) {
downloadedLen += readBytes;
//Some storing to file codes
runOnUiThread(new Runnable() {
#Override
public void run() {
M_progressBar.setProgress((100f * downloadedLen) / contentLength);
}
});
}
is.close();
} catch (ClientProtocolException e) {
Log.e("HttpDownloader", "Error while getting response");
} catch (IOException e) {
Log.e("HttpDownloader", "Error while reading stream");
}
}
}
AdapterClass
class MyAdapter extends ArrayAdapter<String> {
ArrayList<String> M_list;
public MyAdapter(ArrayList<String> list) {
super(MainActivity.this, R.layout.download_item, list);
this.M_list = list;
}
#Override
public int getCount() {
return this.M_list.size();
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.download_item, parent, false);
ProgressBar bar = (ProgressBar) rowView.findViewById(R.id.progrees);
new Thread (new HttpDownloader(this.M_list.get(position), bar)).start();
return rowView;
}
}
Well if you want to keep the references to show a good download manager, lets see how do it, go by parts.
The concept is easy to understand, we have threads downloading items, we are going to call each of this piece of work tasks. Each task is associated with a row in the list view, because you want to show a download progress of each item download.
So if each task is associated with each row, we are going to save tasks actually are in execution, in this way, we know in all moment what tasks are running and their state. This is importante because, like I have said before, getView() method is called many times, and we need to know each download in progress and its state.
Lets see some code of our Adapter:
class MyAdapter extends ArrayAdapter<Uri> {
ArrayList<Uri> M_list;
Map<Uri, HttpDownloader> taskMap;
public MyAdapter(ArrayList<Uri> list) {
super(MainActivity.this, R.layout.download_item, list);
this.M_list = list;
taskMap = new HashMap<Uri, HttpDownloader>();
}
#Override
public int getCount() {
return this.M_list.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.download_item, parent, false);
ProgressBar progressBar = (ProgressBar) rowView.findViewById(R.id.progressBar);
configureRowWithTask(position, progressBar);
return rowView;
}
private void configureRowWithTask(int position,final ProgressBar bar) {
Uri url = M_list.get(position);
HttpDownloader task;
if (!(taskMapHasTaskWithUrl(url))) {
task = new HttpDownloader(url, bar);
Thread thread = new Thread(task);
thread.start();
taskMap.put(url, task);
} else {
task = taskMap.get(url);
bar.setProgress(task.getProgress());
task.setProgressBar(bar);
}
}
private boolean taskMapHasTaskWithUrl(Uri url) {
if (url != null) {
Iterator taskMapIterator = taskMap.entrySet().iterator();
while(taskMapIterator.hasNext()) {
Map.Entry<Uri, HttpDownloader> entry = (Map.Entry<Uri, HttpDownloader>) taskMapIterator.next();
if (entry.getKey().toString().equalsIgnoreCase(url.toString())) {
return true;
}
}
}
return false;
}
}
Some explanations about it:
I have changed your type of adapter to ArrayAdapter of Uris to work better with links.
I have added a Map wich has pairs key-value, keys are Uris and values are HttpDownloaders. This map will save each task in use.
I have added two important methods, one is configureRowWithTask(), like its own name says configures a row with a task, associating them, but only if the task is new, in other case is a task in use.
The other method is taskMapHasTaskWithUrl(), simply checks if the given task (by its url) is currently in the taskMap.
Probably, the most important method is configureRowWithTask(), I am going to explain it deeply.
configureRowWithTask() method checks if one task is in use, this method is needed because getView() is called many times, but we dont want the same downloading task be executed more than once, so this method checks that, if the task is new (not present in the taskMap) then creates a new instance of HttpDownloader and put the new task in the map.
If the task requested is present in the taskMap, it means that the task has been requested previously but the row in the list has gone out and there have been a new call to getView() method. So the task is present, we dont have to create it again, probably the task is downloading the item and the only thing we have to do is see its download progress and set it to the row's progress bar. And finally sets the reference to the progress bar, probably the HttpDownloader has lost this reference.
With this part clear, we go with the second part, the HttpDownloader class, lets see some code:
public class HttpDownloader implements Runnable {
private Uri url;
private ProgressBar progressBar;
private int progress = 0;
private Handler handler;
public HttpDownloader (Uri url, ProgressBar progressBar) {
this.url = url;
this.progressBar = progressBar;
progressBar.setProgress(progress);
handler = new Handler();
}
#Override
public void run() {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url.toString());
HttpResponse response;
try {
response = client.execute(get);
InputStream is = response.getEntity().getContent();
long contentLength = response.getEntity().getContentLength();
int downloadedLen = 0;
int readBytes = 0;
byte [] buffer = new byte [1024];
while ((readBytes = is.read(buffer, 0, buffer.length)) != -1) {
downloadedLen += readBytes;
//Some storing to file codes
progress = (int) ((100f * downloadedLen) / contentLength);
handler.post(new Runnable() {
#Override
public void run() {
if (progressBar != null) {
progressBar.setProgress(progress);
}
}
});
}
} catch (ClientProtocolException e) {
Log.e("HttpDownloader", "Error while getting response");
} catch (IOException e) {
e.printStackTrace();
Log.e("HttpDownloader", "Error while reading stream");
}
}
public int getProgress() {
return progress;
}
public void setProgressBar(ProgressBar progressBar) {
this.progressBar = progressBar;
}
}
This class is basically the same, the diference is that I use a Handler to change the progress of the progress bar in the UI thread, and change this progress only if the reference to the progress bar is not null.
Important thing is every time bytes are downloaded, value of download progress is refreshed.
I have checked the code in a test app and seems that all runs ok, if you have some problems, let me know and I will try to help you ; )
Hope you understand it.
when you call notifyDataSetChanged() or Activity resumes, getView() method of the Adapter is called by each row of the list.
So, when you add new item to the list and call notifyDataSetChanged(), getView() method is executed as many times as items are in the list in that moment, plus one more cause the new item you have added.
Like you know, getView() method builds the row, so builds a new ProgressBar, and obvioulsy this ProgressBar begins at position 0 of progress.
So the answer could be resumed as yes, each time you call notifyDataSetChanged(), getView() method is called many times, one for each row (if you set android:layout_height param to 0dip and android:layout_weight to 1.0, like you probably know for ListViews), thats the reason why you get ProgressBars "initialized" when you add new item to the ListView.

ProgressDialog crashing application

I'm trying to get a ProgressDialog to load my listview before displaying it but i'm getting a crash. Would there be a better way to implement this?
EDIT: Updated with the logcat error, forgotten about it.
List<String> internetArray = new ArrayList<String>();
private ProgressDialog p;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView internetList = (ListView)findViewById(R.id.list);
p = ProgressDialog.show(this, "Please wait..", "Loading list..", true);
new Thread(){
public void run(){
//do some extreme work before creating list
try {
sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
internetArray.clear();
//p.dismiss();
}
}.start();
getPermissions(this);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, internetArray);
arrayAdapter.sort(new Comparator<String>() {
public int compare(String object1, String object2) {
return object1.compareTo(object2);
};
});
internetList.setAdapter(arrayAdapter);
}
Without a logcat from a first glance this is the problem: p.dismiss();.
You are trying to dismiss a UI element, in your case the progress dialog from a background thread.
Although I am certain that this is the cause, you should post your logcat for more details.
EDIT: The above error should be taken under consideration, although the error appears in creating the dialog: MainActivity.this this can't be instatiated. You can try passing the actual context by this and not class context MainActivity.this.
p = ProgressDialog.show(this, "Please wait..", "Loading list..", true);
UPDATE: Perhaps in your line of code is working but you have to know that when you are trying to access a UI element from a background thread would cause memory leaks (you are not even trying to access it through runOnUIThread() method, this is serious according to my opinion).
I didn't say that you should not add it at all, but you should add it in the ui thread. To our problem now, did the this work? Because I don't see any new logcat or something... :)

Android: Getting an error "Only the original thread that created a view hierarchy can touch its views"

I've been working on this problem all day and I'm ready to pull my hair out. I found some answers here and on the web that say that this is caused by trying to do something with a View within the thread (instead of in the UI thread). But I've tried all of the ideas (handler/new thread) that I've seen and still can't get it to work. I programmed in C for many years as a hobby and now I'm a newbie at Java/Android. I'm programming with Eclipse and the Android 2.1 platform. I want my application to work with as many of the Android phones as possible and I think all of the features that I'm using are compatible with API 1. I also saw that there is something called AsyncTask, but will that cause a problem with people who have old phones?
So here is what my app does. When I click on a button, the app goes online to a website and downloads an xml/rss feed. Then it parses it and puts the data into a listview using a custom adapter that I created. The downloading and parsing can take anywhere from 1 second to 15 seconds, so I wanted to add a progress dialog. After adding that, that is where I started getting the error message in the title of this post. The app does the downloading successfully (my example xml file on the web has 8 records in it so it's very small) but then I see the error before the listview is displayed. So I guess I need to know exactly which part of the view is causing the error, and then how to fix it.
Here is the code (I have removed all of my testing code from the last few hours so it is clean and will be less confusing to all of you... and me):
#SuppressWarnings("serial")
public class ClubMessageList extends ListActivity implements Serializable
{
private static final String TAG = "DGMS News";
private ArrayList<CMessage> m_messages = null;
private MessageAdapter m_adapter;
private ProgressDialog m_ProgressDialog = null;
private Runnable downloadMessages;
// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler();
#SuppressWarnings("unchecked")
#Override
public void onCreate(Bundle icicle)
{
Log.i(TAG, "Starting the ClubMessageList activity");
super.onCreate(icicle);
setContentView(R.layout.list);
setTitle("DGMS News - Clubs");
try
{
// check to see if we already have downloaded messages available in the bundle
m_messages = (ArrayList<CMessage>) ((icicle == null) ? null : icicle.getSerializable("savedMessages"));
// if there are no messages in the bundle, download them from the web and then display them
if (m_messages == null)
{
m_messages = new ArrayList<CMessage>();
this.m_adapter = new MessageAdapter(this, R.layout.row_club, (ArrayList<CMessage>) m_messages);
setListAdapter(this.m_adapter);
downloadMessages = new Runnable(){
public void run() {
getMessages();
}
};
Thread thread = new Thread(null, downloadMessages, "DownloadMessages");
thread.start();
m_ProgressDialog = ProgressDialog.show(ClubMessageList.this,
"Please wait...", "Retrieving 2010 Show data ...", true);
}
else // messages were already downloaded, so display them in the listview (don't download them again)
{
Log.i("DGMS News", "Starting activity again. Data exists so don't retrieve it again.");
m_adapter = new MessageAdapter(this, R.layout.row_club, (ArrayList<CMessage>) m_messages);
this.setListAdapter(m_adapter);
}
}
catch (Throwable t)
{
Log.e("DGMS News",t.getMessage(),t);
}
}
private Runnable returnRes = new Runnable()
{
public void run()
{
if(m_messages != null && m_messages.size() > 0)
{
m_adapter.notifyDataSetChanged();
for(int i=0;i<m_messages.size();i++)
m_adapter.add(m_messages.get(i));
}
m_ProgressDialog.dismiss();
m_adapter.notifyDataSetChanged();
}
};
private void getMessages()
{
try
{
m_messages = new ArrayList<CMessage>();
ClubFeedParser parser = ClubFeedParserFactory.getParser();
m_messages = parser.parse();
for(int i = 0; i < m_messages.size(); i++)
m_adapter.add(m_messages.get(i));
}
catch (Exception e)
{
Log.e("DGMS News", e.getMessage());
}
runOnUiThread(returnRes);
}
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable("savedMessages", (Serializable) m_messages);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id)
{
super.onListItemClick(l, v, position, id);
Intent intent = new Intent(ClubMessageList.this, ClubDetails.class);
// Add all info about the selected club to the intent
intent.putExtra("title", m_messages.get(position).getTitle());
intent.putExtra("location", m_messages.get(position).getLocation());
intent.putExtra("website", m_messages.get(position).getLink());
intent.putExtra("email", m_messages.get(position).getEmail());
intent.putExtra("city", m_messages.get(position).getCity());
intent.putExtra("contact", m_messages.get(position).getContact());
intent.putExtra("phone", m_messages.get(position).getPhone());
intent.putExtra("description", m_messages.get(position).getDescription());
startActivity(intent);
}
private class MessageAdapter extends ArrayAdapter<CMessage> implements Serializable
{
private ArrayList<CMessage> items;
public MessageAdapter(Context context, int textViewResourceId, ArrayList<CMessage> items)
{
super(context, textViewResourceId, items);
this.items = items;
}
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row_club, null);
CMessage m = items.get(position);
if (m != null)
{
TextView ltt = (TextView) v.findViewById(R.id.ltoptext);
TextView rtt = (TextView) v.findViewById(R.id.rtoptext);
TextView lbt = (TextView) v.findViewById(R.id.lbottext);
if (ltt != null)
ltt.setText(m.getTitle());
if (rtt != null)
rtt.setText(m.getLocation());
if (lbt != null)
lbt.setText(m.getCity() + ", CO");
//if (rbt != null)
; // not used in this list row
}
}
return v;
}
}
}
As I said, all of that code worked fine until I added the progress dialog stuff that I found on another website a few days ago.
I appreciate any and all help, although I have already gone to the Android Developers website to look at threading, handlers, etc and it just got me more and more confused. Actual code changes would be awesome. :-) My head is hurting after looking at so many websites today.
Thanks!
Bob
runOnUiThread(new Runnable() {
public void run() {
m_adapter.notifyDataSetChanged();
m_adapter.add(m_messages.get(i));
m_ProgressDialog.dismiss();
m_adapter.notifyDataSetChanged();
}
});
All your Ui code must go in runOnUiThread. The error u r getting is you are trying to update UI from other thread than the activity UI thread.
this thread in your code is causing the problem.
private Runnable returnRes = new Runnable()
{
public void run()
{
if(m_messages != null && m_messages.size() > 0)
{
m_adapter.notifyDataSetChanged();
for(int i=0;i<m_messages.size();i++)
m_adapter.add(m_messages.get(i));
}
m_ProgressDialog.dismiss();
m_adapter.notifyDataSetChanged();
}
};
Use AsyncTask. Almost no phones are using Android 1.0/1.1 at this point (the only phone that ever even shipped with Android < 1.5 was the HTC G1, and most were upgraded OTA a looong time ago) . If you really need to support those devices, you can use the identical UserTask. See this article for more info. And see about a dozen SO questions about making sure you update the UI from the main thread.

Categories

Resources