I'm facing an issue here, and I need some help.
In this application, we make Retrofit calls in the UI thread - right in the Activity -, this means that we don't have a good architecture (i know).
The problem I'm facing, is that i need to make an Synchronous GET when the user click a button, and the GET will give me which fragment the user will be redirected, and i need to wait the response of the web service.
Like this:
Button.setOnClickListener(v -> {
getWhichLandingShows(); // Here I make the retrofit call
if (mGoToNewLandingPage)
return LandingSaleV3Fragment.newInstance();
else
return NewLandingSaleFragment.newInstance();
});
I need a method that works, because i already tried everything, and I always get a MainThreadException.
This was my last try:
private void getWhichLandingShowSync() {
InteractionServices interactionServices = RestServices.getInteractionServices();
Call<GetLandingResponse> call = interactionServices.getLandingPage();
try {
call.execute();
} catch (IOException e) {
e.printStackTrace();
}
}
I already tried to put the Retrofit call in a separated class that extends IntentService, like this, but without success:
public class BackgroundService extends IntentService {
private static final String TAG = "NewLpIntentService";
public BackgroundService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
InteractionServices interactionServices = RestServices.getInteractionServices();
Call<GetLandingResponse> call = interactionServices.getLandingPage();
try {
call.execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Using call.execute() is not a good idea in your case. It runs the request on the current thread. You could use call.enqueue(callback) and then show a progressbar. The request runs on a background thread and once you get the callback on the current thread, navigate to other fragments when onResponse callback is successful.
Related
I need to send data over ad UDP connection on a time basis (once every 20ms).
I tried using a Handler / Runnable / postDelayed() approach ... it was working fine until Android 9.0.
Now I need to use a different approach based on AsyncTask:
class SendCommandTask extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
do{
sendCommands();
wait(UPDATE_DELAY);
} while(!isCancelled());
}
catch (Exception e)
{
Log.e(this.getClass().getName(), e.getMessage());
}
return null;
}
}
but it fails throwing an java.lang.IllegalMonitorStateException .
I know the problem is the wait() call but I cannot find a simple way to achieve the same result.
The solution to this issue is to simplify doInBackground method executing just a single sendCommands() call:
class SendCommandTask extends AsyncTask<Object, Void, Void> {
#Override
protected Void doInBackground(Object[] param) {
try {
sendCommands();
}
catch (Throwable e)
{
Log.e(this.getClass().getName(), e.getMessage());
}
return null;
}
}
AsyncTask objects are instantiated and executed trough a recurring thread structure:
timerTask = new Runnable() {
#Override
public void run() {
new SendCommandTask().execute();
sendCommandsTimerHandler.postDelayed(this, UPDATE_DELAY);
}
};
in this specific case a simple timer.
Please note that all this has been wrote to avoid rising of exceptions due to use of network bound resources inside SendCommands() calls. In my previous code these calls where executed straight inside the very same timer as above. Now I have to wrap everything like this... looks like a non-sense to me.
My scenario is an onCreate() activity method which executes the following code (simplified):
dialog.show(); //loading wheel
try {
remote.sendRequest(myData, new MyHandler());
}
catch (Exception e) {
dialog.dismiss();
//log and react
}
class MyHandler extends SDKSpecificCompiledHandler {
#Override
public void failure() {
dialog.dismiss();
//do stuff
}
#override
public void success() {
dialog.dismiss();
//do stuff
}
}
//I have read-only access to this handler!
public abstract class SDKSpecificCompiledHandler {
public abstract void success(JSONObject successData);
public abstract void failure(JSONObject errorData);
}
Explanation: A remote service is called passing an handler that gets called when he's done. A loading wheel (dialog) is shown to the user until a success, failure or exception happens.
The problem is when the service gets successfully called but no response ever comes. In that case dialog.dismiss() doesn't get called and the loading wheel keeps spinning for ever.
What I need is a sort of timeout which dismisses the dialog (and possibly takes other actions) after some seconds if the server doesn't get back.
My first though would be to create a new thread for the service call, and right after the launch set a timer which dismisses the dialog.
Would it be a good idea?
Thank you,
EDIT:
The service is third-party/not editable. I'm using a pre-compiled artifact.
Still not really sure what you're trying to achieve but if you want to run some code after some time on main thread (i.e. your code will do stuff to the UI), you can use a android.os.Handler
mHandler = new Handler(getMainLooper());
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
// do stuff on UI thread
}
},10000);
When your call returned from the server, simply cancel the messages on the queue:
mHandler.removeCallbacksAndMessages(null);
It is better to use time out in service call itself, You can set the time out with service , If you need know how to set the time out then I should know what kind of service you are using ?
One more thing is that if you are using a loader you should make that loader in such a way that it can be cancel by the client.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can’t create handler inside thread that has not called Looper.prepare() inside AsyncTask for ProgressDialog
I'm developing an Android service that try to obtain the device IP address every x time and comunicate it to a server.
I'm using:
Netbeans 7.2Android SDKAndroid Google-Api 8SQLite
I know there are a few questions related to this same issue, but none of them gave me a solution to my problem. As you can see in my code below, I'm not trying to access to the UI of the service main thread (well, I tried, but after I commented the line, the error remains the same). On the other hand, I'm using AsyncTask, which I think is the appropriate way to do it.
This is the main part of my service:
public class ArsosService extends Service {
private NotificationManager mNM;
private final Messenger mMessenger = new Messenger(new IncomingHandler());
protected DatabaseUtil dbu = null;
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
try {
dbu = DatabaseUtility.getInstance(this);
} catch (IOException ex) {
Log.e("Service", ex);
}
Timer timer = new Timer();
timer.schedule(new Checks(), 0, 15000);
}
private class Checks extends TimerTask {
#Override
public void run() {
CheckIpAddress_Task checkIp = new CheckIpAddress_Task();
checkIp.execute();
}
}
// Other methods
private class CheckIpAddress_Task extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... arg0) {
String ipLocal = getLocalIpAddress();
String text = null;
// ipLocal==null means there is no available connection, so we do nothing.
if (ipLocal != null) {
String ipDb = dbu.getLastIP(); // we get the IP saved in the DB.
if (ipDb == null) {
dbu.addProperty("IP", ipLocal); // we save the IP in the DB.
} else if (!ipLocal.equals(ipDb)) {
dbu.setProperty("IP", ipLocal); // we update the IP in the DB.
}
}
if (text != null) {
//showNotification(1, text, ipLocal);
}
return 0;
}
private String getLocalIpAddress() {
String result = null;
// Irrelevant code
return result;
}
}
}
I think the problem may be related to the threads, but I can't see where. Any help will be appreciated.
EDITED: Although I have accepted one of the answers as correct, or maybe because of it, I've been searching for some more information regard to it. I've run into this page I want to share with all of you who someday need to know more about this issue. Its author,Tejas Lagvankar, explains everything about threads, loopers and handler in a very clear and understandable way.
Try this...
- First declare the Handler Object reference variable at class scope.
Handler h;
- Inside the onCreate() method create the instance of the Handler.
h = new Handler();
- Use it with thread like below:
new Thread(new Runnable(){
public void run(){
h.post(new Runnable(){
// Do the UI work here.
});
}
});
- You can very well use the AsyncTask, provided in android, its known as P*ainless threading.*
Handler always runs in the Looper thread context. When you declare a seperate thread, its context is different from the Looper. Hence the error.
Simple solution is always declare Handlers in onCreate(), onStart() and onResume(). If you use AsyncTasks, you can very well declare handlers in onPreExecute() and onPostExecute() as they too run in the Looper context.
(I know this question has been asked in many different flavors, thanks for considering the specifics of my situation).
I am implementing a 3rd party library. One of the methods requires user input, and the return value of this method needs to be the user's response. Specifically, this method needs to pop up an alert dialog. The user will have 3 buttons to choose from and the return value of this method must be an int identifying the button the user clicked.
The only way I've gotten this working is by calling this alert method from an AsyncTask and from there calling runOnUIThread to pop up the alert and then wait for the response. Where I'm stuck is the case where this alert method is being called from the UI thread. Is there a similar work around to wait on a response in this case?
This is what my code currently looks like... as long as this method is called from an AsyncTask I'm good to go. BUT, I need to be able to call it from the UI thread.
public int getInput(final Object [] args)
{
getActivity().runOnUiThread(new Runnable(){
#Override
public void run()
{
buildDialog(args).show();
}
});
try
{
synchronized(this)
{
wait();
}
}
catch (Exception ex)
{
return 0;
}
return m_Result;
}
public void setRetValue(int result)
{
m_Result = result;
synchronized(this)
{
notify();
}
}
(setRetValue gets called from onClick in the OnClickListeners of the buttons in the dialog.)
I'm working on an Android project (API level 10) which needs to send and receive http messages to/from a server.
I implemented a class named NetworkManager which provides different methods, one for each http request (e.g.: loginRequest(user pass), RegistrationRequest(user.....) ).
All these methods generates a JSON object that is passed to the method called sendMessage, which is the method that actually establish the connection, sends and receives the response (also a json object).
Of course network calls are time consuming, so i first decided to use an AsyncTask to display a progressDialog while the network operation is being performed.
The problem is that i need to get the response value retrived from the background thread before executing any other operation which involves the result itself done by the Main thread.
At the same time i would like to make a common and reusable implementation of the AsyncTask.
E.g.: I have a login activity which shows 2 EditText (username, password) and a button called Login. When I press the login button, a progressDialog must appear, and must be disposed once the doInBackground task is accomplished. Of course i could do this way:
onClick(View v) //called when the login button is pressed
{
onPreExecute()
{
//Show the progress dialog
}
doInBackground()
{
//Retreive the login response (an integer containing a message code) using sendLoginRequest(username, password);
//return the response
}
onPostExecute(int response)
{
//Dispose the progress dialog, then loginSucessfull ? start new activity : show error toast
}
}
But, doing this way i should implement an async task for every request i need to send which is what i would like to avoid because if i have N requests i should create N classes that extend AsyncTask.
Thank you!
What i would suggest you is to use INTERFACES for handling response of http request.
The background thread either it be a AysncTask or it be Thread needs to handle both
response
exception
Think it like this way
MainThread - Hey Background Thread do this operation and let me know when you are done.
MainThread - Ok till Background Thread executes its operation let me show progress dialog.
BackGroundThread - I am done with my work. hey MainThread here catch you response or exception
MainThread - Let me stop showing progress bar.
So we need to simulate this callback mechanism via code and also needs to take care that we implement a reusable architecture.
Something like this
Define a Interface
public interface HttpRequestResponse {
public void onSuccess(HttpResponse response);
public void onException(Exception exception);
}
class HttpRequestResponseHandler {
private ActionItem action;
private HttpRequestResponse hrr;
private Executor executor;
public enum ActionItem {
LOGIN_REQUEST ,
REGISTRATION_REQUEST
}
public HttpRequestResponseHandler(ActionItem action, HttpRequestResponse hrr) {
this.action = action;
this.hrr = hrr;
}
public void execute(){
executor = new Executor();
executor.execute();
}
private class Executor extends AsyncTask<Void,Void,Void> {
#Override
public Void doInBackground() {
switch(action) {
case LOGIN_REQUEST : doLogin();
break;
case REGISTRATION_REQUEST : doRegistration();
break;
}
}
}
private void doLogin() {
HttpResponse response = null;
Exception exception = null;
try {
response = makeHttpRequestHere();
} catch (Exception e) {
exception = e;
}
if(exception != null) {
hrr.onException(exception);
} else {
hrr.onSuccess(response);
}
}
}
Now in somewhere in your activity code file do like this.
HttpRequestResponse hrr = new HttpRequestResponse(){
#Override
public void onSuccess(HttpResponse response) {
hideProgressDialog();
handleResponse(response);
}
#Override
public void onException(Exception exception) {
hideProgressDialog();
showErrorDialog(exception.getMessage());
}
}
HttpRequestResponseHandler hrrh = new HttpRequestResponseHandler(ActionItem.LOGIN_REQUEST,hrr);
hrrh.execute();
showProgressDialog();
Hope all this lead to what you want.
Its been a long answer and took quite a effort of mine to figure. :)
why not just using AsyncTask.THREAD_POOL_EXECUTOR(Runnable run);
It wraps a thread pool based executor of #cores + 1 parallelity level.
Then you can simply invoke:
AsyncTask.THREAD_POOL_EXECUTOR(new Runnable(){
public void run(){
doLogin();
});