Can't fetch objects using QBCusomObjects off of main thread in android - android

So in my app, I'm trying to fetch some custom objects I've made, and I'm getting this error:
Caused by: 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 com.quickblox.core.server.HttpRequestRunnable$1.<init>(HttpRequestRunnable.java:40)
at com.quickblox.core.server.HttpRequestRunnable.<init>(HttpRequestRunnable.java:40)
at com.quickblox.core.server.ThreadPoolIntentService.execute(ThreadPoolIntentService.java:23)
at com.quickblox.core.server.HttpRequestTask.execute(HttpRequestTask.java:29)
at com.quickblox.core.rest.RestRequest.asyncRequestWithCallback(RestRequest.java:110)
at com.quickblox.core.query.Query.performInBgAsyncWithDelegate(Query.java:115)
at com.quickblox.core.query.Query.performAsyncWithCallback(Query.java:218)
at com.quickblox.customobjects.QBCustomObjects.getObjects(QBCustomObjects.java:532)
Originially, I was calling the getObjects method from a separate thread I spawned to do the network communication, both because doing it on the UI thread seemed like a bad idea, and because when I tried to do it on the UI thread I got a NetworkCommunicationOnMainThread exception.
Since the separate thread didn't work, I put the request in an AsyncTask to see if that would help, and it didn't change anything.
The code for the request is below
final QBRequestGetBuilder requestBuilder = new QBRequestGetBuilder();
try {
Log.i(classTag, "Attempting to get UserID");
requestBuilder.eq("User_ID", ""+ QBAuth.getSession().getUserId());
} catch (QBResponseException e) {
Log.e(classTag, "Failed to get UserID for current user");
e.printStackTrace();
return null;
}
QBCustomObjects.getObjects("Listing", requestBuilder, new QBEntityCallbackImpl<ArrayList<QBCustomObject>>() { ...}
Any help would be greatly appreciated. Thanks!

This request works in a separate thread already
QBCustomObjects.getObjects("Listing", requestBuilder, new QBEntityCallbackImpl<ArrayList<QBCustomObject>>() { ...}
so you don't need to wrap it
there is also a possibility to use 'sync' requests

Related

Network connection on main thread - alternative in this case?

I need to get a color in the server and set it as a theme
setTheme(colorId);
it needs to be set inside onCreate() and at the beginning to work.
I'm doing this:
protected void onCreate(Bundle savedInstanceState) {
getColor();
...
}
public void getColor() {
StrictMode.ThreadPolicy tp = StrictMode.ThreadPolicy.LAX; //force network on main thread
StrictMode.setThreadPolicy(tp);
OkHttpClient client = new OkHttpClient();
okhttp3.Request request = new okhttp3.Request.Builder()
.url("http://myip/color.php")
.build();
try {
okhttp3.Response response = client.newCall(request).execute();
String color = response.body().string();
setTheme(color);
} catch (IOException e) {
e.printStackTrace();
}
}
}
So, I'm forcing a network connection on main thread because if I add doInBackground(), on response... it will run after my onCreate() and the color will not be set.
My question here is:
1) Is it the only way?
2) Can I do things without force network on main thread?
3) I'd like an example, if possible, not just: "yes, it is possible" or "do XYZ" because I'm new to Android and without examples it doesn't help much.
You shouldn't make any network requests on the main thread.
Instead, you should show the user a progress bar whilst it fetches the data on a background thread.
BUT: Since you have to set the theme in the onCreate() it means you can't show the user any progress because the views won't be inflated at that point. A better solution would be to get the color from the server on a previous activity and pass it in as and intent parameter.
It's always a bad idea to force the network to the main thread
Replace the UI blocking call
client.newCall(request).execute();
With an asynchronous call
client.newCall(request).enqueue(new Callback() {
Check the documentation on how that all works
if I add doInBackground, on response... it will run after my onCreate and the color will not be set
In an Asynctask? Then you're doing something wrong. Okhttp doesn't need an Asynctask

How to throw an exception if a method is executed from main thread

I have a class with severeal methods which extract data from a sqlite database. I would like to "force" the users of this class to call these methods in a thread or an asynctask.
How can i prevent a method to run on the main thread ?
I would like to achieve something similar to the android.os.NetworkOnMainThreadException thrown when you try to do some networking on the ui thread.
Do something like:
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new DontDoThisOnUiThreadPleaseException();
}
Source: Looper.getMainLooper() and Looper.myLooper().
From Google Volley library :
private void throwIfOnMainThread() {
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new IllegalStateException("Must not be invoked from the main thread.");
}
}
if (Looper.getMainLooper().equals(Looper.myLooper())) {
throw new MyException("Don't do it on the UI thread");
}
Try this it should work. Of course create your own exception or use existing one.
see Looper documentation to check if you are running in the ui thread or not

Where to "quit" with looper?

I have a problem with a looper. I call looper.prepare(), and after doing something it all works fine. But if I rotate the device I get an exception on the prepare.
07-12 16:40:09.760: E/activity(15809): java.lang.RuntimeException: Only one Looper may be created per thread
I'm trying to quit the looper, but it doesn't do anything.
Here is my AsyncTask:
#Override
protected String doInBackground(String... args) {
try{Looper.prepare(); //here start the exception
try {
URL url = new URL(link);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
utente.measure(0, 0);
bmImg = decodeSampledBitmapFromResource(is,(int) utente.getMeasuredWidth(), utente.getMeasuredHeight(), link);
if(bmImg!=null){
try{
getCroppedBitmap();
}catch(Exception e){
System.out.println(e);
}
}
}
catch (IOException e)
{
Log.e("lele", "errore qui");
e.printStackTrace();
}
Looper.myLooper().quit(); //do nothings
}catch(Exception e){
Log.e("canta tu", " "+e);
}
Looper.myLooper().quit(); //do nothings
return null;
}
#Override
protected void onPostExecute(String args) {
//Looper.myLooper().quit(); //generathed an error, main thread can't stop looper
if(bmImg!=null){
try{
utente.setImageBitmap(bmImg);
ellisse.setVisibility(View.VISIBLE);
}catch(Exception e){
Log.e("lele",""+e);
Log.e("lele","errore probabile out of bound");
}
}
else {
Toast.makeText(getApplicationContext(), "Modifica la foto da \"profilo\"", Toast.LENGTH_LONG).show();
}
Ideas?
There are two cases to consider:
(1) looper threads you want to live the entire life of the app, and do not hold strong reference to a view (even not implicitly)
Quoting Google engineer, Christopher Tate - you can just leave the looper there until your app is destroyed, and it will go down with it. You don't need to worry about it.
"Speaking very generally, never quit() your looper threads. That method exists mostly for historical and testing reasons. In Real Lifeā„¢, I recommend that you continue to reuse the same looper thread(s) for the life of the process rather than creating/quitting them."
I use such a looper thread as a multi purpose HandlerThread, and send Runnables to it whenever I want something to run outside the main thread (UI).
(2) looper threads that have reference to a view
This one falls out of the recommendation of Christopher Tate, because it will cause memory leak, for example if you rotate the screen.
(You better make the handler thread static and use weak reference - and you'll be back with option #1)
To kill it you must quit the loop. To do that, you need to run the quit command on the context of that thread.
So create a message with some whatever int as your msg.what, and in your handleMessage wait for this int, and when it arrives - call:
Looper myLooper = Looper.myLooper();
if (myLooper!=null) {
myLooper.quit();
}
And don't forget to null all reference to views and activities.
Send this kill message to the handler from your activity onDestroy()
Looper.prepare() associates a Looper-instance with the thread that it is called on, but Looper.quit() does not remove this association (it merely stops the message dispatch mechanism). So, when you get a second call to Looper.prepare a RuntimeException is thrown.
The general recommendation is to not associate Looper-instances with AsyncTask-threads. The Looper is intended for passing messages between threads, but this is already handled internally in the AsyncTask, so that data can be sent between onPreExecute (UI thread) -> doInBackground (Worker thread) -> onPostExecute (UI thread).

Synchronous HttpPost on a separate thread

Im currently posting some data to a php webservice using a class that extends AsyncTask.
Now i need to make a synchronous call, because i want to show the default exception popup that my app has crashed once the data is sent (previousHandler.uncaughtException(t, e)).
Can i just disable the async functionality on the AsyncTask, or do you have any other suggestions
Here is my current code, thanks in advance:
public void uncaughtException(Thread t, Throwable e) {
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
String stacktrace = result.toString();
printWriter.close();
String deviceUuid = Utilities.DeviceUuid(ctx, cr);
String bluetoothName = Utilities.LocalBluetoothName();
AsyncTasks.ErrorLogTask logTask = new AsyncTasks.ErrorLogTask(e, bluetoothName, deviceUuid, stacktrace);
logTask.execute();
//task wont be complete before this code below runs since its async.
previousHandler.uncaughtException(t, e);
}
I think you still need to catch the exception. I would keep the call in your AsyncTask, but catch the exception. Either use a flag as the return value from doInBackground or create a variable local to the AsyncTask to use as a flag, and in your onPostExecute check for the flag and show a dialog if necessary.
In general you don't want to make a server call on the main UI thread because of the risk of ANRs. See this article on them:
http://developer.android.com/guide/practices/responsiveness.html
Put your default exception popup into onPostExecute() method of the ErrorLogTask. That block executes in main thread when your task is finished.

How to deserialize Activity object in a background thread? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I have a problem with using Java Serialization mechanism in Android. It works well when invoked from the UI thread, but when I try to use it from some background thread I get:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Because of project nature I cannot deserialize everything in UI thread (also it should be possible to do it in background, so the UI will not stop responding).
BTW. Same thing happens when I try to deserialize something in background using SimpleXML.
So now we do deserialization (both XML and Java serialization) from UI thread which cannot be used everywhere.
Can anyone shed some light on this issue?
EDIT:
I'm using the following code to deserialize an object, it works well when called from UI thread.
public Object getObject(String key) throws InvalidClassException {
Object result;
try {
FileInputStream fileIn = context.openFileInput(getPath(key));
ObjectInputStream in = new ObjectInputStream(fileIn);
result = in.readObject();
in.close();
fileIn.close();
} catch (InvalidClassException e) {
throw new InvalidClassException(e.getMessage());
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return result;
}
EDIT 2
As mentioned in EJP comment below, I'm deserializing an Activity object. So I'm changing my questuion to: How to deserialize Activity object in a background thread?
Not deserializing this object is an option that I'd rather avoid, because of performance issues (XML deserializes in about 4s while binary deserialization is less then 0.5s). I know that it would be possible to redesign our application, but due to project constraints, and it's extreme and unnecessary complexity, that's not really an option. Every bigger change is extremely painful.
So when issue is little clearer - does anyone have some ideas?
Thanks for any suggestions.
Try and call Loooper.Prepare(); before your code and
Looper.Loop(); after, workd for me.
Something like :
Looper.Prepare();
//your code
Looper.Loop();
you cannot do ui operations in any other thread
all ui operations should be on mainthread
you can use this
runOnUiThread(new Runnable() {
#Override
public void run() {
code here
}
});

Categories

Resources