Let's say I need to fetch data from a db asynchronously and then pass it to a recyclerview's adapter. Using AsyncTask, I can do the following:
void getItemsFromDb() {
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... voids) {
this.items = getFromDb(); // items is the adapter's data set
return null;
}
#Override
protected void onPostExecute(Void unused) {
super.onPostExecute(unused);
this.adapter.notifyDataSetChanged();
}
}.execute();
If I were to be doing this using WorkRequest, the fetching would look like this:
class MyWork extends Worker {
#NonNull
#Override
public Result doWork() {
getItemsFromDb() // <---- how do I pass this to my adapter?
return Result.success();
}
}
WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);
How would I get the items from a db and pass them to the adapter? And how do I call notifyDataSetChanged in the UI thread after the background work has completed?
Related
Like I need to check whether a username already existed in database, and the program won't continue until response arrives.
it seems you need asynctask, this is an example how to use it..
public class YourFragment extends Fragment implements YourAsyncTask.YourInterface {
public YourFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_your, container, false);
//do your initial things
.
.
.
YourAsyncTask yourAsyncTask = new YourAsyncTask(this);
yourAsyncTask.execute();
return view;
}
#Override
public void onJobFinishListener(YourDataType yourData) {
//when this method is trigered by your asynctask
//it means that you are in ui thread and update your ui component
//TODO: update ui component with your data
}
}
and this is the asynctask;
public class YourAsyncTask extends AsyncTask {
private YourInterface yourInterfaceListener;
private YourDataType yourData; //this data should be calculated in doInBackground method and send via interface
public YourAsyncTask(YourInterface yourInterfaceListener) {
this.yourInterfaceListener = yourInterfaceListener;
}
#Override
protected Object doInBackground(Object[] objects) {
//do your all background tasks here
.
.
.
yourData = do something here to fill your data..
return null;
}
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
yourInterfaceListener.onJobFinishListener(yourData);
}
public interface YourInterface{
void onJobFinishListener(YourDataType yourData);
}
}
Use AsyncTask to perform network operations
public class TalkToServer extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
/*
* do things before doInBackground() code runs
* such as preparing and showing a Dialog or ProgressBar
*/
}
#Override
protected void onProgressUpdate(Void... values) {
/*
* updating data
* such a Dialog or ProgressBar
*/
}
#Override
protected Void doInBackground(Void... params) {
//do your work here
return null;
}
#Override
protected void onPostExecute(Void result) {
/*
* do something with data here
* display it or send to mainactivity
* close any dialogs/ProgressBars/etc...
*/
}
}
And you can execute it using
TalkToServer myTask = new MyTask(); // can add params for a constructor if needed
myTask.execute(); // here is where you would pass data to doInBackground()
After the network call is done and response obtained onPostExecute() is called. If the AsyncTask is in inner class of your activity you can update UI inside onPostExecute(). Otherwise you can use an Interface to create a callback to activity.
You can find AsyncTask Docs here
You have to use async task. Then you can uae it your_async_class.execute().get() in your activiry this ..get method you want to it. Main thread will wait your async task. You have to change your_async_class extends AsyncTask
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 know how to use AsyncTask to download file, create a zip file or so.. as I call publishProgress() in my loop.
I got stuck when doInBackground() has a single slow line, no loops here, just creating an object where its constructor has slow loops.
I'm not sure about the reasonable way of updating progress in such case.
Here's a sample code:
public class Session {
private QQActivity activity;
public int createdParts;
public DailyClass daily;
private void checkDaily() {
if(!isDailyReady){
new SetAsyncQQDaily().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
class SetAsyncQQDaily extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String sdq = null;
daily = new DailyClass(Session.this); //Very very Slow!
// Do other network http
sdq = new String(Base64.encode(bos.toByteArray(),Base64.DEFAULT));
// Do some work
return sdq;
}
#Override
protected void onPostExecute(String sdq) {
//Never mind
}
#Override
protected void onPreExecute() {
Toast.makeText(activity,"Preparing the daily. Get ready!",Toast.LENGTH_LONG).show();
}
#Override
protected void onProgressUpdate(Void... values) {
//TODO: Update Value of leftBar
activity.leftBar.setProgress((100*createdParts)/Utils.DAILY_PART_COUNT);
}
}
}
In the slow constructor class, I can set-back an integer of the current progress: createdParts, but cannot call publishProgress.
public class DailyClass implements Serializable {
public DailyClass(Session session){
for(int i=1;i<=partCount;i++ ){ //Very slow loop
session.createdParts = i; //TODO: reflect value to progress bar!?
for(int j=0;j<questionsCount;j++){
objects[i-1][j] = createDefined(i);
}
Log.d("Daily","created part"+i);
}
}
//Bla .. !
}
I also though of passing the object of the AsyncTask to the slow constructor in order to call publishProgress() from there, but cannot. As publishProgress() is accessible only from doInBackground()
What's the best practice?
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 am implementing synronous class in back ground process I am getting some results. These results are stored in array list in post execute method. How can I retrieve these results?
Code file
public class DownLoanPhoto extends AsyncTask
{
protected void onPreExecute()
{
super.onPreExecute();
}
protected Object doInBackground(Object... params)
{
ArrayList hhh=new ArrayList();
hhh.add(PersonImage);
hhh.add(layoutmsg);
hhh.add(personName);
hhh.add(msgImage);
hhh.add(layoutPersonImage);
Bundle bbb=new Bundle();
bbb.putStringArrayList("val", hhh);
onPostExecute(bbb);
}
return params;
}
#Override
protected void onPostExecute(Object result)
{
//How to retrieve that array list results?
layoutPersonImage.addView(msgImage);
layoutPersonImage.addView(PersonImage);
layoutPersonImage.addView(personName);
ll1.setBackgroundResource(R.drawable.tabmessage);
ll1.setGravity(Gravity.CENTER);
ll1.addView(layoutPersonImage);
((LinearLayout)findViewById(R.id.LinearlayoutMessage)).addView(ll1);
}
}
Please forward some solution.
There is no need of calling onPostExecute in doInBackground it will be automatically called.
#Override
protected ArrayList<String> doInBackground(Void... url) {
ArrayList<String> list=null;
//Now manipulate your code get the right list
return list;
}
// -- called as soon as doInBackground method completes
#Override
protected void onPostExecute(ArrayList<String> list) {
//Your ui code.
}