i have an AsyncTask where in "doinbackground", it update the variable "pics", later in postexecute i update all, the problem is than i wanna update the adapter when i'm updating the varible "pics". where i should declare the adapter, and call notifyDataSetChanged??
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting all products
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
/**
* Updating parsed JSON data into ListView
* */
mAdapter = new Gridadapter(tab.this, pics);
gridView.setAdapter(mAdapter);
}
});
thx!
you don't need to call the runOnUiThread(...) inside the onPostExecute. that method is already called inside the UI thread.
the adapter can be declared when you declare the other components of the views and you should use always the same instance. (dont create a new adapter every time you have an update do do!)
I would create an adapter like that:
public class GridAdapter extends BaseAdapter{
private ArrayList<Items> mItemList;
public void updateItemList(ArrayList<Items> newItemList){
this.mItemList = newItemList;
notifyDataSetChanged();
}
}
then instance it:
public void onCreate(Bundle savedInstance){
// ...all the previous code
mGridView = (GridView) findViewById(R.id.gridview);
mGridAdapter = new GridAdapter(this);
mGridView.setAdapter(mGridAdapter);
}
and call the update from the onPostExecute:
protected void onPostExecute(String file_url) {
mGridAdapter.updateItemList(pics);
}
Related
I want to access and populate a ListView from seprate thread... But its object has not its scope in new thread... What is the solution for it?
ListView FilesListView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FilesListView= (ListView)findViewById(R.id.remoteFilesListView);
new Thread ( new Runnable() {
#Override
public void run() {
// fetch data from server…
String xmlFormServer = Worker.getXmlresponse();
Log.d("Response from Serever", xmlFormServer;
// FilesListView object of Listview is not accessable in this thread to populate data…
}
}).start();
}
You cannot populate populate ListView/RecyclerView or any other view or component on another thread.
That has to be on the MainThread(UIThread).
Checkout this link for more info about UIThread in android and how its works.
What is the Android UiThread (UI thread)
However, you can put the logic or IO operation on different thread asynchronously and then you can put populate the result on UI thread.
One approach would be to use AsyncTask.
https://developer.android.com/reference/android/os/AsyncTask.html
Something like this..
new AsyncTask<Void, Void, String >() {
// Runs on Worker thread
#Override
protected String doInBackground(Void... params) {
String xmlFormServer = Worker.getXmlresponse();
return xmlFormServer;
}
// Runs on Ui thread
#Override
protected void onPostExecute(String data) {
if(data != null){
adapter.setDate(data);
adapter.notifyDataSetChanged();
}
}
}.execute();
You should to implement adapter for your ListView
Try to follow pattern below
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FilesListView = (ListView) findViewById(R.id.remoteFilesListView);
adapter = new SimpleAdapter(/*...*/); // implement your custom adapter or use native
// 1. set adapter into FileListView
FilesListView.setAdapter(adapter);
new AsyncTask<Void, Void, List>() {
#Override
protected List doInBackground(Void... params) {
String xmlFormServer = Worker.getXmlresponse();
Log.d("Response from Serever", xmlFormServer;
// 2. READ YOUR DATA HERE
List result = null; //
// 3. send result to ui thread
return result;
}
#Override
protected void onPostExecute(List list) {
// the method executes on ui thread
// 4. put your data into adapter
// you should implement the method or create native adapter
adapter.setDate(list);
// 5. refresh list - only UI THREAD can do this
adapter.notifyDataSetChanged();
super.onPostExecute(list);
}
}.execute();
}
I've checked other answers regarding the asynchronous updates of ListFragments and have figured out that the most common problem for the notifyDataSetChanged() method not working is, that developers tend to overwrite the initial adapter source, causing the adapter to lose reference and hence not updating the view. I have a ListFragment that I want to update asynchronously. What I've decided to do, is parse the list data in an AsyncTask and finally update the fragment in onPostExecute(). I want the UI to be as fluid as possible, so I want to avoid doing heavy processing on the main thread. I call the AsyncTask after the views are created to avoid null pointers.
public class CategoryFragment extends ListFragment {
ArrayList<Category> categoriesArray = new ArrayList<Category>();
CategoryAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_category, container, false);
adapter = new CategoryAdapter(getActivity(), R.layout.category_list_item, categoriesArray);
setListAdapter(adapter);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
new UpdateUITask().execute(categories);
}
...
// The async task to update the UI.
class UpdateUITask extends AsyncTask<String, String, ArrayList<Category>>{
#Override
protected ArrayList<Category> doInBackground(String... input) {
// Do some data processing, to fill the categoriesArray.
// categoriesArray.add(...); -- loop
return categoriesArray;
}
#Override
protected void onPostExecute(ArrayList<Category> result) {
super.onPostExecute(result);
adapter.notifyDataSetChanged();
}
}
}
The refresh method fires, but produces no result. What else am I missing here? Should I pick a completely different approach?
Its looking like your instance of categoriesArray is getting lost. adapter.notifyDataSetChanged(); doesn't work only in case when your refrence of the listArray which you just passed to the adapter has been lost or changed. So, I would reccomend you to please make sure about this.
Also if you are going to populate your custom array then, use onProgressUpdate() method of the AsyncTask. It will reduce the loading time too.
You can do this like this:
class UpdateUITask extends AsyncTask<String, Category, ArrayList<Category>>
{
#Override
protected ArrayList<Category> doInBackground(String... input)
{
// Do some data processing, to fill the categoriesArray.
// and get the category objects one by one and call
//publishprogress till data is there
publishProgress(Category);
// and finallly just return somthing to get in onpostexecute
}
#Override
protected void onProgressUpdate(Category... values)
{
// TODO Auto-generated method stub
super.onProgressUpdate(values);
categoriesArray.add(...);
adapter.notifyDataSetChanged();
}
#Override
protected void onPostExecute(ArrayList<Category> result)
{
super.onPostExecute(result);
adapter.notifyDataSetChanged();
}
}
use below code for your AsyncTask, but please make sure again you are changing in the original categoryList.
private class UpdateUITask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// Do some data processing, to fill the categoriesArray.
return null;
}
#Override
protected void onPostExecute(Void result) {
adapter.notifyDataSetChanged();
}
}
and just run this task with passing any argument.
new UpdateUITask().execute();
I have a main activity with three fragments. In the first fragment is a listview. I populate it in the fragment's onCreateView method like this:
private ArrayList<MobileNETDistinctChatInfo> m_parts = new ArrayList<MobileNETDistinctChatInfo>();
public MobileNETDistinctChatInfoAdapter m_adapter;
public ListView list;
public String logged_user;
onCreateView(){
LinearLayout view = (LinearLayout) inflater.inflate(R.layout.tab1, container, false);
list = (ListView)view.findViewById(R.id.chats_list)
m_parts = db.MESSAGES_getAllDistinctChatInfo(logged_user);
// adapter extends the ArrayAdapter
m_adapter = new MobileNETDistinctChatInfoAdapter(getActivity(), R.layout.chatlist_list_item, m_parts);
list.setAdapter(m_adapter);
return view;
}
I would like to refresh the listview in the onResume() method in fragment1, but I can't get it to work. I tried these two methods (If I use the first method, nothing happens. If I use the second, the app crashes, returning a NullPointerException):
# 1
public void onResume() {
super.onResume();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
m_adapter.notifyDataSetChanged();
}
}
}
# 2
public void onResume() {
super.onResume();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
m_parts.clear();
m_parts = db.MESSAGES_getAllDistinctChatInfo(logged_user);
ListView list = (ListView) getActivity().findViewById(R.id.chats_list);
MobileNETDistinctChatInfoAdapter caa = (MobileNETDistinctChatInfoAdapter) list.getAdapter();
caa.clear();
for(MobileNETDistinctChatInfo el : m_parts){
caa.add(el);
}
list.setAdapter(caa);
}
}
}
I've printed the size of m_parts and m_adapter in OnResume() and it seems the adapter isn't being refreshed, but m_parts is. Does anybody know why, or how I can solve this?
You are running a m_adapter.notifyDataSetChanged() in a separate thread which leads the execution of refreshing the list before even the list is modified or updated actually.
if you debeg your code then you can see that it is working fine because the thread got enough time to get executed.
I have two classes,HomeActivity and CustomListAdapter.THe HomeActivity class extends an activity and then updates a listview.I am populating the data to the listview using a CustomListAdapter class which extends BaseAsapter.Everything is working fine but i want to load the data in a background task.When i do that,an error comes up.
Here is my implementation of the onPostExecute of the AyncTask class.
#Override
protected void onPostExecute(HomeActivity Params){
progressDialog.dismiss();
runOnUiThread(new Runnable(){
public void run(){
final ListView lv1 = (ListView) findViewById(R.id.listings);
lv1.setAdapter(new CustomListAdapter(this, shares));
}
});
}
I get an error telling me that i should change the constructor on CustomListAdapter.But when i change it,everything goes downhill.
I have tried this unsuccessfully too
final ListView lv1 = (ListView) findViewById(R.id.listings);
lv1.setAdapter(new CustomListAdapter(this, shares));
shares is an arraylist of data from the web service.
Here is the constructor in the CustomListAdapter class
public CustomListAdapter(Context context, ArrayList listData) {
this.listData = listData;
layoutInflater = LayoutInflater.from(context);
}
How can go about it?Help will be highly appreciated.
You have to change :
#Override
protected void onPostExecute(HomeActivity Params){
progressDialog.dismiss();
runOnUiThread(new Runnable(){
public void run(){
final ListView lv1 = (ListView) findViewById(R.id.listings);
lv1.setAdapter(new CustomListAdapter(YourActivity.this, shares));
}
});
}
See the below code works for me
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
progressDilaog.dismiss();
itemListAdapter = new ItemListBaseAdapter(
IncidentListActivity.this, Util.arrIncidents);
gridView.setAdapter(itemListAdapter);
}
And one more thing, you don't require runOnUiThread in onPostExecute method. You can directly change your listview.
You are sending your AsyncTask context to your Adapter , you should put your Activity context which hosts your Listview to your AsyncTask class then use that Context to construct your Adapter.
Edit : look at this as an example and onPostExecute by default runs on Ui thread and it doesn't need to define a runOnUiThread
public class SyncHandler extends AsyncTask<String, Void, ResponseType>{
private Activity activity;
public SyncHandler (Activity activity)
{
this.activity = activity;
}
then in your calling Activity pass the Activity context to your Async class :
new SyncHandler(this).execute();
I have created a custom adapter that inflates rows in a fragment. I would like to know how to put this in a thread.
In my fragment I have:
context = getActivity().getApplicationContext();
ListAdapter adapter = new NotesAdapter(courseId, context);
setListAdapter(adapter);
Every thing works this way but I have tried to put this in all four ways (AsyncTask, Java thread...) that Android offers for multithreading but the adapter won`t start that way. It just shows blank screen.
Can anyone help me how to put this in a separate thread?
For your reference,
public class SampleTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// Do your Background process Eg.. some Parsing whatever it's, then paste you adapter initialization code
// Initialize your adapter as global
CustomAdapter sampleAdapter = new CustomAdapter(CurrentActivity.this,
R.id.ImageView01, <Your Arraylist/Array>);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Here you set your adapter
listView.setAdapter(sampleAdapter);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
}