We have the following method to parse an XML file and display its contents accordingly:
#Background
#AfterInject
void parseXMLAndLoadContent() {
try {
URL url = new URL(URI);
xmlParser.setInput((InputStream) url.getContent());
showProgressDialog();
angeboteXML = xmlParser.parse();
if (angeboteXML != null) { // Breakpoint here
if (angeboteXML.backgroundImage != "") {
loadBitmapFromUrl(angeboteXML.backgroundImage);
}
loadAngebote();
} else
throw new Exception();
} catch (Exception exception) {
showToast();
} finally {
dismissProgressDialog();
}
}
As you can see it is supposed to show the a progress dialog (method annotated with #UiThread), then call the XML parser and handle the result.
Unfortunately, this does only work when I set a breakpoint in the line mentioned above, just after the call of parse(). Somehow, this leads to a certain grace period, that allows the parser to handle the document. If I just let it run without the breakpoint, nothing happens, not even the progress dialogue shows up and angeboteXML is null.
Since I am no Android expert - why is this happening and is there anything I can improve? As far as my understanding goes, this should be executed sequentially, i.e. after the parser is done parsing, everything else is executed. But this is somehow not the case here.
Edit 16/05/13 13:21:
Adding a Thread.sleep(1000) after parse() helps, but it seems more like a workaround than a fix.
This is the trace log of method execution:
05-16 13:19:26.168: I/AngeboteActivity(6051): Entering [void parseXMLAndLoadContent() ]
05-16 13:19:26.278: I/AngeboteXMLParser(6051): Entering [public de.sample.app.helper.AngeboteXML parse() throws org.xmlpull.v1.XmlPullParserException, java.io.IOException]
05-16 13:19:26.318: I/AngeboteXMLParser(6051): Exiting [public de.sample.app.helper.AngeboteXML parse() throws org.xmlpull.v1.XmlPullParserException, java.io.IOException], duration in ms: 35
05-16 13:19:26.318: I/AngeboteActivity(6051): Exiting [void parseXMLAndLoadContent() ], duration in ms: 147
05-16 13:19:26.318: I/AngeboteActivity(6051): Entering [void loadAngebote() ]
loadAngebote() is where a NPE is thrown, since the parser seems to be not yet finished.
Edit 16/05/13 13:29
This is how the parse() method is implemented:
public AngeboteXML parse() throws XmlPullParserException, IOException {
this.xml = new AngeboteXML();
int eventType = this.parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG :
this.readStartTag(this.parser.getName());
break;
case XmlPullParser.END_TAG :
this.readEndTag(this.parser.getName());
break;
case XmlPullParser.TEXT :
this.readText(this.parser.getText());
break;
default :
break;
}
this.parser.next();
eventType = this.parser.getEventType();
}
return xml;
}
Actually, I think this is a design problem. The call to xmlParser.parse() is the task you want to execute in the background. Everything before and after that belongs in another method, which triggers this task.
I don't know how the #Background feature works, but if you would use the http://developer.android.com/reference/android/os/AsyncTask.html, there would be a onProgressUpdate (put showProgressDialog() in here) and a onPostExecute callback (put dismissProgressDialog() in here). Looking at the documentation of android annotations, I would suggest the following:
#AfterViews
void initXMLParsing() {
showProgressDialog();
parseXMLAndLoadContent();
}
#Background
void parseXMLAndLoadContent() {
try {
// ...
} catch (Exception exception) {
showToast();
} finally {
dismissProgressDialog();
}
}
Related
I was working on some validation. There is some mandatory fields and some of them are optional. For mandatory fields, I'm throwing exception, but for optional fields, I've to print warning and have to proceed further in my method. I'm not getting any way to doing warning part. Can someone help on it?
public void method(String param1, String param2){
if(param1 == null){
throw new IllegalArgumentException("mandatory field");
}
//Here for param2, I want to throw eception, but want to proceed further to next line.
//Execute my code here
}
This is not how exceptions work. There are several ways to solve it:
Just don't use exceptions and print your error instead (println() or some textfield, toast or whatever)
Place a boolean marker saying that param2 failed and throw your exception at the end of the method
m_param2 = true
//...
if (param2 == null) {
m_param2 = false
}
// you proceed here
if (!m_param2){
// throw exception
}
Use submethods for the parameter-check which always throw an exception when errors occur and catch the error in your main-method and decide what to do then.
For me case 3 does not make that much sense but that depends on how and when you want to print the message. If you have something in the parent layer (the code that runs your method) that automatically generates the error-message when an exception occurs, I would stick to my second suggestion.
In general I think that missing optional parameters are no real error case so that no exception should be thrown. The method-caller needs to pass the parameter anyhow (though it can be null, of course).
throw is a keyword which finishes the method execution you cant continue by throwing an exception you can use an interface to do what you want
public void method(String param1, String param2,Listener listener){
if(param1 == null){
listener.IllegalArgumentException("mandatory field");
return;
}
listener.IllegalArgumentException("mandatory field");
//Execute my code here
}
interface Listener{
void IllegalArgumentException(String string);
}
You can use
try{
} catch (Exception e){
// you can ignore if you want to
}finally {
//rest of your code here
}
try the below code let me know if any issues.
public void method(String param1, String param2){
if(param1 == null){
throw new IllegalArgumentException("mandatory field");
}
if(param2 == null) {
Log.d("Error", "param2 is null");
}
}
I have a custom error handler that checks RetrofitError it gets passed and rethrows it as custom exceptions
private static ErrorHandler getErrorHandler() {
return new ErrorHandler() {
#Override
public Throwable handleError(RetrofitError cause) {
switch (cause.getKind()) {
case NETWORK: return new NetworkException(cause);
case HTTP: return new ApiException(cause);
default: return cause;
}
}
};
}
If this is my endpoint
#GET(USERS_GET_URL)
User getUsers() throws NetworkException, ApiException;
while executing synchronous request I try...catch and handle each custom exception as I want. When it is done asynchronously using
#GET(USERS_GET_URL)
void getUsers(Callback<User> cb) throws NetworkException, ApiException;
the handled exception gets rethrown as RetrofitError. The following snippet of code is from CallbackRunnable class of Retrofit which executes the request
try {
final ResponseWrapper wrapper = obtainResponse();
callbackExecutor.execute(new Runnable() {
#Override public void run() {
callback.success((T) wrapper.responseBody, wrapper.response);
}
});
} catch (RetrofitError e) {
Throwable cause = errorHandler.handleError(e);
final RetrofitError handled = cause == e ? e : unexpectedError(e.getUrl(), cause);
callbackExecutor.execute(new Runnable() {
#Override public void run() {
callback.failure(handled);
}
});
}
As it can be seen, my custom exceptions are getting rethrown as RetrofitError which makes me loose valuable information. Is there any way I can bypass custom error handling for just the async requests?
In your ErrorHandler you pathing original RetrofitError as cause, so as result in your Callback#failure(RetrofitError error) to get actual information you need to write next code: error.getCause().getCause(). This error will contain response that server send with all the data.
But error handler was created for sync request and after some time square team decided to close this gap this way. For more info you can read: https://gist.github.com/benvium/66bf24e0de80d609dac0
As for me, I don't recommend to use ErrorHander for async way, because I don't find any good solution to handle different types of error. It was much easier to get data right from initial RetrofitError.
i have i problem that i don't know the cause, so when running my application after an asynctask call in POST i change activity and when the new Activity is setting the main content to the screen the app crashes with any log.
The activty chages code is written in onPostExecute method of asynctask and i've tried to do this in another thread calling the runOnUIThread method from activity but isn't working.
the only log that I see:
03-10 12:03:20.312: I/MyHttpClient(3160): HTTPResponse received in [1210ms]
03-10 12:03:20.367: I/my.app.package.ActivationActivity(3160): SendActivation onPostExecute: ActivationResponse [my.app.result.json.with.SUCCESS:result.code]
03-10 12:03:25.398: D/OpenGLRenderer(3160): Flushing caches (mode 0)
EDIT: now i have changed some names of classes and objects but is the code that don't work for me
class MyAsincTask extends AsyncTask<String, Void, String>
{
private Exception exception;
private Gson gson;
protected void onPostExecute(String response) {
hideProgressDialog();
if (exception != null) {
//deleted log code here
} else if (response != null) {
// I manage the json response from the server
try {
// I manage the json response
// determining if the server call was SUCCESS or ERROR
if (resultCode.equals(Constants.RESULT_ERROR)) {
//deleted log code here
}else if (resultCode.equals(Constants.RESULT_SUCCESS)) {
launchRegistration(); // I enter Here and then crashes
}
} catch (Exception e) {
//deleted log code here
}
//deleted log code here
} else {
//deleted log code here
}
}
}
protected void launchRegistration(){
runOnUiThread(new Runnable() {
#Override
public void run() {
Intent mIntent = new Intent(mContext, ActivityToOpen.class);
mIntent.setAction(Constants.ACTION_TO_OPEN_ACTIVITY);
mIntent.putExtra(Constants.SOME_EXTRA, extras);
startActivity(mIntent);
finish();
}
});
}
is inside other activity, and the asynctask class is inner in other activity class. this code for me work on many recent device, with recdent hardware and recent version like 4.4 and 5 and 4.3, but the problem is happening in other devicewith 4.0 and 4.1 with less hardware resource.
`<activity android:name="com.example.Activity"
android:excludeFromRecents="true"
android:icon="#drawable/app_icon"
android:label="#string/wizard.welcome.title"
android:theme="#style/Theme.NoDisplay" /> `
the error that I did, is in the manifest declaration, some activity has the theme "NoDisplay" that don't work in recent version of android, but works in previous versions. And for this I had an issue.
Thank
I have an interesting problem that I've never run into in programming before. I have an onClickListener that does a lot of username and password checks (makes sure the username is proper length, not taken, etc). I'm using MobDB, and I was using a conditional statement that would return a row if the username already existed. The problem is that the Listener skips the DB and goes to the final check that, if everything works, posts a new username and password to my DB. How can I make it wait for a response from the DB before skipping to the last check?
Here is the relevant code:
usernamecheck3 = true;
MobDB.getInstance().execute(APP_KEY, null, rd, null, false, new MobDBResponseListener() {
#Override public void mobDBSuccessResponse() {
usernamecheck3 = false;
Log.e("mobdbSuccess:", "success");
}
#Override public void mobDBResponse(Vector<HashMap<String, Object[]>> row) {
}
#Override public void mobDBResponse(String jsonObj) {
/*Log.e("mobdbSuccess:", "jsonObj");
Log.e("mobdbSuccess:", jsonObj);
JSONObject mainObject;
try {
mainObject = new JSONObject(jsonObj);
// need to parse the json object.
} catch (JSONException e1) {
e1.printStackTrace();
} */
}
#Override public void mobDBFileResponse(String fileName, byte[] fileData) {
//get file name with extension and file byte array
}
#Override public void mobDBErrorResponse(Integer errValue, String errMsg) {
usernamecheck3 = false;
Log.e("doesnt", "work");
}
});
if(usernamecheck3 == false){
Toast.makeText(getApplicationContext(), "Username is taken, please choose another", Toast.LENGTH_SHORT).show();
}
Basically the check always returns true, and then logcat will say mobdbSuccess: success, which should have set the Bool to false.
Thanks.
MobDBResponseListener is executing on a different thread. What happens here is that the processing is split, while a thread is doing the query, the main thread on which you added the listener, skips right ahead to the validation. Your best bet is to place the validation inside the MobDBResponseListener, on the mobDBResponse method.
Try to debug your code and calls, the Listener may be using an async task. If so, you may do anything you please from the response method, as it will be executing in the main thread again. Otherwise, you should look at solutions that handle threaded execution like Handlers
For example, the flash platform provides the flash.debugger.enterDebugger() API call that does the job:
if (some_cond())
{
...
}
else
{
enterDebugger();
}
In that case, if some_cond() evaluates to false and we're in a debug session (it does nothing if we're in a normal session), then the execution will be halted at the line where enterDebugger is invoked and control given to the debugger, as if a breakpoint was set at that line.
I've looked at the android.os package but found nothing like it. Throwing an exception does the job of giving the control to the debugger, but then the code execution cannot be resumed at the spot where the exception was thrown.
Java debugging supports suspending on exceptions. You could write:
void enterDebugger() {
try {
throw new DebugException();
}
catch (DebugException e) { //no-op
}
}
And setup your IDE to suspend on caught exceptions of type DebugException.
if (someCond()) { .... }
else {
android.os.Debug.waitForDebugger();
}
See android.os.Debug.