since im new in android development, and i need to provide an asynctask class for my http request. i have a lot of http request function type in one activity, and i want to make it dynamic. so i wanted to create only one AsyncTask function that can run all my function.
so this is the example
private class WebServiceCall extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
pBar.setVisibility(View.VISIBLE);
pBar.setIndeterminate(false);
pBar.setClickable(false);
}
#Override
protected Void doInBackground(Void... params) {
// a function that i passed
Function01();
return null;
}
#Override
protected void onPostExecute(Void result) {
try{
some code
}
}
catch(Exception e)
{
e.printStackTrace();
}
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
pBar.setClickable(true);
pBar.setVisibility(View.GONE);
}
}
and i just call like this
Oncreate(
new WebServiceCall().execute(function01());
)
any help and code sample would be appreciate,
thanks
I don't know what you mean by a function as a parameter to another function!
but you can use Interfaces for this purpose.
for example:
create an Call Back interface that can be called in onPostExecute()
public interface ResponseCallback {
void onRespond();
}
and before calling asynckTask define it like this:
ResponseCallback callback = new ResponseCallback() {
#Override
public void onRespond() {
//code to be done after calling it from onPostExecute
}
};
and pass callback to the constructor of of the asynckTask and call it in onPostExecute
of course you can modify the signature of the interface to what ever you want.
Send class object with your function and call function from object in AsyncTask.
public class A
{
//your function
int function()
{
return...;
}
}
private class WebServiceCall extends AsyncTask<Void, Void, Void> {
A myobj;
WebServiceCall(A mycustomslass)
{
myobj = mycustomclass;
}
#Override
protected void onPreExecute() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
pBar.setVisibility(View.VISIBLE);
pBar.setIndeterminate(false);
pBar.setClickable(false);
}
#Override
protected Void doInBackground(Void... params) {
// a function that i passed
int cur = myobj.function();//this your function
return null;
}
#Override
protected void onPostExecute(Void result) {
try{
some code
}
}
catch(Exception e)
{
e.printStackTrace();
}
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
pBar.setClickable(true);
pBar.setVisibility(View.GONE);
}
}
and you can call like
Oncreate(
new WebServiceCall(new A()).execute();
)
This doesn't address your question directly, but I urge you to investigate both the fairly-well advertised problems with using AsyncTask for anything that's likely to take more than a few milliseconds, and the several really good HTTP / REST frameworks for Android, e.g. Retrofit.
Related
After years, I'm trying to develop an Android app, using Firebase Firestore. I'm basically trying to replicate this Swift function:
func getCategories(onCompletion completionBlock: #escaping (_ categories: [Category]?, _ error: Error?) -> Void) {
firestore.collection("cats").getDocuments { (snap, error) in
guard let snap = snap else {
completionBlock(nil, error ?? anUnknownError)
return
}
var categories: [Category] = []
for document in snap.documents {
let cat = Category.init(data: document.data())
categories.append(cat)
}
completionBlock(categories, nil)
}
}
But I have no idea what is the equivalent of swift's blocks, even don't know if it exists.
I checked Firebase source codes. Query.get() returns Task<QuerySnapshot> so I tried to return a Task<List<Category>> without luck.
Any Help? Thank you.
EDIT: Android code added to clarify what I'm trying to do.
public class FirestoreService {
private static volatile FirestoreService singleton = new FirestoreService();
public static FirestoreService getInstance() {
return singleton;
}
private FirebaseFirestore firestore() {
// default firestore instance
FirebaseFirestore db = FirebaseFirestore.getInstance();
// default firestore settings
FirebaseFirestoreSettings settings = db.getFirestoreSettings();
// firestore settings builder
FirebaseFirestoreSettings.Builder builder = new FirebaseFirestoreSettings.Builder(settings);
// enable timstamps
builder.setTimestampsInSnapshotsEnabled(true);
// set new settings to db instance
db.setFirestoreSettings(builder.build());
// return db with new settings.
return db;
}
public void getProductCategories(Handler? handler) {
Task<QuerySnapshot> task = firestore().collection("coll").get();
task.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
try {
if (task.isSuccessful()) {
List<Category> cats = new ArrayList<>();
for (QueryDocumentSnapshot doc : task.getResult()) {
String id = doc.getId();
Map<String, Object> data = doc.getData();
Category cat = new Category(id, data);
cats.add(cat);
}
// now I need completion handler
} else {
Log.w("ERROR", "Error getting categories", task.getException());
}
} catch (Exception e) {
Log.e("ERROR", e.getMessage());
}
}
});
}
}
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FirestoreService.getInstance().getCategories().addCompletionListener(
// handle List<Category> and respresent in UI
);
}
}
Thank you very much four your help and lead #Daniel-b.
I've solved my issue now.
First I created an Interface for handling results; as you suggested.
public interface ResultHandler<T> {
void onSuccess(T data);
void onFailure(Exception e);
}
Then in the service class, I added ResultHandler to the function's input parameters :
public void getUserInfo(String id, ResultHandler<UserInfo> handler) {
firestore().collection("userInfo").document(id).get().addOnCompleteListener(snap -> {
if (snap.isSuccessful()) {
try {
// failable constructor. use try-catch
UserInfo info = new UserInfo(snap.getResult().getId(), snap.getResult().getData());
handler.onSuccess(info);
} catch (Exception e) {
handler.onFailure(e);
}
} else {
handler.onFailure(snap.getException())
}
});
}
And called service in Activity
FirestoreService.getInstance().getUserInfo("ZsrAdsG5HVYLTZDBeZtkGDlIBW42", new ResultHandler<UserInfo>() {
#Override
public void onSuccess(UserInfo data) {
Log.i("UserInfo", data.id);
}
#Override
public void onFailure(Exception e) {
// getting data failed for some reason
}
});
Using AsyncTask
You can use an AsyncTask. It has 3 steps to it.
1. onPreExecute() - things you want to do before running doInBackground(). This happens in the UI main thread.
2. doInBackground()- the AsyncTask, will do operations in a background thread (the background thread is created by Android so you don't need to worry about it).
3.onPostExecute() - here you can receive any data from the doInBackground method. The postExecute method is executed again, in the UI main thread.
So you can do any I/O operations in doInBackground(), and return the value you received from the server or any other data source, and onPostExecute(), is the equivalent of a completion block in swift.
How to Declare
To use AsyncTask, you need to extend the Android AsyncTask.
So your own AsyncTask declaration will look like this:
private class MyAsyncTask extends AsyncTask<Void, Void, Void> { ... }
What are the 3 generic arguments you ask?
1. Params - the type of the parameters sent to the task upon execution.
2. Progress - the type of the progress units published during the background computation. (Almost always will be Void, unless you care about the actual progress of the operation. Notice this is Void with a capital letter, and not void as the return type).
3. Result - the type of the result of the background computation.
Full Example
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
TextView txt = findViewById(R.id.output);
txt.setText(result);
}
}
In the example, I create a fake, long operation, that you can not run on the UI main thread (because it is a blocking operation).
When the operation is finished, it returns a String, and that same String is received in the onPostExecute() method (and remember, onPostExecute() runs on the UI main thread again). So you can change your UI with the String value you received from the long,blocking operation.
If you want the documentation, here it is:
https://developer.android.com/reference/android/os/AsyncTask
Using Observer Pattern
You can also use the observer pattern in your situation.
Create an interface, that has a method onSuccess(). Have an object implement that interface, and whenever you need it, you can call the onSuccess() method.
Example:
public Interface SuccessInterface{
void onSuccess()
}
public class SuccessHandler implements SuccessInterface{
public void onSuccess(){
//success code goes here
}
}
then in your code, have a SucessHandler instantiated, and call onSuccess() when you need to.
For API 26,
CompletionHandler is available.
Check https://developer.android.com/reference/java/nio/channels/CompletionHandler
When a background task returns a value how can it be accesses from another class. Just using this as example code, but what I want is the background task to do something and return a value.
protected String doInBackground(String... params) {
publishProgress("Sleeping..."); // Calls onProgressUpdate()
try {
// Do your long operations here and return the result
int time = Integer.parseInt(params[0]);
// Sleeping for given time period
Thread.sleep(time);
resp = "Slept for " + time + " milliseconds";
} catch (InterruptedException e) {
e.printStackTrace();
resp = e.getMessage();
} catch (Exception e) {
e.printStackTrace();
resp = e.getMessage();
}
**return resp;**
}
For this you need to extend asynktask class like
extends AsyncTask<String, String, String>
#Override
protected void onPostExecute(String result) {
//heare result is value you return from doInBackground() method
//this is work on UI thread
}
Classs look like
public class AsyncTaskGetResult extends AsyncTask<String, String, String> {
PrintListner mPrintListner ;
private AsyncTaskGetResult (PrintListner mPrintListner) {
this.mPrintListner = mPrintListner;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
return result;
}
#Override
protected void onPostExecute(String result) {
//heare result is value you return from doInBackground() method
//this is work on UI thread
this.mPrintListner.getResult(result);
}
}
public interface PrintListner {
public void getResult(String receiptItem);
}
If you need to access it in another class you can write listner for that and implement in you activity
public class MyActivity extends Activity implements PrintListner{
#Override
public void getResult(String receiptItem){
//Do whatever you want
}
}
and call it like new AsyncTaskGetResult(this).execute(yourString);
AsyncTask:
public class YourBackgroundTask extends AsyncTask<String, Void, String> {
private Callback callback;
public YourBackgroundTask(Callback callback){
this.callback = callback;
}
protected void doInBackground(String... strings) {
// do what you have to do
return result;
}
protected void onPostExecute(String result) {
this.callback.onDone(result);
}
public Interface Callback{
void onDone(String result);
}
}
and call it like this:
new YourBackgroundTask(yourCallback).execute(yourString);
You have a little misunderstanding. Background tasks do NOT return a value. They just do something. If you want to get a value out of some computation done in background you can make the background task so that when it finishes, it notifies some object about the resulting value.
The previous behavior can be done through the observer pattern in which an object is used to observe events from another object. In this case you want to define an observer (often called listener) and pass it to your background task.
Your listener interface may look like this:
interface ValueListener {
public void onValueComputed(int computedValue);
}
Then an implementing class looks like this:
class ValueListenerImpl implements MyListener {
#Override
public void onValueComputed(int computedValue) {
//do something...
}
}
(or you can make an anonymous class)
Your background task:
class MyAsyncTask extends AsyncTask<Void, Void, Integer> {
ValueListener listener;
public MyAsyncTask(ValueListener valueListener) {
this.listener = valueListener;
}
#Override
public Integer doInBackground(Void.. params) {
//do something...
return someValue;
}
#Override
public onPostExecute(Integer.. values) {
listener.onValueComputed(values[0]);
}
}
Finally, in your main thread you do:
...
this.valueListener = new ValueListenerImpl();
new MyAsyncTask(this.valueListener).execute();
...
This is my code:
//.___ Async task bring info from API __./
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
mMovieDto = mDataSource.getPopularMovies();
return null;
}
#Override
protected void onPostExecute(Long result) {
fillList();
}
};
asyncTask.execute();
I'm getting the error that the onPostExecute is not overriding from super, witch is the right way to add this king of method to my AsyncTask?
Thanks for the help
Jose
You are missing the AsyncTask's generic types:
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the background computation.
Result, the type of the result of the background computation.
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
Change your code like this:
AsyncTask asyncTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
mMovieDto = mDataSource.getPopularMovies();
return null;
}
#Override
protected void onPostExecute(Void result) {
fillList();
}
};
asyncTask.execute();
I have 2 Classes: a Main Class handling the UI and a second Class for retrieving Data from SQL Server by using PHP.
From the first class a mehtod in the second class is called with passing and retrieving variables.
Actually it is working fine without AsyncTask.
But since I want to use the code on devices running Android 3.0 and above, I need to change the method to be an AsyncTask. Else I get this error: "android.os.networkonmainthreadexception"
the actual working code Looks like this:
Main class:
...
String inputString="1";
String outputString;
outputString = Class2.SomeMethodInClass2(inputString);
....
Class2:
public class Class2 {
public static String SomeMethodInClass2(String input) {
String Output;
...
//Do some php-sql stuff based on "input"-variable
//and return the "output"-variable
...
return output;
}
}
This code works perfectly on Android 2.0 but I need to change it to AsyncTask, because Andoid 3.0 and above is giving me: "android.os.networkonmainthreadexception"
I have read a lot of threads about AsyncTask, but I can not get it to work with Input and Output in my code.
Eclipse allways tells me there is something wrong with my code.
How do I have to change my code, to be a working async Task? (please explain using my above code sample)
--edit: if there is an easier way to get rid of "android.os.networkonmainthreadexception" on 3.0 an above than AsyncTask, this would be fine too! --
Have a Callback in SecondClass
Extend your SecondClass with Asynctask
Implement preExecute,doinbackground, postExecute methods
Do your stuff in doinbackground
return result in doinbackground
In postExecute pass result to the Callback
Implement SecondClass.Callback in FirstClass
start SecondClass (execute) and pass a Callback reference from FirstClass
In Callback just handle your next operations with the result
EDIT :
public class SecondClass extends AsyncTask<String, Void, String> {
public interface Callback {
public void update(String result);
}
Callback mCallback;
public SecondClass(Callback callback) {
super();
mCallback = callback;
}
#Override
protected String doInBackground(String... params) {
String result = null;
//do your stuff and save result
return result;
}
#Override
protected void onPostExecute(String result) {
if(mCallback != null)
mCallback.update(result)
super.onPostExecute(e);
}
}
public class FirstClass implements SecondClass.Callback{
#Override
public void update(String result){
//do your stuff with result
}
return_type someMethod(){
SecondClass sc = new SecondClass(this) ;
sc.execute(someurl);
}
}
thanks for your Posts!
But i found an alternative way that seems much easier and better to me than doing async Task.
i added to my main class:
public class MainClass extends Activity implements OnTouchListener {
...
BackgroundOperations1 ourBackgroundOperations; //<===new
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
ourBackgroundOperations = new BackgroundOperations1(); //<===new
...
}
#Override
protected void onPause() {
....
ourBackgroundOperations.pause(); // <===new
}
#Override
protected void onResume() {
....
ourBackgroundOperations.resume(); // <===new
}
//whole new class inside of "MainClass"
//runs a different thread, i believe...?
public class BackgroundOperations1 implements Runnable {
Thread ourThread = null;
boolean isRunning = false;
public void pause() {
isRunning = false;
while (true) {
try {
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
public void resume() {
isRunning = true;
ourThread = new Thread(this);
ourThread.start();
}
#Override
public void run() {
while (isRunning) {
if (dothis==true){
//here i call my mehtod from class2, whenever "dothis" is set to true (somewhere in my onTouch or where ever i want)
String inputString="1";
String outputString;
outputString = Class2.SomeMethodInClass2(inputString);
}
}
}
}
}
this works on Android 4.0 and i think it is the best way to do what i want. and to me it seems a lot clearer then AsyncTask, because i can call my methods an pass varaibles in a simple way.
or is there a reason to not do it like this?
I am trying to understand mechanism of callback handler. How is the handle() method invoked? Can anybody give an example of usage of custom callback handler (other than those used in Login Modules of JASS or so) in non Swing application?
Define an interface to handle the callback.
public interface ServiceListener<T> {
void callback(T result);
}
Define a method that takes ServiceListener as parameter and returns void.
Public void runInBackground(ServiceListener listener) {
...code that runs in the background...
listener.callback(...data to return to caller...);
}
And you can now do this from your main code:
runInBackground(new ServiceListener() {
#Override
public void callback(..returned data...) {
...Do stuff with returned data...
}
});
This is a basic example for requesting data from a webserver using the AsyncTask from an Android application.
First define the async class. Note that the constructor takes a listener which we use to publish the result once ready.
public class Webservice extends AsyncTask<String, Void, String> {
private DialogListener dialogListener;
public Webservice(final DialogListener dialogListener) {
this.dialogListener = dialogListener;
}
#Override
protected String doInBackground(final String... strings) {
// We cant trigger onComplete here as we are not on the GUI thread!
return "";
}
protected void onPostExecute(final String result) {
dialogListener.onComplete(result);
}
}
Basic server class for handling various network communications:
public class Server {
public void queryServer(final String url, final DialogListener service) {
// Simulate slow network...
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Webservice(service).execute(url);
}
}
We can now use this code inside our activity without having to worry how long the call takes as it is not going to halt the GUI as it is executed async.
Server s = new Server();
// Async server call.
s.queryServer("http://onto.dk/actions/searchEvents.jsp?minLatE6=55640596&minLngE6=12078516&maxLatE6=55642654&maxLngE6=12081948", new DialogListener() {
#Override
public void onComplete(final String result) {
toast("complete");
}
#Override
public void onError() {
toast("error");
}
});