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();
}
}
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 am new to Android and currently start learning how to implement PullToRefreshListview by using this library of chrisbanes. can you guys please explain to me, where should i put my code to call API for getting data, and which part should i set the(ImageBitmap) after i get the data (image URL) from API. as i know, we should do something in background to avoid the UI freeze when loading Image to UI, but i am not sure. Please help.
The following is the sample code from the library:
please explain to me what should i do in GetDataTask and onPostExecute. In the case like loading image.
#Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
// Do work to refresh the list here.
new GetDataTask().execute();
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
#Override
protected String[] doInBackground(Void... params) {
// Simulates a background job.
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
}
return mStrings;
}
#Override
protected void onPostExecute(String[] result) {
mListItems.addFirst("Added after refresh...");
mAdapter.notifyDataSetChanged();
// Call onRefreshComplete when the list has been refreshed.
mPullRefreshListView.onRefreshComplete();
super.onPostExecute(result);
}
}
Sorry for the newbie question, i jsust want to confirm it in order to follow the standard. sorry for my bad english
I think you should put your GetDataTask in a separated class with a Listener. This is an example of a listener you can have:
public abstract class RemoteCallListener implements IRemoteCallListener {
#Override
public abstract void onString(String s); //String is just an example.
#Override
public abstract void onError(Exception e);
}
You should give the listener to your constructor if your async task.
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
RemoteCallListener listener;
public GetDataTask(){
}
public GetDataTask(RemoteCallListener listener){
this.listener = listener;
}
#Override
protected String[] doInBackground(Void... params) {
// Simulates a background job.
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
}
return mStrings;
}
#Override
protected void onPostExecute(String[] result) {
listener.onString(result);
// mListItems.addFirst("Added after refresh...");
// mAdapter.notifyDataSetChanged();
// Call onRefreshComplete when the list has been refreshed.
// mPullRefreshListView.onRefreshComplete();
super.onPostExecute(result);
}
}
To make an instance of the call you should do something like
GetDataTask task = new GetDataTask(yourlistener);
task.execute("your link");
And in your 'controller'class you should make an instance of RemoteCallListener and when onString is called:
mListItems.addFirst("Added after refresh...");
mAdapter.notifyDataSetChanged();
// Call onRefreshComplete when the list has been refreshed.
mPullRefreshListView.onRefreshComplete();
You can also freeze the UI by the Dialogs class from android. An example is given here:
public final static ProgressDialog showLoading(Context c, String title,
String message, boolean indeterminate) {
ProgressDialog p = new ProgressDialog(c);
p.setTitle(title);
p.setMessage(message);
p.setCancelable(false);
p.setIndeterminate(indeterminate);
if (!indeterminate) {
// p.setProgressDrawable( c.getResources().getDrawable(
// R.drawable.progress ) );
p.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
p.setProgress(0);
p.setMax(100);
}
p.show();
return p;
}
But dont forget to close your Dialog!
You can contact me anytime if you have further questions
GetDataTask is used to call your webservice again to get the new list items. These things should be done in doInBackground. Once you get the new list item need to set the new adapter for your listview in onPostExecute.
I had AsyncTask in my adapter class when i calling first time it's working fine. But when i call second time it doesn't work.
I know when we want to call same task multiple times in activity class we have to call new MyTask.execute().But here am created my task in non activity class (i.e Adapter class) so here am unable to instantiate my task. How can i resolve this problem? Please provide any solution.
This is my code:
public AsyncTask<String,Void,Void> mytaskfavorite = new AsyncTask<String,Void,Void>() {
protected void onPreExecute() {
pd = new ProgressDialog(mContext);
pd.setMessage("Loading...");
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
//proDialog.setIcon(R.drawable.)
pd.setCancelable(false);
pd.show();
System.out.println("###########################################");
}
#Override
protected Void doInBackground(String...code) {
String buscode = code[0];
// TODO Auto-generated method stub
addFavoriteBusinessSelection.addFavoriteBusinessBusinessSelection(buscode);
System.out.println("##################################" + buscode);
return null;
}
#Override
protected void onPostExecute(Void res) {
pd.dismiss();
}
};
But here am created my task in non activity class (i.e Adapter class) so here am unable to instantiate my task.
That is not true. The you can initiate an AsyncTask from any class you wish with the guaranteed that doInBackground will be executed in a separate thread and the other methods in the called thread (usually the UI Looper thread).
To call it several types you should create a new class with it like that:
public Class TaskFavorite extends new AsyncTask<String,Void,Void>() {
// You can optionally create a constructor to receiver parameters such as context
// for example:
private Context mContext
public TaskFavorite(Context c){
mContext = c;
}
protected void onPreExecute() {
pd = new ProgressDialog(mContext);
pd.setMessage("Loading...");
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
//proDialog.setIcon(R.drawable.)
pd.setCancelable(false);
pd.show();
// Don't use println in Android, Log. gives you a much better granular control of your logs
System.out.println("###########################################");
}
#Override
protected Void doInBackground(String...code) {
String buscode = code[0];
// TODO Auto-generated method stub
addFavoriteBusinessSelection.addFavoriteBusinessBusinessSelection(buscode);
System.out.println("##################################" + buscode);
return null;
}
#Override
protected void onPostExecute(Void res) {
pd.dismiss();
}
};
and then from your code (anywhere, adapter or activity, or fragment or even a loop you call)
TaskFavorite task = new TaskFavorite(getContext()); // how you get the context to pass to the constructor may vary from where you're calling it, but most adapters to have one
task.execute(... parameters...);
I'm using a ListActivity and am filling the list view with an adapter as such:
// SimpleAdapter adapter = ...
setListAdapter( adapter );
setContentView( R.layout.main );
ListView lv = getListView();
lv seems to have zero children, even though I'm populating it with children from a layout and the adapter has many items in it. I noticed that if I wait some time -- when the list view is rendered fully -- it does have children. How can I get notified of when the list view is fully ready to be used?
You can populate your list in the background using an AsyncTask, and then notify yourself once the loading is complete.
class MyTask extends AsyncTask<Context, Integer, String> {
m_loaded = false;
#Override
protected String doInBackground(Context... params) {
Log.d("doinBackground", "here");
// do your loading
return "";
}
// -- gets called just before thread begins
#Override
protected void onPreExecute() {
super.onPreExecute();
}
// -- called as soon as doInBackground method completes
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
m_loaded = true; //your list is done loading
}
}