So, I made a function to return an ArrayList of strings. In that function, i have an if/else statement. In the if statement I start a background thread using AsyncTask. My question is, will my function return me the ArrayList called queriedCardIDList before I finish the AsyncTask? And if so, how do I work around this?
Cheers!
public ArrayList<String> getCardIDList()
{
if(shouldIQuery())
{
QueryCardsAsyncTask queryCardsAsyncTask = new QueryCardsAsyncTask();
queryCardsAsyncTask.execute();
}
else
{
myPreferences.loadCardsPrefs();
for(CardModel c : myPreferences.getSavedCards())
{
queriedCardIDList.add(c.getCardID());
}
return queriedCardIDList;
}
return queriedCardIDList;
}
Manage your async task as mentioned below,
public class QueryCardsAsyncTask extends AsyncTask<Void, Void, ArrayList<String>> {
private ArrayList<String> queriedCardIDList = new ArrayList<>();
#Override
protected ArrayList<String> doInBackground(Void... params) {
if (shouldIQuery()) {
// You logic to be written in async task
} else {
// else part, get your data from preference
myPreferences.loadCardsPrefs();
for (CardModel c : myPreferences.getSavedCards()) {
queriedCardIDList.add(c.getCardID());
}
}
return queriedCardIDList;
}
#Override
protected void onPostExecute(ArrayList<String> cardIdList) {
super.onPostExecute(cardIdList);
// Now use cardIdList here as per your requirement
}
}
Then just call async task only
QueryCardsAsyncTask queryCardsAsyncTask = new QueryCardsAsyncTask();
queryCardsAsyncTask.execute();
Related
In my application, I should use Material Stepper and for this, I want to use this library : https://github.com/ernestoyaquello/VerticalStepperForm
But I want to add this dynamically from server.
For connecting with server I used Retrofit library and I should check the type of items from server.
when this type is "penny" show one of this steps and when the type is "best" show another step.
I create this steps from library tutorials, but i want when type is penny show me StepDynamicTxt and when the type is best show me StepDynamicEdt!
I write below codes but just add one of the items from each step!
But in API, I have 2 item of penny types and 3 items of best type!
Should show me 5 step, but show me 2 step!
My codes :
public class StepperActivity extends AppCompatActivity {
private ApiServices apiServices;
private ProgressBar loader;
private VerticalStepperFormView stepper;
private StepDynamicEdt stepDynamicEdt;
private StepDynamicTxt stepDynamicTxt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bidzila_stepper);
//Initialize
apiServices = ApiClient.ApiClient().create(ApiServices.class);
loader = findViewById(R.id.bidStepper_loader);
stepper = findViewById(R.id.bidStepper);
//Api
callAPi();
}
private void callAPi() {
loader.setVisibility(View.VISIBLE);
Call<TodayResponse> call = apiServices.TODAY_RESPONSE_CALL(5);
call.enqueue(new Callback<TodayResponse>() {
#Override
public void onResponse(Call<TodayResponse> call, Response<TodayResponse> response) {
if (response.isSuccessful()) {
if (response.body() != null) {
if (response.body().getRes() != null) {
if (response.body().getRes().getToday().size() > 0) {
loader.setVisibility(View.GONE);
//Foreach
for (int i = 0; i < response.body().getRes().getToday().size(); i++) {
if (response.body().getRes().getToday().get(i).getType().equals("penny")) {
stepDynamicEdt = new StepDynamicEdt(response.body().getRes().getToday().get(i).getName());
} else if (response.body().getRes().getToday().get(i).getType().equals("best")) {
stepDynamicTxt = new StepDynamicTxt(response.body().getRes().getToday().get(i).getName());
}
}
stepper.setup(new StepperFormListener() {
#Override
public void onCompletedForm() {
}
#Override
public void onCancelledForm() {
}
}, stepDynamicEdt, stepDynamicTxt)
.allowNonLinearNavigation(false)
.displayCancelButtonInLastStep(false)
.displayBottomNavigation(false)
.confirmationStepTitle("Confirm")
.stepNextButtonText("Continue")
.lastStepNextButtonText("Finish")
.includeConfirmationStep(false)
.init();
}
}
}
}
}
#Override
public void onFailure(Call<TodayResponse> call, Throwable t) {
Log.e("ResponseErr", t.getMessage());
}
});
}
#Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase));
}
}
I think this problem for this line:}, stepDynamicEdt, stepDynamicTxt) because just add 2 step.
How can i add this step dynamically in Android?
In your code, you are making a very fundamental mistake. And that is, you are using the same variable each time in your loop to store dynamic edit type and dynamic text type, which will replace any previously created fields. And hence when you finally create them, you end up with single last values of each type.
What you can do is, create a List with type Step, add new type every time you get them, and finally pass that list to the builder.
The builder accepts a list too, you should check implementation when its open source.
// before the for loop, create a list of type Step
List<Step> steps = new ArrayList();
// your loop on response received from server
for (int i = 0; i < response.body().getRes().getToday().size(); i++) {
if (response.body().getRes().getToday().get(i).getType().equals("penny")) {
StepDynamicEdt stepDynamicEdt = new StepDynamicEdt(response.body().getRes().getToday().get(i).getName());
// add to list
steps.add(stepDynamicEdt);
} else if (response.body().getRes().getToday().get(i).getType().equals("best")) {
StepDynamicTxt stepDynamicTxt = new StepDynamicTxt(response.body().getRes().getToday().get(i).getName());
// add to list
steps.add(stepDynamicTxt);
}
}
// finally create them
stepper.setup(new StepperFormListener() {
#Override
public void onCompletedForm() {
}
#Override
public void onCancelledForm() {
}
}, steps) // pass the list
.allowNonLinearNavigation(false)
.displayCancelButtonInLastStep(false)
.displayBottomNavigation(false)
.confirmationStepTitle("Confirm")
.stepNextButtonText("Continue")
.lastStepNextButtonText("Finish")
.includeConfirmationStep(false)
.init();
I want to know how to access the data and bind it to a component in out of the AsyncTask class body?
I have a class like:
class DownloadData extends AsyncTask<String, Void, String> {....}
and it has a method :
#Override
protected String doInBackground(String... params) {
return ....;//return some data
}
I don't understand doInBackground return data to where?
Because when i want to use my class, i use it like:
DownloadData dd = new DownloadData();
dd.execute(...);
can i use it like this? because i want to fetch returned data out of my main class to bind it to some components
DownloadData dd = new DownloadData();
string temp=dd.doInBackground(...);
After doInBackground() your return will be forwarded to onPostExecute().
To use it in your activity refer this link : How to use Async result in UIThread
I can not catch
#Override
protected String doInBackground(String... params) {
return ....;//return some data
}
result from main UI.
You have to use callbacks. For example, you can use interface to obtain the result.
For example create an interface:
public interface IProgress {
public void onResult(int result);
}
create class:
private class DownloadData extends AsyncTask<String, Void, String> {
private IProgress cb;
DownloadData(IProgress progress) {
this.cb = cb;
}
#Override
protected String doInBackground(String... params) {
for (int i = 0; i < 10; i ++) {
if (cb!=nil)
cb.onResult(i);//calls 10 times
}
....
}
...
}
somewhere in code:
DownloadData dd = new DownloadData( new IProgress() {
public void onResult(int result) {
/// this is your callback
//to update mainUI thread use this:
final res = result;
runOnUiThread(new Runnable() {
#Override
public void run() {
//update UI here
textview.setText("" + res);
}
});
}
});
dd.execute(...);
And, as usual, you can update UI after doInBackground via onPostExecute()
If you just want to return a result from your AsyncTask class so that you can update the UI in your activity according to the result you can do something like this:
In your AsyncTask class declare an interface like this:
private AsyncResponse asyncResponse = null;
public DownloadData(AsyncResponse as) {
this.asyncResponse = as;
}
public interface AsyncResponse {
void onAsyncResponse(String result); // might be any argument length of any type
}
and in onPostExecute() :
asyncResponse.onAsyncResponse(result); // result calculated from doInBackground()
and in the activity class:
DownloadData dd = new DownloadData(new AsyncResponse() {...}); // implement onAsyncResponse here
dd.execute();
private class exampleTask extends AsyncTask<String, Void, SomeResult>{
#Override
protected SomeResult doInBackground(String... urls) {
SomeResult res ;
someMethod(new CallBack<T>(){
#Override
public void onResponse(SomeResult something) {
res = something ;
}
#Override
public void onFailure() {
//
}
});
return res ;
}
#Override
protected void onPostExecute() {
//
}
}
Please I want to assign "res" to "something" witch is inside the callback in the onResponse method. In this code it's impossible to assign res inside the onResponse method.
Please any help is welcome.
Thank you :)
my original code : I'd like to assign "url" ;
private class GetBeaconInfosTask extends AsyncTask<String, Void, Call<Url>> {
Url url ;
#Override
protected Call<Url> doInBackground(String... urls) {
ProxService service = ProxService.Factory.makeProxService(ProxService.ENDPOINT);
return service.getUrlDetails(urls[0]);
}
// onPostExecute return the results of the AsyncTask.
#Override
protected void onPostExecute(Call<Url> call) {
call.enqueue(new Callback<Url>() {
#Override
public void onResponse(Call<Url> call, Response<Url> response) {
url = response.body();
}
#Override
public void onFailure(Call<Url> call, Throwable t) {
//
}
});
if(url == null){
Log.i("url is null", "url is null !!!!! ....");
}
else {
setShopLogo(url.icon) ;
setShopName(url.title);
setDescription(url.description);
setlongUrl(url.longUrl); }
}
}
Assuming the problem is due to the variable having to be declared as final to be accessible from the callback, you could move it out of the doInBackground method and declare it as a member of the exampleTask class.
private class exampleTask extends AsyncTask<String, Void, SomeResult>{
SomeResult res;
#Override
protected SomeResult doInBackground(String... urls) {
someMethod(new CallBack<T>(){
#Override
public void onResponse(SomeResult something) {
res = something ;
}
#Override
public void onFailure() {
//
}
});
return res ;
}
#Override
protected void onPostExecute() {
//
}
}
While this should answer your question, it's hard to tell what you're trying to achieve. Further to #Gabe Sechan's answer - your variable may never get assigned, or it would be assigned after a certain length of time. Ordinarily you would carry out work in the doInBackground and when that has been carried out onPostExecute is called, but in your case you'll likely have onPostExecute called before hitting the onRespons of your callback. I don't think it's good practice to use a Callback in doInBackground the way you're trying to use it.
If you have other work that needs to be carried out asynchronously in doInBackground, do that, but move the someMethod call to onPostExecute and do whatever you need to do with res in there.
private class exampleTask extends AsyncTask<String, Void, SomeResult>{
SomeResult res;
#Override
protected SomeResult doInBackground(String... urls) {
// background work
}
#Override
protected void onPostExecute() {
someMethod(new CallBack<T>(){
#Override
public void onResponse(SomeResult something) {
res = something ;
// DO STUFF WITH RES HERE AFTER IT'S BEEN ASSIGNED OR YOU WON'T HAVE ACCESS TO IT
}
#Override
public void onFailure() {
//
}
});
}
}
EDIT: Now that the question contains real code, I can provide a flow that should work for you. Note in the code I pasted above the comment in onResponse stating this is where you should have the code that uses the variable. Look at onResponse below for example using your code. The value doesn't exist until you get to the onResponse callback method, so you have to wait until it gets there. Your code below is being carried out before onResponse so the variable is inevitably null. The code isn't executed sequentially. I'd suggest studying callbacks to fully understand them :)
private class GetBeaconInfosTask extends AsyncTask<String, Void, Call<Url>> {
Url url ;
#Override
protected Call<Url> doInBackground(String... urls) {
ProxService service = ProxService.Factory.makeProxService(ProxService.ENDPOINT);
return service.getUrlDetails(urls[0]);
}
// onPostExecute return the results of the AsyncTask.
#Override
protected void onPostExecute(Call<Url> call) {
call.enqueue(new Callback<Url>() {
#Override
public void onResponse(Call<Url> call, Response<Url> response) {
url = response.body();
setShopLogo(url.icon) ;
setShopName(url.title);
setDescription(url.description);
setlongUrl(url.longUrl); }
}
#Override
public void onFailure(Call<Url> call, Throwable t) {
//
}
});
}
You seem to not understand the purpose of a callback. A callback is called at some point in the future. Not now. So the function that sets up the callback won't be assured its called by the end of its execution. What you want will never work. Instead, you should execute whatever you wanted to do in onPostExecute with that value in the body of the callback.
i have qualification what is best why to getting data from data base in android.
my code
class MyClass{
List<String> listdata;
public void getData(){
new DownloadTask (){
protected void onPostExecute(List<String> result) {
listdata = result;
// listdata contain 10 records
}
}.execute();
// here list data is null out side asynctask
listdata is null
}
private class DownloadTask extends AsyncTask<Void, Void, List<String>> {
protected List<Stirng> doInBackground() {
return data.getAllRecords();
}
}
}
if anything wrong me correct me , Thanks
listdata is assigned a value in the onPostExecute() which is called at a later point after the doInBackground() has finished.
doInBackground(Params...) This step is used to perform background
computation that can take a long time.
onPostExecute(Result) invoked on the UI thread after the background
computation finishes. The result of the background computation is
passed to this step as a parameter.
You execute the task and then try to access the value of listdata in the next line. It will be null as the task has not completed as yet, the onPostExecute() has not been called yet.
Its not final. You are not using the enclosed value.
class MyClass{
final List<String> listData;
public myClass(){
listData = new ArrayList<String>();
}
public void getData(){
new DownloadTask (){
protected void onPostExecute(List<String> result) {
listData.addAll(result);
listDataRetrieved();
};
}.execute();
private final void listDataRetrieved(){
assertTrue(listData != null && containsCorrectElements());
}
private class DownloadTask extends AsyncTask<Void, Void, List<String>> {
protected List<String> doInBackground() {
return data.getAllRecords();
}
}
}
I am using parse.com to make as a backend for an Android app. I have several "inBackground" related functions that need to happen consecutively and then send the results back to my Activity which I use to build a ListView. I am looking for a "clean" way to do this, such as writing a class with methods to call from my Activity. I can't figure out how to do this in an external class though. Take the following code for example:
List<ParseObject> list = ParseUtility.getList();
We will define getList() as something like
private List<ParseObject> result;
public List<ParseObejct> getList() {
ParseQuery<ParseObject> query = ParseQuery.getQuery(TABLE_NAME);
query.whereEqualTo(KEY, VALUE);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> list, ParseException e) {
if (e == null) {
result = list;
} else {
result = null;
}
}
});
return result;
}
I believe that the "findInBackground" would cause this method to return before "result" is set to the correct value. What is a workaround to this?
If you want to get result from your function you have to use 'synchronized' method ParseQuery.find(...) instead of 'asynchronous' ParseQuery.findInBackground(...). And then call this function from a worker thread or service or AsyncTask, etc...
public static List<ParseObejct> getList() {
ParseQuery<ParseObject> query = ParseQuery.getQuery(TABLE_NAME);
query.whereEqualTo(KEY, VALUE);
result = query.find();
}
new AsyncTask<Void, Void, List<ParseObject>>() {
#Override
protected List<ParseObject> doInBackground(Void... params)
{
return ParseUtility.getList();
}
}.execute();