Pass an Exception as a Parcel - android

I am trying to pass an exception to an activity meant to dump the relevant information to the screen.
Currently I pass it through a bundle:
try {
this.listPackageActivities();
} catch (Exception e) {
Intent intent = new Intent().setClass(this, ExceptionActivity.class).putExtra("Exception", e);
startActivity(intent);
}
But when it gets there:
if (!(this.bundle.getParcelable("Exception") != null))
throw new IndexOutOfBoundsException("Index \"Exception\" does not exist in the parcel." + "/n"
+ "Keys: " + this.bundle.keySet().toString());
This sweet exception is thrown but when I look at the keySet and the bundle details it tells me that there is one parcelable object with a key named "Exception".
I understand that this has something to do with types but I do not understand what I am doing wrong. I just want to dump information about an exception, any exception to the screen. Is there a way to do that without having to condense all the information into a string every time?

I stumbled on this question when I was searching for a method to pass exceptions from a service to an activity. However, I found a better method, you can use the putSerializable() method of the Bundle class.
To add:
Throwable exception = new RuntimeException("Exception");
Bundle extras = new Bundle();
extras.putSerializable("exception", (Serializable) exception);
Intent intent = new Intent();
intent.putExtras(extras);
To retrieve:
Bundle extras = intent.getExtras();
Throwable exception = (Throwable) extras.getSerializable("exception");
String message = exception.getMessage();

The class Exception doesn't implement the Parcelable interface. Unless android is breaking some fundamental Java constructs of which I'm unaware, this means you can't put an Exception as a Parcel into a Bundle.
If you want to "pass" the execption to a new Activity, just bundle up the aspects of it that you're going to need in your new Activity. For example, let's say you just want to pass along the exception message and the stacktrace. You'd so something like this:
Intent intent = new Intent().setClass(this,ExceptionActivity.class)
intent.putExtra("exception message", e.getMessage());
intent.putExtra("exception stacktrace", getStackTraceArray(e));
startActivity(intent);
where getStackTraceArray looks like this:
private static String[] getStackTraceArray(Exception e){
StackTraceElement[] stackTraceElements = e.getStackTrace();
String[] stackTracelines = new String[stackTraceElements.length];
int i =0;
for(StackTraceElement se : stackTraceElements){
stackTraceLines[i++] = se.toString();
}
return stackTraceLines;
}

Related

Passing a string "dynamically" as a class name in Android Studio

Let's say you have a string:
String string_name; //assign whatever value
And you have an intent:
Intent i = new Intent(getApplicationContext(), string_name.class);
This obviously doesn't work. AS doesn't recognise string_name as a class (although IT EXISTS as an activity in the main folder). The forname method didn't work for me either (unless I did it wrong).
I have 10 activities/classes listed name1, name2, name3, etc... And after I'm done with each activity, the program goes to a "Transition" activity page, which then redirects to the next activity at run time. So after the user is done with name1 activity, the program redirects him to the "Transition" page. And after that I'm trying to send them to name2 activity. And so on.
What I'm trying to do is assign the name of name1, name2, activities to a string (string_name in this case) in the "Transition" activity/class. After a couple of lines of code, I managed to retrieve the name of name1, change it to name2, and store it in a string. But Android Studio does not accept a "dynamic" string as a class value.
Thoughts?
Instead of this:
Intent i = new Intent(getApplicationContext(), string_name.class);
You can do this:
Intent i = new Intent();
// Set the component using a String
i.setClassName(getApplicationContext(), string_name);
NOTE: Make sure that all of your activities are declared in your manifest.
Updated:
You can use Class.forName(String string_name) to get class from a String. But in String you have to give complete package name of that class.
String string_name = "com.your_package.TestActivity";
try {
Class<?> classByName = Class.forName(string_name);
Intent i = new Intent(this, classByName.class);
} catch (ClassNotFoundException e) {
Log.e("YourParentClassName", "System can't find class with given name: " + string_name);
}
It looks like this snippet should help you:
String string_name = "com.package.ActivityToStart";
Intent i = null;
try {
i = new Intent(this, (Class<?>) Class.forName(string_name).newInstance());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
Log.e("YourParentClassName", "System can't find class with given name: " + string_name, e);
}
if (i != null) {
// do your work
}
For a string to class name conversion you need to properly give your package name else it will always throw exception
String s = "yourclassname";
try {
context.startActivity(new Intent(context, Class.forName("your.package.name." + s)));
} catch (ClassNotFoundException e) {
Toast.makeText(context, s + " does not exist yet", Toast.LENGTH_SHORT).show();
}
Class.forName() used for creating object of class Class. Below is the syntax :
Class c = Class.forName(String className)
The above statement creates the Class object for the class passed as a String argument(className). Note that the parameter className must be fully qualified name of the desired class for which Class object is to be created. The methods in any class in java which returns the same class object are also known as factory methods. The class name for which Class object is to be created is determined at run-time.

Facebook error : application ID is invalid

Hey i get this error using the SDK though the app ID is correct.
Now when i try to authorize the app, it works fine and authorizes it, but when i try and make requests, facebook returns this error. My app is initlized properly and is not in sandbox mode.
I found No info about this problem, does someone know what can cause this?
I'm trying to upload photo using The following code :
byte[] data = null;
Bitmap bi = BitmapFactory.decodeFile(photoToPost);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bi.compress(Bitmap.CompressFormat.JPEG, 100, baos);
data = baos.toByteArray();
Bundle params = new Bundle();
params.putString("method", "photos.upload");
params.putByteArray("picture", data);
AsyncFacebookRunner mAsyncRunner = new AsyncFacebookRunner(facebook);
mAsyncRunner.request(null, params, "POST", new SampleUploadListener(), null);
SampleUploadListener :
public class SampleUploadListener extends BaseRequestListener {
public void onComplete(final String response, final Object state) {
try {
// process the response here: (executed in background thread)
Log.d("Facebook-Example", "Response: " + response.toString());
JSONObject json = Util.parseJson(response);
final String src = json.getString("src");
// then post the processed result back to the UI thread
// if we do not do this, an runtime exception will be generated
// e.g. "CalledFromWrongThreadException: Only the original
// thread that created a view hierarchy can touch its views."
} catch (JSONException e) {
Log.w("Facebook-Example", "JSON Error in response");
} catch (FacebookError e) {
Log.w("Facebook-Example", "Facebook Error: " + e.getMessage());
}
}
#Override
public void onFacebookError(FacebookError e, Object state) {
// TODO Auto-generated method stub
}
}
I Solved the problem.
THe problem was i created 2 instances of the Facebook object, one as global and one inside the method preforming the code mentioned above, So what happened is i never authorized the Object i tried doing the request is.
For some reason the error dosen't say that but in case this happens to you, make sure you have initialised the right Object and it has a valid session

Intent extras only work on some devices

In my app I send some intent extras from one activity to another. But some users report back that these data are always zero - even though I can see the values are alright in the sending activity.
Here's the code of the sending activity:
Intent intent = new Intent();
intent.setClass(waypointListView.this, addWaypointActivity.class);
intent.putExtra("latitude", String.format("%9.6f", globLatitude));
intent.putExtra("longitude", String.format("%9.6f", globLongitude));
startActivityForResult(intent, ACTIVITY_ADD_WAYPOINT);
And this is how it's read in the new activity:
Intent myIntent = getIntent();
String latitudeStr = myIntent.getExtras().getString("latitude");
try{
globLatitude = Float.parseFloat(latitudeStr);
} catch(NumberFormatException nfe) {
globLatitude=0f;
}
String longitudeStr = myIntent.getExtras().getString("longitude");
try{
globLongitude = Float.parseFloat(longitudeStr);
} catch(NumberFormatException nfe) {
globLongitude=0f;
}
On both my devices it works fine, but I have 3 cases of customers complaining that it doesn't work (documented in video recordings).
Any suggestions?
I tried to change the code to use getFloatExtra() instead of getString and parse it to a float, and it solved the problem. I see this is a lot more efficient, but I still don't understand why the original solution worked on some devices but not on others.
Case closed!

Android Facebook Open Graph?

I am curious if I can get some help with Open Graph since I can't seem to make any sense out of the Facebook API that I have read.
Right now I have setup my Open Graph Application on Facebook. It has been approved. I am trying to submit my "objects" via the bundle params but I am curious how I setup a bundle param object like the following. Where myObject has multiple values associated with it.
Bundle params = new Bundle();
param.putString("myObject", ""); // My object has multiple values
I guess I really need to figure out how you submit something in the Bundle that has multiple properties associated with it. If anyone has any insight on this please help me out.
At first I had tried something like this.
Bundle myObject = new Bundle();
myObject("property1", "property1Value");
myObject("property2", "property2Value");
myObject("property3", "property3Value");
Bundle params = new Bundle();
params.putString("myObject", myObject);
But in hindsight I figured out why this wouldn't work.
Edit 1
Maybe this will shed some light. Keep in mind this is an Open Graph action which is not a part of the Graph API.
//Build recipe
JSONObject recipe = new JSONObject();
recipe.put("type", "myappns:recipe");
recipe.put("recipe_name", "Thai Island");
recipe.put("cook_time", "1hr. 30min.");
//Build cookbook
JSONObject cookbookParams = new JSONObject();
cookbookParams.put("type", "myappns:book");
cookbookParams.put("title", "Hot & Spicy");
cookbookParams.put("description", "This book consists of hot & spicy foods");
cookbookParams.put("recipes", new JSONArray().put(recipe));
Bundle params = new Bundle();
params.putString("cookbook", cookbookParams.toString());
AsyncFacebookRunner request = new AsyncFacebookRunner(facebook);
request.request("me/myappns:used", params, "POST", new addToTimelineListener(), null);
Here is a question though as I have been digging more into the Open Graph system. I believe I need to actually have a website setup somewhere, is this correct? I was lead to believe through the introductory documentation of Open Graph that I could create and use my Facebook application on Android without the need of any website. That is use the Open Graph system, I know I can use the application to post feeds and what not which I have done successfully.
Thanks again!
Edit 2
Dont even worry about replying I understand what my problem was now...I have to have a website somewhere hosting a Facebook application for the posts to link back too. Makes perfect sense, I haven't seen where the documentation was very direct about this...oh well now I know.
I use this code to publish on wall for multiple object properties.
private void publishPhoto(String imageURL) {
Log.d("FACEBOOK", "Post to Facebook!");
try {
JSONObject attachment = new JSONObject();
attachment.put("message",text);
attachment.put("name", "MyGreatAndroidAppTest");
attachment.put("href", "http://stackoverflow.com/users/909317/sunny");
attachment.put("description","Test Test TEst");
JSONObject media = new JSONObject();
media.put("type", "image");
media.put("src", imageURL);
media.put("href",imageURL);
attachment.put("media", new JSONArray().put(media));
JSONObject properties = new JSONObject();
JSONObject prop1 = new JSONObject();
prop1.put("text", "Text or captionText to Post");
prop1.put("href", imageURL);
properties.put(text, prop1);
// u can make any number of prop object and put on "properties" for ex: //prop2,prop3
attachment.put("properties", properties);
Log.d("FACEBOOK", attachment.toString());
Bundle params = new Bundle();
params.putString("attachment", attachment.toString());
facebook.dialog(MyProjectActivity.this, "stream.publish", params, new DialogListener() {
#Override
public void onFacebookError(FacebookError e) {
// TODO Auto-generated method stub
}
#Override
public void onError(DialogError e) {
// TODO Auto-generated method stub
}
#Override
public void onComplete(Bundle values) {
final String postId = values.getString("post_id");
if (postId != null) {
Log.d("FACEBOOK", "Dialog Success! post_id=" + postId);
Toast.makeText(MyProjectActivity.this, "Successfully shared on Facebook!", Toast.LENGTH_LONG).show();
} else {
Log.d("FACEBOOK", "No wall post made");
}
}
#Override
public void onCancel() {
// TODO Auto-generated method stub
}
});
} catch (JSONException e) {
Log.e("FACEBOOK", e.getLocalizedMessage(), e);
}
}
To see a complete example look at the wishlist example.
A complete example for Android is included. The package includes the files to be uploaded on the server and a readme file that explain how to set up all the stuff on the open graph panel.

How to perform two operations on one activity in android

I want to implement a search in my Android application.
In this page, first I am displaying a user list and then performing a search on the user list. Both are in the same activity. In the following manner, I am getting intent and some values from the previous page. When I display the user list, all the values are coming. But while performing search, spaceId gets lost and becomes null. I need this value.
Intent intent = this.getIntent();
Bundle receiveBundle = intent.getExtras();
spaceId = receiveBundle.getString("spaceId");
What should I do to get this value?
Edit:
String spaceId;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = this.getIntent();
Bundle receiveBundle = intent.getExtras();
spaceId = receiveBundle.getString("spaceId");
String URLTicketList = String.format(getString(R.string.URLTicketList, spaceId));
RestClient client = new RestClient(URLTicketList,
this.getApplicationContext());
try {
client.Execute(RequestMethod.GET);
} catch (Exception e) {
e.printStackTrace();
}
TabSettings ts = new TabSettings();
ts.setSelTab(0);
String response = client.getResponse();
tickets = parseTicketList(response);
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
searchResult=getMatchingStrings(tickets,query);
this.ticket_adapter = new TicketAdapter(this,
R.layout.ticket_details_row,searchResult);
setListAdapter(this.ticket_adapter);
}
else {
this.ticket_adapter = new TicketAdapter(this,
R.layout.ticket_details_row, tickets);
setListAdapter(this.ticket_adapter);
}
}
getMatchingstrings()
ArrayList<Ticket> getMatchingStrings(ArrayList<Ticket> list, String regex1) {
ArrayList <Ticket> listClone = new ArrayList<Ticket>();
for (Ticket string : list) {
if(string.getAssignedTo().equals(regex1)){
listClone.add(string);
}
}
return listClone;
}
Try it
getIntent().getExtras().getString("spaceId");
You said your activity is recreating. So you are not getting the value of spaceID after recreation. Then do this thing as below.
public String PREFS_NAME = "Shared_Pref";
Bundle receiveBundle = this.getIntent().getExtras();
String spaceId_value = receiveBundle.getString("spaceId");
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
if(spaceId_value == null) {
spaceId_value = settings.getString("spaceId", "");
}
else {
SharedPreferences.Editor editor = settings.edit();
editor.putString("spaceId", spaceId_value);
}
I hope this will help you out.
edit :
I am editing your code.
Which part i have edited, i have mentioned that part as edited. Carefully see what i have changed and do that thing in your code. Then let me know.
String spaceId;
public String PREFS_NAME = "Shared_Pref"; //edited part
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//editing start
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
Bundle receiveBundle = this.getIntent().getExtras();
if(receiveBundle != null) {
spaceId = receiveBundle.getString("spaceId");
if(spaceId == null) {
spaceId = settings.getString("spaceId", "");
}
else {
SharedPreferences.Editor editor = settings.edit();
editor.putString("spaceId", spaceId);
}
}
//editing end
String URLTicketList = String.format(getString(R.string.URLTicketList, spaceId));
RestClient client = new RestClient(URLTicketList,
this.getApplicationContext());
try {
client.Execute(RequestMethod.GET);
} catch (Exception e) {
e.printStackTrace();
}
TabSettings ts = new TabSettings();
ts.setSelTab(0);
String response = client.getResponse();
tickets = parseTicketList(response);
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
searchResult=getMatchingStrings(tickets,query);
this.ticket_adapter = new TicketAdapter(this,
R.layout.ticket_details_row,searchResult);
setListAdapter(this.ticket_adapter);
}
else {
this.ticket_adapter = new TicketAdapter(this,
R.layout.ticket_details_row, tickets);
setListAdapter(this.ticket_adapter);
}
}
When you are firstly loading your list in activity,you have to save that spaceId in some SharedPreference variable for further use.And while reloading activity with search result,you can find that Id from SharedPreference variable previously saved.
Be sure,you overwrite that variable as and when you firstly load list in your activity to meet your needs cleanly.
Also you have to get spaceId from intent like:
int spaceId=0;
if(getIntent().hasExtra())
spaceId=getIntent().getStringExtra("spaceId");
Doing this wont give you excpetion when you reload the same activity with no extras to your intent.
Or,you will have to pass this spaceId along with intent you are using to reload the same activity for showing search result.
Hope,you get the point!
If u relaunching the same activity while performing search,u will lost that value. If u r doing so,while relaunching also pass that spaceId to the relaunching activity also using intent.putextra() method
as in your question and comments i guess you are getting problem if your activity is recreated
add following code in manifest file under your activity tag
android:configChanges="keyboardHidden|orientation"
your activity will not be created again
and then use the value of spaceID where you need

Categories

Resources