This question already has answers here:
Android Updating ListView
(2 answers)
Closed 7 months ago.
I want to update TextView's text using AsyncTask.
I have list view in that there is Two TextView and one is ImageView
When user press ImageView button the Song will be played from server side. So i have put code in AsyncTask task
This is an custom Adapter from that i am calling ImageView's on Click event below is my code sample like this
public View getView(final int position, View convertView,
ViewGroup parent) {
holder.imgPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
and onclick event i am passing textview in asynctask, that i want to change after getting data from internet so below is my code
new MetadataTask2().execute(holder.txtMetadata);
now AsyncTask's Code is below
class MetadataTask2 extends AsyncTask<TextView, Void, IcyStreamMeta> {
TextView txtView;
#Override
protected IcyStreamMeta doInBackground(
TextView... arg0) {
//SOME OPERATION
txtView = arg0[0];
return streamMeta;
}
#Override
protected void onPostExecute(IcyStreamMeta result) {
txtView.setText("Hiiiiiiii");
}
#Override
protected void onPreExecute() {
super.onPreExecute();
try {
PD = ProgressDialog.show(CompaniesList.this, "Tuning...",
"Please Wait...");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Now here u can see that with textView.setText("Hiii") the text will be updated but it will not reflect in Listview for that i have to update ListView or Adapter but do not know how to do that so i can see text on listview can any body help me
i have used below code for updating listview but still does nothing
adapter.notifyDataSetChanged();
mainListView.setAdapter(adapter);
mainListView.invalidate();
Have your adapter be a member variable of your activity class. Then you will be able to reference it from onPostExecute.
Also, from your code it's not clear to me if your TextView is actuallly the one that you intend to modify (the one that you inflated presumably) just in case, remember that you have to call setContentView in the main thread before doInBackground attempts to modify any component. Make sure that this Textview variable (arg0[0]??) is the one that you are inflating
Related
I have a ListView in an Android Activity and a custom adapter for that listview.
I want to be able to edit a row item and update that row instantly. This works, the modifications of the row is seen But, on scroll i loose all data.
This is my Asynk task from where i get the data and update the list row item:
/**
*
*/
public class EditNewsFeedPostAsyncTask extends AsyncTask<Void, Void, Boolean> {
public Activity context;
public String content;
public int rowPosition;
public ListView listView;
public TextView decriptionTxt;
#Override
protected Boolean doInBackground(Void... params) {
try {
token = Utils.getToken(context);
if (token != null) {
....
// {"status":"true"}
if (result != null) {
....
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
if (success) {
updateListView(rowPosition, content);
}
}
public boolean updateListView(int position, String content) {
int first = listView.getFirstVisiblePosition();
int last = listView.getLastVisiblePosition();
if (position < first || position > last) {
return false;
} else {
View convertView = listView.getChildAt(position - first);
decriptionTxt.setText(content);
listView.invalidateViews();
return true;
}
}
private void updateView(int index, TextView decriptionTxt) {
View v = listView.getChildAt(index - listView.getFirstVisiblePosition());
if (v == null)
return;
decriptionTxt.setText(content);
listView.invalidateViews();
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onCancelled() {
}
}
What am i missing? shouldn't the data be persistent?
Thx
You must update the object in your listView adapter, not only the views!
after scrolling, the getView method inside your list's adapter will call and you will return the default view for that.
if you want to change that item permanent, you should update your data set and call notifyDataSetChanged on your adapter.
Make sure you're updating the data, not just the view.
When you modify the row, are you changing the underlying data or just the view? If just the view...
You're probably running into ListView recycling issues. This answer has a great explanation. Basically, ListViews are about efficiency in displaying views based on data, but are not good for holding new data on screen. Every time a ListView item is scrolled out of view, its View is recycled to be used for the item that just scrolled into view. Therefore, if you put "hi" in an EditText and then scroll it off screen, you can say goodbye to that string.
I solved this in my app by ditching ListView altogether and using an array of LinearLayouts (probably a clunky approach, but I had a known list size and it works great now). If you want to continue using a ListView, you'll have to approach it from a "data first" perspective. Like I said, ListViews are great at showing info from underlying data. If you put "hi" in an EditText and simultaneously put that string in the underlying data, it would be there regardless of any scrolling you do. Updating onTextChanged might be cumbersome, so you could also let each row open a dialog in which the user enters their data which then updates the underlying dataset when the dialog closes.
These are just some ideas, based on some assumptions, but editing views in a ListView is, in general, not very in line with how ListViews work.
I have an AsyncTask that uses HttpGet to fetch content from a remote server. I have tested and this is working fine, now I want to update a TextView with the result of this AsyncTask. Here is what I have done.
From the OnCreateView of the Fragment, I get reference to a Button and a TextView, I initially hide the TextView and then in the OnClickListener for the button I want to unhide the textview and update that textview with the result of my AsyncTask
View rootView = inflater.inflate(R.layout.fragment_programs_list, container, false);
Button btnLoadPrograms = (Button) rootView.findViewById(R.id.btnLoadPrograms);
TextView tvShowPrograms = (TextView) rootView.findViewById(R.id.tvRestCall);
tvShowPrograms.setVisibility(View.GONE);
btnLoadPrograms.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startNewAsyncTask();
}
});
return rootView;
Now in the onPostExecute of the AsyncTask, I want to update the Textview
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
getView().findViewById(R.id.tvRestCall).setVisibility(View.SHOW); //Does not exit
}
How do I get a reference to the TextView from within the AsyncTask in a Fragment and then update that TextView with the result of the doinbackground.
Try to Use getView().findViewById(R.id.tvRestCall).setVisibility(View.VISIBLE);
Try this way,
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
tvShowPrograms.setVisibility(View.VISIBLE);
}
I agree with https://stackoverflow.com/users/1113949/ksarmalkar - you can send a reference to AsyncTask and then use this reference to set Visibility by mYourView.setVisibility(View.VISIBLE);
I ended up solving the issue as follows
Set a public property for the textView
public TextView tvShowPrograms;
Then in OnCreateView I initialize the TextView and set the text to null
tvShowPrograms = (TextView) rootView.findViewById(R.id.tvRestCall);
tvShowPrograms.setText("");
And then the onPostExecute, I simply set the textView to the result.
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
tvShowPrograms.setText(result);
}
Thanks for the answers, I am glad it is working
i know this question has been posted multiple times and i browsed almost all of them but there is not result, i am performing a deleting an item from mysql database but it is not refreshing, here is the code of the onclicklistener and the button:
onClick listener:
holder.void_button.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
adapter = new CustomListViewVoidAdapter(context,R.layout.mytemp, items);
item_selected= items.get(position);
new DeleteOrder().execute();
}});
vi.setTag(holder);
}
OnPostExecute from AsyncTask:
protected void onPostExecute(String unused){
adapter.remove(item_selected);
adapter.notifyDataSetChanged();
}
the adapter is instatiated globally, can you please check where the problem might be?
it is not returning any error, just deleting the item and not refreshing.
Regards
Ralph
Throwing it out there, but, have you tried adapter.notifyDataSetInvalidated();? That forces an update.
Also, put the code in the asynctask!
Like such:
protected void onPostExecute() {
adapter.notifyDataSetChanged();
adapter.notifyDataSetInvalidated();
}
You better set the adapter again to the list view in onPostExecute with the new values. And you don't need to call notifyDataSetChangedin this case. Also don't re-intialize the adapter in onClick, this is not neccessary.
Add below line in postExecute.
if(adapter != null) {
adapter = new CustomListViewVoidAdapter(context,R.layout.mytemp, items);
YourListviewObject.setAdapter(adapter);
}
what I have is an AsyncTask, that started as soon as ListView reached bottom item on a screen, and in AsyncTask it adds new items to the ListView.
Here is the code:
#Override
protected void onPostExecute(final List<ItemDailyRecord> records) {
super.onPostExecute(records);
((ActivityHome)context).runOnUiThread(new Runnable() {
public void run() {
for (ItemDailyRecord p : records) {
adapter.add(p);
}
adapter.notifyDataSetChanged();
}
});
}
#Override
protected List<ItemDailyRecord> doInBackground(Void... voids) {
DbAdapterDailyRecord db = new DbAdapterDailyRecord(context);
List<ItemDailyRecord> list = db.getRecordsFromTo(offset, count);
return list;
}
here is a method from ListView Adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(position == getCount() - 1 && hasMoreItems){
HistoryLoaderTask t = new HistoryLoaderTask(position + 1, pageSize, getContext(),this);
t.execute();
footer.setText("Loading . . .");
}
And the error message is(if I scroll the listview too fast :)
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its
views.
any ideas how to solve this issue?
The onPostExecute() method is executed on the UI thread, so you should be updating the UI directly in this method; no need to spawn a new Runnable object.
You shouldn't execute your async task from getView of your adapter. Instead you should try to do it from your activity/fragment where your list resides by using getLastVisiblePosition() of ListView
Like this --->
if(list.getLastVisiblePosition() == (dataSet.size() - 1)) {
// last item displayed
.... change the text off footer and execute async task
}
and in the async task append the extra data to dataset and then call notifyDataSetChanged() on the adapter.
I have an android activity that consists of a List View and a Text View. The Text view displays information about the summed contents of the list view, if the items in the list view are updated then the Text View needs to reflect the change.
Sort of like an observer pattern but with one component reflecting the changes of many rather than the other way round.
The tasks are displayed as items in the list view and the progress can be updated using a seekbar to set the new progress level.
The following method populates the TextView so I need to call this again from inside the SeekBar onStopTrackingProgress Listener.
private void populateOverviewText() {
TextView overview = (TextView) findViewById(R.id.TaskOverview);
if (!taskArrayList.isEmpty()) {
int completion = 0;
try {
completion = taskHandler.getProjectCompletion();
overview.setText("Project Completion = " + completion);
} catch (ProjectManagementException e) {
Log.d("Exception getting Tasks List from project",
e.getMessage());
}
}
}
I realise if I want to call the method from the List Adapter then I'll need to make the method accessible but I'm not sure the best approach to do this.
Either make this method public
or you can pass activity to adapter through which you can find the button and update text, or can directly pass Button to adapter...
Using DataSetObserver
I was looking for a solution that didn't involve altering the adapter code, so the adapter could be reused in other situations.
I acheived this using a DataSetObserver
The code for creating the Observer is incredibly straight forward, I simply add a call to the method which updates the TextView inside the onChanged() method.
Attaching the Observer (Added to Activity displaying list)
final TaskAdapter taskAdapter = new TaskAdapter(this, R.id.list, taskArrayList);
/* Observer */
final DataSetObserver observer = new DataSetObserver() {
#Override
public void onChanged() {
populateOverviewText();
}
};
taskAdapter.registerDataSetObserver(observer);
Firing the OnChanged Method (Added to the SeekBar Listener inside the adapter)
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
int task_id = (Integer) seekBar.getTag();
TaskHandler taskHandler = new TaskHandler(DBAdapter
.getDBAdapterInstance(getContext()));
taskHandler.updateTaskProgress(task_id, progress);
mList.get(position).setProgress(progress);
//need to fire an update to the activity
notifyDataSetChanged();
}