Issue
I have application, which needs to load data in specific order. The reason for that is simple. Data1
are needed to construct Data2
etc. For example if you have application which is loading user profile, you need user profile data to load other stuff in app.
So I call api.startup()
AsyncTask, which will inside onPreExecute()
call animation onUIThread
and inside doInBackground()
method it will call another api asyncTask
call(called getData1()
).
As that one call ends and data are received in CallBack
, and if it's success, it will callanother asyncTask().
Below you can see how it should work. But what will happen is that as getData1()
asyncTask is ended, it will switch to onPostExecute()
(inside api.startup()
) and return true to my callback. But data2 3 4 5
are still running and this makes my splashAnimation laggy.
How to solve this issue?
api.splashStartup(this)
fun startupRequest(): Boolean {
var INSTALLATION_ID: String? = getSharedPreferences(getString(R.string.SharedPrefs),
Context.MODE_PRIVATE)?.getString(getString(R.string.INSTALLATION_ID), null)
if(INSTALLATION_ID == null){
createInstallationID()
INSTALLATION_ID = getSharedPreferences(getString(R.string.SharedPrefs),
Context.MODE_PRIVATE)?.getString(getString(R.string.INSTALLATION_ID), null)
}
api.postStartup(INSTALLATION_ID!!, object: IStartupCallback {
override fun onError(errorJSON: JSONObject) {
createLog("SplashScreen", "Startup API Error -> " + errorJSON.toString())
createToast(errorJSON.toString())
}
override fun onSuccess(startupJSON: JSONObject?) {
createLog("SplashScreen", "Startup API Success -> " + startupJSON.toString())
val X_SESSION: String? = startupJSON?.getString("session")
val userID: Int = startupJSON.getInt("user_id")
loadData1(X_SESSION, userID)
}
}
return true
}
private fun loadData1(X_SESSION: String, userID: Int){
api.getData1(X_SESSION, userID, object: IData1Callback{
override fun onError(errorJSON: JSONObject) {
createLog("SplashScreenLoadData1", "Data1 API Error -> " + errorJSON.toString())
}
override fun onSuccess(data1: JSONObject?) {
//do some stuff with data
addDataToSingleton(data1)
loadData2(data1.getString("object_Hash"))
}
})
}
private fun loadData2(objectHash: String){
api.getData2(objectHash, object: IData2Callback{
override fun onError(errorJSON: JSONObject) {
createLog("SplashScreenLoadData2", "Data2 API Error -> " + errorJSON.toString())
}
override fun onSuccess(data1: JSONObject?) {
//do some stuff with data
addDataToSingleton(data2)
loadData3(data2)
}
})
}
////
API CLASS
fun splashStartup(splashActivity: Splash){
class GetSplashAsync: AsyncTask<Void, Void, Boolean>() {
override fun onPreExecute() {
createLog("SplashScreen: ", "Starting onPreExecute() --> anim on UIThread")
splashActivity.splashAnimation()
}
override fun doInBackground(vararg params: Void?): Boolean {
return splashActivity.startupRequest()
}
override fun onPostExecute(result: Boolean?) {
createLog("StartupAsync ", "startup async ended")
}
}
GetSplashAsync().execute()
}
fun postStartup(INSTALLATION_ID: String, callback: IStartupCallback){
class PostStartupAsync(private val startupCallback: IStartupCallback): AsyncTask<Void, Void, JSONObject>() {
override fun doInBackground(vararg p0: Void?): JSONObject {
val server = Server.getInstance(context!!)
val jsonObject = JSONObject()
jsonObject.put("installation", installation)
return server.doPost(context.getString(R.string.startup_resource_link), jsonObject)
}
override fun onPostExecute(result: JSONObject?) {
super.onPostExecute(result)
if(result!!.has("ErrorCode") && result.getInt("ErrorCode") == errServerOffline
|| result.has("ErrorCode") && result.getInt("ErrorCode") == errServerNotResponding){
startupCallback.onError(result)
} else if (result.has("error")){
startupCallback.onError(result)
} else {
startupCallback.onSuccess(result)
}
}
}
PostStartupAsync(callback).execute()
}
Solution
You see that's not how the execution works.
A thread execute statement one by one. So when you reach a statement where a new thread is started then the previous thread will not wait for this thread to finish things, instead it will move to next statement.
Similarly, when you execute your startup AsyncTask and in doInBackground()
you call a method startupRequest()
. Now this method is starting a new AsyncTask (new thread), so this method will return true just after starting the Async task. And you get its response in onPostExecute(). Now the startup AsyncTask
is already done and the next AsyncTask is working.
What you can do is -
1) Start the animation in first api call and end it in the last API call,OR
2) Call all the API request in same AsyncTask.
public MyAsyncTask extends AsyncTask<Void,Void,Boolean>() {
public void onPreExecute() {
//start animation
}
public Boolean doInBackground(Void ignore) {
JSONObject res1 = loadData1(); // Sync call to API
if (res1 is Success) {
JSONObject res2 = loadData2(); // Sync call to API
if (res2 is Success) {
JSONObject res3 = loadData3(); // Sync call to API
if (res1 is Success) {
return true;
}
}
}
return false;
}
public void onPostExecute(Boolean result) {
// stop animation
if (result) {
// show home
} else {
// show error
}
}
}
loadData() calls are Sync API call, means you dont need to run AsyncTask in then. Just call the API directly.
Answered By - Siddharth jain
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.