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.
Related
I have a code in the UI Thread that call to another Thread. This new Thread wait for a server response to execute an database update.
When the new Thread send the post content the server send the answer fine, but the update process to the database stops when the screen (activity) load the next item to calculate and send it to the server again.
My code looks like this
public class MyActivity extends Activity {
onCreate(){ ... }
public void pushButton(View v) {
...
//Call the Thread
MyOwnThread t = new MyOwnThread(arg1, arg2);
t.start();
showTheNextItemToProcess();
}
}
MyOwnThread looks like this
public class MyOwnThread extends Thread {
public MyOwnThread(String arg1, Object arg2) { ... }
public void run() {
if(arg1.equals("ok_status") {
//The code on this part stops wen the UI Thread show the next item to process
for( ... ) {
// ...
}
}
}
}
I tried with send a clone of the variables inside the new Thread constructor, but the result it's the same. I don´t know why the UI Thread interrupts the another Thread. With the ListenableFuture (Google Guava) it´s the same.
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
ListenableFuture<String> futureTask = service.submit(new Callable<String>(){
public String call() {
//Send the post to the server
}
});
Futures.addCallback(futureTask, new FutureCallback<String>() {
#Override
public void onSuccess(String arg0) {
//when get the answer from the server, executes the db update
//the UI thread stop this too
}
});
I don't see errors in the LogCat. Your help is welcome, sorry for my bad english.
Thanks!
EDIT
I changed my code to use full threads (extends Thread), with WIFI connection the app sends the package to the server and the server returns the response, the app takes the value sended from the server and trigger the db update, it's fine!. But with the movil data (local operator), the app calls and runs the Thread but the thread simply not continue running. I had set the priority to MAX and it's the same. Anyone know why????
Thanks!
I have a service that constantly polls a webservice for some options. These options basically restart a LocationManager. This restart is done using a custom event which gets fired from a method used inside a thread.
Here is my custom event
public class OptionsChangedEvent extends EventObject {
public OptionsChangedEvent(Object o){
super(o);
}
}
and the custom listener
public interface OptionsChangedListener extends EventListener {
public void optionsChanged(OptionsChangedEvent evt);
}
the thread that runs in the service and polls for new options is the following
private Thread optionsThread = new Thread() {
public void run() {
//Looper.prepare();
while(true) {
String opts = getOptsFromServer();
if(!opts.equals(currentOpts)) updateOpts(opts); //the prob is here
//Looper.loop();
Thread.sleep(10 * 1000) // sleep 10sec
}
}
}
Finally here is how I implement the listener inside my tracker.
locOpts.addOptionsChangedListener(new OptionsChangedListener() {
#Override
public void optionsChanged(OptionsChangedEvent event) {
Log.d("LOCATION_OPTIONS_CHANGED", "SUCCESS");
mLocationManager.removeUpdates(mLocationListener);
mLocationManager.requestLocationUpdates(
provider,
update,
0, mLocationListener
);
}
});
I had the following error which basically says that I need to use Looper.loop and Looper.prepare inside my thread.
12-03 11:31:39.544 26751-26843/com.test.location E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-10370
Process: com.test.location, PID: 26751
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.location.LocationManager$ListenerTransport$1.<init>(LocationManager.java:221)
at android.location.LocationManager$ListenerTransport.<init>(LocationManager.java:221)
at android.location.LocationManager.wrapListener(LocationManager.java:844)
at android.location.LocationManager.requestLocationUpdates(LocationManager.java:857)
at android.location.LocationManager.requestLocationUpdates(LocationManager.java:454)
at com.test.location.trackers.LocationTracker$2.optionsChanged(LocationTracker.java:93)
at com.test.location.options.LocationTrackerOptions.notifyListeners(LocationTrackerOptions.java:22)
at com.test.location.options.LocationTrackerOptions.fromJSON(LocationTrackerOptions.java:34)
at com.test.location.MainService$5.run(MainService.java:219)
If I uncomment the Looper parts the thread works only once and I cant figure out why this happens.
update
After some investigation I found that code that needs the message queue and creates this problem. Does anyone needed to do something like this? I would like to not change my design here if it possible.
private synchronized void notifyListeners(Object obj) {
for (OptionsChangedListener listener : listeners) {
listener.optionsChanged(new OptionsChangedEvent(obj));
}
}
Do you try to update the UI in your callback method updateOpts ?
Looper prepare & loop using in other way, in case when you want to send tasks from UI thread to the backround thread, so you send message to the thread, and inside the thread process that message in handlemessage event of Handler.
try to avoid UI calls directly from your thread, maybe also try using runOnUIThread(...)
or AsyncTasks onPost to make the proper callback to the UI thread.
The solution was actually very simple. I was missing the callback function.
locOpts.addOptionsChangedListener(new OptionsChangedListener() {
#Override
public void optionsChanged(OptionsChangedEvent event) {
Log.d("LOCATION_OPTIONS_CHANGED", "SUCCESS");
mLocationManager.removeUpdates(mLocationListener);
mLocationManager.requestLocationUpdates(
provider,
update,
0, mLocationListener,
Looper.getMainLooper() // this was the problem
);
}
});
I have a MainActivity Class and a Class that extends
public void run()
{
while(true)
{
this.person.movePerson();
checkWin();
checkHit();
this.gameview.postInvalidate();
try
{
sleep(4);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
This is my Thread. In The function 'CheckWin' the game need to check if the user won or not and then show a dialog.
But i can't show a dialog because of a handler problem.
so i tried to add a handler to the tread,
the problem that i always getting a syntax problems -- i am new to developing.
I passed a handler from the MainActivity, and tried to do this:
hand.post(new Runnable{
#Override
public void run()
{
while(true)
{
this.person.movePerson();
checkWin();
checkHit();
this.gameview.postInvalidate();
try
{
sleep(4);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}});
And everything that i get is only a syntax errors.
This is my AlertDialog Code:
AlertDialog.Builder alert = new AlertDialog.Builder(gameview.getContext());
alert.setTitle("Game Over");
alert.setMessage("Your Score is: " + result.score);
alert.setNeutralButton("Again!!", null);
alert.create();
alert.show();
I don't know what syntax error you get, but here is a little explanation on the working with threads in Android. First of all, if you are using plain Thread I suggest you to switch to HandlerThread. It's Android-specific Thread class built with Looper. Secondly, when you create a new Handler it will be attached to the thread from which it was created. If you are going to update UI, Handler which is responsible for posting UI updates to the MessageQueue should be created from UI thread. Alternatively you can pass a Thread-specific Looper to the Handler's constructor.
But I suppose you get syntax error on using this since it's pointing to a wrong object. If person and gameview are the fields of MainActivity class, for example, you can try to reference them by calling MainActivity.this.person...
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();
});
I am quite new to Android and Java. Before I was working with C++ where the events where dispatched with messages. Now I would like to create the same user experience for Android platform and I would appreciate any of your suggestions or comments on what is the best way to bind events to user controls.
Here is an example from C++:
ON_MESSAGE(WM_RECORD_START, &CMainFrame::OnRecordStart)//Method OnRecordStarts() executes on WM_RECORD_START_MESSAGE
...
LRESULT CMainFrame::OnRecordStart(WPARAM wParam, LPARAM lParam)
{
m_pNetworkCtrl->SetGeoLocationInfo();
...
}
...
void CMainFrame::RecordStart()
{
PostMessage(WM_RECORD_START);
}
In the case above the method RecordStart() is bound to a Button (it is executed when a Button is pressed) and posts the message WM_RECORD_START. When the message WM_RECORD_START is received, the method OnRecordStart() is executed.
As mentioned before I would like to create a responsive user interface and am not sure if it would be good enough if the method OnRecordStart() is called directly from RecordStart():
void RecordStart()
{
OnRecordStart();
}
I would really appreciate any of your suggestions.
You can emulator the MFC style behavior in Android by using a Handler to post a Runnable into the message queue.
Here is a brief example
class MyClass
{
Handler m_myHandler;
Runnable m_myRunnable;
MyClass()
{
m_myHandler = new Handler();
m_myRunnable = new RUnnable()
{
public void run()
{
// do your stuff here
}
};
}
public void onclickListener(...)
{
// push the runnable into the message queue
m_myHandler.post(m_myRUnnable);
}
}
You have 2 questions here.
How to bind controls. I use
anonymous inner classes everywhere. It is a bit verbose to type in but auto completion makes it a snap.
how to make the UI responsive.
The key is not to do anything time
consuming in the UI thread. If it
takes more than .1s, do the work in
a worker thread and notify the UI to
update when the task is done. The
other thing is to make sure you
don't generate a lot of garbage
since the android GC is pretty primitive right now.
For Buttons I usually extend Button class and override onTouchEvent()
public boolean onTouchEvent (MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
setPressed(true);
}
return super.onTouchEvent(event);
}