It seems that my implementation of toString() method in an Activity is never called no matter what I do. I always get result from java.lang.Object (like Ljava.lang.Object;#4059d6a8) instead of "I was called!". I've read a bunch of articles and scanned through a lot of code and I can't figure out what I'm doing wrong. Could someone please explain to me how do I override the method? This is my code:
public class OverrideTestActivity extends Activity {
private int number = 27;
private String[] items = { "MyFirstItem", "MySecondItem" };
public Object[] stuff = { number, items };
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.test);
OverrideTest();
}
public void OverrideTest() {
TextView result = (TextView) findViewById(R.id.textView1);
result.setText(stuff.toString());
}
#Override
public String toString() {
return "I was called!";
}
}
Thanks a lot in advance!
You are overriding the toString() method for the class OverrideTestActivity and calling toString() for the array of Objects: that's why you are getting the default implementation of the Object class.
In this case, the toString() is called only on objects of type OverrideTestActivity.
Instead you are calling toString() on an array, which doesn't have such an implementation.
private int number = 27;
private String[] items = { "MyFirstItem", "MySecondItem" };
public Object[] stuff = { number, items };
If you did something like this
List<Object> stuff = Arrays.asList(27, "MyFirstItem", "MySecondItem");
stuff.toString();
You would find that it outputs a format that represents the contents of the List. The format will have been determined by the toString() method on the List implementation.
Related
I am working on an app in which users have to select a country code, i was successful in creating a spinner for the said purpose as shown in this link:
Creating a spinner for choosing country code
But i am getting problem in reading the value selected in the spinner.
{
String abc = onCountryPickerClick();//abc is always null
}
public String onCountryPickerClick (){
ccp.setOnCountryChangeListener(new CountryCodePicker.OnCountryChangeListener() {
#Override
public void onCountrySelected() {
selected_country_code = ccp.getSelectedCountryCodeWithPlus();
}
});
return selected_country_code;
}
When String abc = onCountryPickerClick(); is being invoked, the selected_country_code value will be assigned to abc.
When your CountryCodePicker.OnCountryChangeListener's onCountrySelected() method is being invoked, the ccp.getSelectedCountryCodeWithPlus();'s value gets assigned to selected_country_code. Since String is immutable, changing selected_country_code's value won't change the value of abc, nor the return selected_country_code; will be invoked.
One of possible solutions would be to change your CountryCodePicker.OnCountryChangeListener anonymous implementation to assign the selected country value to abc e.g.
#Override
public void onCountrySelected() {
selected_country_code = ccp.getSelectedCountryCodeWithPlus();
abc = selected_country_code
}
Callbacks are not synchronous. Unfortunately, you cannot simply do String abc = onCountryPickerClick(); because what you are returning is something that is not yet set. Let's go through your code:
ccp.setOnCountryChangeListener(
new CountryCodePicker.OnCountryChangeListener() {
#Override
public void onCountrySelected() {
selected_country_code = ccp.getSelectedCountryCodeWithPlus();
}
});
The code seems to say that when the country is selected in the spinner, you assign the value of selected_country_code. Assuming this is an action triggered by the user, when you call String abc = onCountryPickerClick();, how can you be sure the user has selected anything? This is the issue. You cannot be sure that the user has already selected the option and returning the value is not enough.
You can solve this in many ways. You can for example keep propagating the callback:
public void onCountryPickerClick(OnCountryChangeListener listener){
ccp.setOnCountryChangeListener(listener);
}
// Anywhere you call this
onCountryPickerClick(new CountryCodePicker.OnCountryChangeListener() {
#Override
public void onCountrySelected() {
// Here do whatever you want with the selected country
}
});
The above approach is not very different than what you have now. There are other options. You could use java observables i.e.:
class CountryCodeObservable extends Observable {
private String value;
public CountryCodeObservable(String value) {
this.value = value;
}
public void setCountryCode(String countryCode) {
value = countryCode;
setChanged();
notifyObservers(value);
}
}
public CountryCodeObservable onCountryPickerClick(){
CountryCodeObservable retValue = new CountryCodeObservable("");
ccp.setOnCountryChangeListener(
new CountryCodePicker.OnCountryChangeListener() {
#Override
public void onCountrySelected() {
retValue.setCountryCode(ccp.getSelectedCountryCodeWithPlus());
}
});
return retValue;
}
// Then when calling this method you can do something like:
CountryCodeObservable observable = onCountryPickerClick();
observable.addObserver((obj, arg) -> {
// arg is the value that changed. You'll probably need to cast it to
// a string
});
The above example lets you add more than one observable. It might be too much for your use case, I just thought it illustrates another approach and also the asynchronicity of this situation.
Again, there are even more ways to solve this, the key is that you can't simply return a string and hope it changes when the user selects anything.
I want to return an object with some things in them.
Here is the declaration;
Object user_det = get_user_det();
Here is the function code:
private Object get_user_det() {
Firebase f_user = new Firebase("https://myapp.firebaseio.com/User/");
f_user.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot snap_user) {
// TODO Auto-generated method stub
Iterable<DataSnapshot> rs = snap_user.getChildren();
Iterator<DataSnapshot> irs = rs.iterator();
long allNum2 = snap_user.getChildrenCount();
int maxNum2 = (int)allNum2;
int count_user = 1;
while(irs.hasNext())
{
if(count_user <= maxNum2)
{
Firebase user_data = new Firebase("https://myapp.firebaseio.com/");
AuthData authData = user_data.getAuth();
Map<String, Object> nPost = (Map<String, Object>) irs.next().getValue();
String db_email = nPost.get("email_addr").toString();
if (authData != null) {
String usr_email = authData.getProviderData().get("email").toString();
if(usr_email.equals(db_email))
{
//NB: I WANT TO ADD THE FOLLOWING INTO THE OBJECT
String disp_name = nPost.get("disp_name").toString();
String real_name = nPost.get("real_name").toString();
}
} else {
System.out.println("Failed");
}
}
count_user++;
}
}
#Override
public void onCancelled(FirebaseError arg0) {
// TODO Auto-generated method stub
}
});
return null; //NB: I NEED TO RETURN THE OBJECT HERE.
}
I want to return the string disp_name and real_name but they are inside the addListenerForSingleValueEvent, so how do I get them out and return it to the function.
I have wrote "NB" in the code where I need help with.
Thanks for your time.
If you want to return an object from your method in java, do it like this:
The Object class:
This contains the structure of your Object, and defines what data will be in it. Also includes methods to easily get the data.
private class myObject {
private String name;
private String realName;
//The constructor, so you can set the data when creating the Object.
public myObject (String disp_name, String real_name) {
name = disp_name;
realName = real_name;
}
//Getter methods, to get the data.
public String getRealName() {return realName;}
public String getDisplayName() {return name;}
}
Your code:
private Object get_user_det() {
myObject o; //Declare it, so it can be returned.
...
String disp_name = nPost.get("disp_name").toString();
String real_name = nPost.get("real_name").toString();
o = new myObject(disp_name, real_name); //create it and set the data.
...
return myobject; //return the new Object with the data.
}
To get the data from the Object:
myObject o = get_user_det(); //Call the metod which return our Object.
String realName = o.getRealName(); //Get the data from the Object.
String displayName = o.getDisplayName;
In your case, it would be much easier to use a String array.
Hope this helps.
It's probably easiest to see what's going on, if you add some printlns to your code:
private Object get_user_det() {
Firebase f_user = new Firebase("https://myapp.firebaseio.com/User/");
System.out.println("Adding listener");
f_user.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot snap_user) {
System.out.println("Data received");
}
#Override
public void onCancelled(FirebaseError arg0) {
// TODO Auto-generated method stub
}
});
System.out.println("Returning");
return null; //NB: I NEED TO RETURN THE OBJECT HERE.
}
If you execute this code, you will see that it logs:
Adding listener
Returning
Data received
Most likely, this is not what you expected. But hopefully, it makes sense if you read my explanation below.
Asynchronous loading
When you register your listener:
f_user.addListenerForSingleValueEvent(new ValueEventListener(){
You tell Firebase to start listening for events. It goes off and starts retrieving the data from the server.
Since retrieving the data may take some time, it does this retrieval asynchronously so that your thread isn't blocked. Once the data is completely retrieved, Firebase calls the onDataChange method in your listener.
Between the time you start listening and the time onDataChange is called, your code continues executing. So there is no way to return data that is loaded asynchronously, because by the time your function returns, the data isn't loaded yet.
Solutions
Disclaimer: I am not an expert at solving this problem in Java, so there may be problems with my solutions. If^H^HWhen you find any, please report them in the comments.
I know of three possible solutions to the problem:
force the code to wait for the data to be returned
return a Future that at some point will contain the data
pass a callback into get_user_det and call that function once the data is available
You will probably be tempted to selected option 1, since it matches most closely with your mental modal of loading data. While this is not necessarily wrong, keep in mind that there is a good reason that the loading is done asynchronously. It might be worth taking the "learning how to deal with asynchronicity" penalty now.
Instead of writing up examples for all solutions, I'll instead refer to some relevant questions:
Retrieving data from firebase returning NULL (an answer that uses approach 3)
Is waiting for return, ok?
Java wait() & notify() vs Android wait() & notify() (a question from a user taking approach 1)
How it works:
Firebase uses reflection to build a JSON tree object to save to the database. When you retrieve this JSON tree, you can cast it back to your original object. Just like serializing and deserializing. This means you do not need to handle the keys and values when trying to "rebuild" your object like you are. It can all be done like so:
YourObject object = (YourObject) dataSnapshot.getValue(YourObject.class);
Notice the YourObject.class in the getValue(). This tells firebase to reflect through this class and find the appropriate accessors with the dataSnapshot.
How to do it
Be sure that your object has:
Accessors Appropriate getters and setters for ALL fields - (or annotated with #JsonIgnore if you wish to not save a particular field)
Empty constructor. Your object must provide a constructor that does not modify itself at all.
What your object should look like:
public class YourObject {
private String displayName;
private String realName;
public YourObject() { /*Empty constructor needed for Firebase */ }
// Accessors
public void setRealName(String realName){
this.realName = realName;
}
public String getRealName(){
return this.realName;
}
public String getDisplayName(){
return this.displayName;
}
public void setDisplayName(String displayName){
this.displayName = displayName;
}
}
Then, in any of the firebase callbacks, you can just cast your DataSnapshot in to your object:
public void onDataChange(DataSnapshot snap_user) {
YourObject object = new Object;
if(snap_user.getValue() != null) {
try {
object = (YourObject) snap_user.getValue(YourObject.class); <-- Improtant!!!
} catch(ClassCastException ex) {
ex.printStackTrace();
}
}
return object;
}
Also
It seems you are retrieving many objects. When doing this, I find it best to use the onChildEventListener then for each of the YourObjects in that node, onChildAdded(DataSnapshot ds, String previousChild); will be called.
public class UnitListAdapter extends ArrayAdapter<Unit> {
private Context context;
private ArrayList<Unit> units;
private MeasurementType type;
private static HashMap<String, Double> unitValues;
public void setMeasurementType(MeasurementType measurementType) {
type = measurementType;
}
public void setUnitValues(HashMap<String, Double> newValues) {
unitValues.clear();
unitValues = newValues;
}
public void setUnits(ArrayList<Unit> newUnits) {
units = newUnits;
}
}
Above is the implementation of ArrayAdapter minus the getView() and getCount() methods. Now, in my activity I have this method:
public void updateUnitAdapter(ArrayList<Unit> units, final MeasurementType measurementType) {
//change the type
unitAdapter.setMeasurementType(measurementType);
//set the hashmap unit values
unitValues = new HashMap<String, Double>() {{
put(measurementType.getType(), DEFAULT_VALUE);
}};
//clear the current units for the previous measurement type
unitAdapter.clear();
//add the new units for the new measurement type
for(Unit u : units) {
unitAdapter.add(u);
}
//update the list view
unitAdapter.notifyDataSetChanged();
}
but when I step through in the debugger, it gets to the getView() method and when I check these variables, they are haven't changed to the new ones that I am setting them too, they stay the same...is there something I am not understanding about ArrayAdapter ?
ArrayAdapter has its own internal collection, which is modified when you call add() or clear(). In this case you are updating it, but (from your comments) it looks like you have also overriden getCount() and getView() to get those values from somewhere else (possibly the units member?).
If that's the case, you should update units intead of calling clear()/add().
Otherwise, remove the units field altogether and use getItem() to access the collection items.
I finally managed to get an object out of an AsyncTask (DogAsyncTask) with an interface/listener (DogListener):
public String fout(String url) {
Dog d_in = new Dog("DogName");
DogAsyncTask task = new DogAsyncTask(d_in);
final String out = ""; <---Have tried but error for out becomes "The final local variable out cannot be assigned, since it is defined in an enclosing type"
task.setDogListener(new DogListener()
{
#SuppressWarnings("unchecked")
#Override
public void DogSuccessfully(String data) { <---The string I want to get
Log.e("DogListened", data);
out = data;
}
#Override
public void DogFailed() {}
});
task.execute(url);
return out;
}
My main activity calls this function (fout) and is supposed to get a String out of it. String data is already there and Log.e("DogListened", data); records it too. How can I return that outwards to my main activity? I have tried setting out = data and made out a final String on the outside but the "final local variable out cannot be assigned, since it is defined in an enclosing type" error comes up. How can I get around this?
Thanks
I guess you cannot access to out because it is out of the listener's scope. You can maybe pass your out as a reference parameter to the constructor of your DogListener.
final String out = "";
task.setDogListener(new DogListener( **out** )
{
#SuppressWarnings("unchecked")
#Override
public void DogSuccessfully(String data) {
Log.e("DogListened", data);
out = data;
}
#Override
public void DogFailed() {}
});
BUT honestly I donT know how to pass parameters as a reference in Java like in C#..
EDIT:
This can help you too: Can I pass parameters by reference in Java?
Use a value holder, which basically is an object which stores some value in a field. The value holder can be assigned as final, but you can change the value. Follow the link for more info on this pattern: http://martinfowler.com/eaaCatalog/lazyLoad.html
However you can use your string as value holder: Just append to the empty string assigned to out. Or better use a StringBuffer object.
So I've been googling most of yesterday and last nite and just can't seem to wrap my head around how to pass an arraylist to a subactivity. There are tons of examples and snippets passing primitive data types, but what I have is an arraylist of type address (address.java below).
I've found a lot of stuff on stackoverflow and around the web on this, but nothing that got a lot of attention except for one with a GeoPoint example. Again, it looked to me like they just flattened the GeoPoint object into two integers and passed it in. I can't do that because my address class may expand to include integers, floats, whatever. Right now, the test app below is only two strings for simplicity. I thought if I could get the parcelalbe stuff working with that, the rest could follow.
Can someone post a working example for an ArrayList of a non-primitive object, or perhaps add code below to make this work?
UPDATE: code below is now working after replies/editing. Thanks!
/* helloParcel.java */
public class helloParcel extends Activity
{
// holds objects of type 'address' == name and state
private ArrayList <address> myList;
#Override
public void onCreate (Bundle savedInstanceState)
{
super.onCreate (savedInstanceState);
setContentView (R.layout.main);
Button b1 = (Button) findViewById(R.id.button1);
b1.setOnClickListener(ocl);
myList = new ArrayList();
address frank = new address ("frank", "florida");
address mary = new address ("mary", "maryland");
address monty = new address ("monty", "montana");
myList.add (frank);
myList.add (mary);
myList.add (monty);
// add the myList ArrayList() the the extras for the intent
}
OnClickListener ocl = new OnClickListener()
{
#Override
public void onClick(View v)
{
// fill parceable and launch activity
Intent intent = new Intent().setClass(getBaseContext (), subActivity.class);
// for some reason, I remember a posting saying it's best to create a new
// object to pass. I have no idea why..
ArrayList <address> addyExtras = new ArrayList <address>();
for (int i = 0; i < myList.size(); i++)
addyExtras.add (myList.get(i));
intent.putParcelableArrayListExtra ("mylist", addyExtras);
startActivity(intent);
}
};
}
/* address.java */
public class address implements Parcelable
{
private String name;
private String state;
private static String TAG = "** address **";
public address (String n, String s)
{
name = n;
state = s;
Log.d (TAG, "new address");
}
public address (Parcel in)
{
Log.d (TAG, "parcel in");
name = in.readString ();
state = in.readString ();
}
public String getState ()
{
Log.d (TAG, "getState()");
return (state);
}
public String getName ()
{
Log.d (TAG, "getName()");
return (name);
}
public static final Parcelable.Creator<address> CREATOR
= new Parcelable.Creator<address>()
{
public address createFromParcel(Parcel in)
{
Log.d (TAG, "createFromParcel()");
return new address(in);
}
public address[] newArray (int size)
{
Log.d (TAG, "createFromParcel() newArray ");
return new address[size];
}
};
#Override
public int describeContents ()
{
Log.d (TAG, "describe()");
return 0;
}
#Override
public void writeToParcel (Parcel dest, int flags)
{
Log.d (TAG, "writeToParcel");
dest.writeString (name);
dest.writeString (state);
}
}
/* subActivity.java */
public class subActivity extends Activity
{
private final String TAG = "** subActivity **";
private ArrayList <address> myList;
#Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate (savedInstanceState);
Log.d (TAG, "onCreate() in subActivity");
setContentView(R.layout.subactivity);
TextView tv1 = (TextView) findViewById(R.id.tv_sub);
myList = getIntent().getParcelableArrayListExtra ("mylist");
Log.d (TAG, "got myList");
for (int i = 0; i < myList.size (); i++)
{
address a = myList.get (i);
Log.d (TAG, "state:" + a.getState ());
tv1.setText (a.getName () + " is from " + a.getState ());
}
}
}
I can see a number of problems here:
Why use addressParcelable? Why not make address implement Parcelable, and then use:
intent.putParcelableArrayListExtra( "addresses", addyExtras );
Your parcelable object must include a static CREATOR. See the documentation for details.
You are not actually adding any extras to the intent before you call startActivity(). See point 1 for a suggestion here.
I think that you will need to address all of these issues in order to get it working.
It can be done MUCH simpler, without all the pain-in-the-ass of implementing Parcelable...
ArrayList (but NOT any List) is Serializable. So, you can put the entire list using putExtra() and retrieve it using getSerializableExtra(), as Sam said.
BUT, I want to add one more important thing: the object your array list stores has to also implement Serializable... and all other complex objects that the object may contain (in your case none) must also implement that (so it's recursive - in order to serialize an object, you must be able to serialize all of its fields).
Now, you might be asking yourself why implementing Serializable instead of Parcelable when there are already methods for reading and writing array lists of parcelables?
Well... the difference is simplicity - just add implements Serializable and optionally private static final long serialVersionUID = SOME_CONSTANT and you're DONE! That is the reason why I never use Parcelable - you can do all those things using Serializable with literally 2 lines of code - instead of many method inheritances and all that stuff...
You can pass Serializable objects via putExtra. ArrayList implements Serializable.
Mike dg is correct!
putExtra() and getSerializable() will store and retrieve an ArrayList<> of your custom objects, with no interface implementing required. Worked for me!