I have a provider that takes a decent number of properties. For example:
public MyProvider(
byte[] image,
String firstName,
String nickName,
String lastName,
String hairColor,
String favoriteFood,
String favoriteColor,
String cityBorn,
String stateBorn,
long favoriteNumber,
int age,
String nameOfFather,
String nameOfMother,
String nameOfBestFriend
)
I do know that I can get the value of each property, and set each individual one as an extra, like so:
Intent myIntent = new Intent(firstActivity.this, secondActivity.class);
myIntent.putExtra("firstName", myProvider.getFirstName().toString());
myIntent.putExtra("nickName", myProvider.getNickName().toString());
...
firstActivity.this.startActivity(myIntent);
I would like to just pass the entire provider as an extra, and then be able to get the provider in the next activity. I know it's possible to do such a thing in Swift, but I am not sure how to do so in Java for Android Studio.
What I am hoping to be able to do is something like the following:
MyProvider newPerson = new MyProvider(image, firstName, nickName, lastName, hairColor, favoriteFood, favoriteColor, cityBorn, stateBorn, favoriteNumber, age, nameOfFather, nameOfMother, nameOfBestFriend);
intent.putExtra(newPerson);
But it seems like a provider cannot be passed like this (or possibly at all?).
Alternative Attempt:
I also attempted passing it as data like a URI (see here), but .setData is specifically for URIs.
Is there such a way to pass the entire provider as an extra, and then be able to get the provider in the next activity?
Thanks in advance.
EDIT
I have implemented Parcelable as #NabinBhandari and #JuanCruzSoler suggested, but it is causing the following error:
Cannot resolve constructor 'MyProvider(byte[], java.lang.String, long)'
when I call:
MyApartmentsProvider newApartment = new MyApartmentsProvider(image, firstName, favoriteNumber);
My updated MyProvider.java is as follows:
(note: I cut out some variables for the time being to make the example easier to work with)
import android.os.Parcel;
import android.os.Parcelable;
public class MyProvider implements Parcelable {
/////////////////////////
// Initializers
byte[] image;
String firstName;
long favoriteNumber;
// End of [Initializers]
/////////////////////////
/////////////////////////
// Getters
public byte[] getImage() {
return image;
}
public String getFirstName() {
return firstName;
}
public long getFavoriteNumber() {
return favoriteNumber;
}
// End of [Getters]
/////////////////////////
/////////////////////////
// Setters
public void setImage(byte[] image) {
this.image = image;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setFavoriteNumber(long favoriteNumber) {
this.favoriteNumber = favoriteNumber;
}
// End of [Setters]
/////////////////////////
public MyProvider() {
super();
}
public MyProvider(Parcel parcel) {
image = new byte[parcel.readInt()];
parcel.readByteArray(image);
this.firstName = parcel.readString();
this.favoriteNumber = parcel.readLong();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(image.length);
parcel.writeByteArray(image);
parcel.writeString(this.firstName);
parcel.writeLong(this.favoriteNumber);
}
public static final Creator<MyProvider> CREATOR=new Creator<MyProvider>() {
#Override
public MyProvider createFromParcel(Parcel parcel) {
return new MyProvider(parcel);
}
#Override
public MyProvider[] newArray(int i) {
return new MyProvider[i];
}
};
}
Make your Provider class implement the interface Serializable or Parcelable.
Parcelable is faster but Serializable is easier to implement.
To send:
intent.putExtra(KEY, yourObj);
To receive:
Provider provider = (Provider) getIntent().getSerializableExtra(KEY);
Related
I am new to collections and looking for help. I am trying to search a map using a key, and return the values of the key which is from another object. This is my code so far.
public class Employer {
Map<String, NewHire> employee = new HashMap<>();
}
public void addEmployee(String fullName, String age, String location, String JobTitle) {
NewHire newEmployee = new NewHire(age, location, JobTitle);
this.employee.put(fullName, newEmployee);
}
The code for the other object is -
public class NewHire {
private String age;
private String location;
private String jobTitle;
}
public NewHire(String aAge, String aLocation, String aJobTitle) {
this.age = aAge;
this.location = aLocation;
this.jobTitle = aJobTitle;
}
I then create like so -
Employer CompanyA = new Employer();
CompanyA.addEmployee("JohnSmith", "23", "London", "Service Desk");
I wanted to create a method that can search the map for a key specified by the user, in this case "JohnSmith", and if found, it then shows me the age, location and jobTitle of that person but I really am not sure how I would go about this.
The best way to go about it in my opinion is the way Titulum said, using Optional.
I would just leave another way, a bit not so nice, but you may understand it better.
You can Override the toString() method in the NewHire class and use it, or create getters for the properties:
#Override
public String toString(){
return String.format("Age: %s\nLocation: %s\nJobTitle: %s", age, location, jobTitle);
}
// getters
public String getJobTitle() {
return jobTitle;
}
public String getLocation() {
return location;
}
public String getAge() {
return age;
}
On your Employer class, if you want to use the not so much nicer way of doing it (although i recommend using Optional):
public NewHire getEmployeeByName(String fullName){
return employee.get(fullName);
}
Then to use it:
Employer employer = new Employer();
employer.addEmployee("JohnSmith", "23", "London", "Service Desk");
NewHire newHire = employer.getEmployeeByName("sJohnSmith");
if(newHire != null) {
System.out.println(newHire.toString());
// using getters
System.out.println(newHire.getAge());
System.out.println(newHire.getJobTitle());
System.out.println(newHire.getLocation());
}
You can simply write the method as follows:
public Optional<NewHire> findByFullName(String fullName) {
return Optional.ofNullable(employee.get(fullName));
}
This will return you an Optional, which is an Object in Java that contains either something or nothing. To see if the Optional contains anything you can do:
Optional<NewHire> possiblyFoundNewHire = findByFullName("SomeName");
possibleFoundNewHire.ifPresent(newHire -> {
System.out.println(newHire); // Or formatted as you would like.
});
How can I display another field from my object in vigiltime.setText? I want it to display the specific relating value of the time fields wihtin the object from the parishArrayList?
The parent.getItemAtPosition(position) already retrieves the specific object then how can I get it to parse relevant object details within the onItemSelected method?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parishArrayList = new ArrayList<>();
parishArrayList.add(new Parish(1, "Aghyaran", "Termonamongan, N.West Tyrone", "6.30pm", "10.00am"));
parishArrayList.add(new Parish(2, "Castlederg", "Castlederg, N.West Tyrone", "7pm", "11.00am"));
parishArrayList.add(new Parish(3, "Strabane", "Strabane, N.West Tyrone", "8pm", "12.00am"));
Spinner parishSpinner = (Spinner) findViewById(R.id.spinner);
// Create an ArrayAdapter using the parishArrayList and a default spinner layout
ArrayAdapter<Parish> parishAdapter = new ArrayAdapter<Parish>(getApplicationContext(), android.R.layout.simple_spinner_item, parishArrayList);
// Specify the layout to use when the list of choices appears
parishAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
parishSpinner.setAdapter(parishAdapter);
parishSpinner.setOnItemSelectedListener(this);
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
TextView vigiltime = (TextView) findViewById(R.id.vigiltime);
vigiltime.setText("Spinner selected : ");
vigiltime.setText(vigiltime.getText() + parent.getItemAtPosition(position).toString());
}
Parish.java
public class Parish {
private int parishIdNumber;
private String pName;
private String pAddress;
private String pVigilTimes;
private String pSundayTimes;
public Parish(int id, String name, String address, String vigilTimes, String sundayTimes) {
parishIdNumber = id;
pName = name;
pAddress = address;
pVigilTimes = vigilTimes;
pSundayTimes = sundayTimes;
}
public int getId() {
return parishIdNumber;
}
public void setId(int id) {
parishIdNumber = id;
}
public String getName() {
return pName;
}
public void setName(String name) {
pName = name;
}
public String getAddress() {
return pAddress;
}
public void setAddress(String address) {
pAddress = address;
}
public String getVigilTimes() {
return pVigilTimes;
}
public String getsundayTimes() {
return pSundayTimes;
}
public int getParishIdNumber() {
return parishIdNumber;
}
public void setParishIdNumber(int parishIdNumber) {
this.parishIdNumber = parishIdNumber;
}
#Override
public String toString() {
return pName;
}
}
You don't need to use toString(). You could simply call the relevant functions or variables of your Parish class:
Parish item = parent.getItemAtPosition(position);
vigilTime.setText("Spinner selected : ");
vigilTime.append(item.getTime() + " "); //append has the same effect as what you're currently doing
vigilTime.append(item.getSomethingElse + " ");
//etc
If you want to simply use toString(), override it in your Parish class:
#Override
public String toString() {
return /* format the String you want returned here */
}
EDIT: to answer your actual question:
ViewAdapter#getItemAtPosition() returns an Object, not your specific class. You need to cast that call to Parish:
Parish item = (Parish) parent.getItemAtPosition(position);
Then you can call item.getVigilTimes();.
Override the toString method in the class that you want to alter the string representation.
#Override
public String toString() {
//TODO - Here.
}
You can access any private variable of an object through a public method of class shown below.
vigiltime.setText(vigiltime.getText() + ((Parish)parent.getItemAtPosition(position)).getVigilTimes());
You can also override toString() method to display VigilTimes and call parent.getItemAtPosition(position).toString().
#Override
public String toString() {
return pVigilTimes;
}
The toString() method is inherited from the Object Class that every other class in java inherits from. The foundational toString() returns this:
getClass().getName() + '#' + Integer.toHexString(hashCode())
The string class if you are creating a new string object like String
first_name = 'someFirstName'
actually creates an instances with the constructor,
String first_name = new String("someFristName")
and this class overrides the object toString() method once more.
The documentation at Oracle says of toString() in the String class,
This object (which is already a string!) is itself returned.
Every single class that is created or built is directly or indirectly inherited from the Object class which has the foundational toString() which one can override within the current class. It's as simple as...
#Override
public String toString(){
//to do logic here
}
Your overrided toString() is nothing more than your getName() method. Consider if it is necessary.
I have started with parse to store the data of my class. I have followed parse guide and tutorials and tried to implement the code. Unfortunately, the objects of class are not getting saved in parse data browser. When I see the data in browser just one object id is shown not the columns of name, desc and qty of my item class. I have created class in dashboard also created columns respective to my data. Unable to get the solution as I am new to android and parse.
Here is my code
Item class
package com.example.owner.newstock;
import com.parse.ParseClassName;
import com.parse.ParseObject;
#ParseClassName("Item")
public class Item extends ParseObject {
public int id;
public String item_name;
public String item_desc;
public String item_qty;
public Item(){}
public Item(int id, String item_name, String item_desc, String item_qty) {
super();
this.item_name = item_name;
this.item_desc = item_desc;
this.item_qty = item_qty;
}
public Item(String item_name, String item_desc, String item_qty){
this.item_name = item_name;
this.item_desc=item_desc;
this.item_qty = item_qty;
}
public int getID(){
return id;
}
public void setID(int id){
this.id= id;
}
public String getItem_name(){
return getString(item_name);
}
public void setItem_name(String item_name)
{
put("item_name", item_name);
}
public String getItem_desc()
{
return getString(item_desc);
}
public void setItem_desc(String item_desc)
{
put("item_desc", item_desc);
}
public String getItem_qty()
{
return getString (item_qty);
}
public void setItem_qty(String item_qty){
put("item_qty", item_qty);
}
}
code of parse in main activity
ParseObject.registerSubclass(Item.class);
Parse.initialize(this, "Kw0dyUgLoqv24QdLE30mvFBVclEzLHRGtR2hQVHA", "5BWc3bAd60EgqU0sFIj31mMYYg7OIX9WKgC0a6oP");
ParseAnalytics.trackAppOpened(getIntent());
code to save the objects
Item i = new Item();
i.setItem_name(item_name);
i.setItem_desc(item_desc);
i.setItem_qty(item_qty);
i.saveInBackground();
Am I missing something?
Rather than creating an item class that extends ParseObject, set up a ParseObject variable, as follows:
ParseObject item = new ParseObject("Item");
Then put data in as follows:
item.put("quantity", yourQuantityVariable);
item.put("description", yourDescriptionVariable);
item.put("name", yourNameVariable);
To save:
item.saveInBackground();
To retrieve data, make use of querying and the getDataType() methods. Specified on https://parse.com/docs/android/guide#objects and https://parse.com/docs/android/guide#queries
Well, i was trying to pass arraylist of objects from one activity to another. I have 2 constructors in the class Student.
If, i use, Serializable than the code is like below:
#SuppressWarnings("serial")
public class Student implements Serializable
{
private int studentdID;
private String studentName;
private String studentDept;
public Student(){}
public Student(String name, String dpt)
{ this.studentName = name;
this.studentDept = dpt;}
public Student(int id, String name, String dpt)
{ this.studentdID = id;
this.studentName = name;
this.studentDept = dpt; }
public int getstudentdID() { return studentdID; }
public void setstudentdID(int studentdID) {this.studentdID = studentdID;}
public String getstudentName() { return studentName;}
public void setstudentName(String studentName) {this.studentName = studentName;}
public String getstudentDept() { return studentDept; }
public void setstudentDept(String studentDept) { this.studentDept = studentDept;}
}
But the problem i am facing is that how am i going to do this with parcelable? How am i going to set the values of the variables in class-like i did with Serializable? I mean separately using 2 constructors-one without ID another without the ID?
Did you read how Parcelable works?
You need only one constrcutor for parcelable to read what you pass to it, and Parcelable interface will add a method writeToParcel where you put the data to save.
It's not an automatic process like Serializable, everything is up to you.
The constructor which Parcelable will use will accept only one argument Parcel where you will find some methods like read*(KEY) to read back values.
And in writeToParcel you will write in the Parcel (the argument of the method) the values you want pass to pass with write*(KEY, VALUE).
Parcelable don't care about your constructors or fields.
P.S You will need a CREATOR too. Read some tutorial online to know more about it if you need.
Marco's answer explains why Parcelable doesn't automatically decide what constructor to use - it can't.
However, there is a way around this. Use Parcel.dataAvail(), which
Returns the amount of data remaining to be read from the parcel. That
is, dataSize()-dataPosition().
For example,
public Student(){}
public Student(String name, String dpt)
{
this.studentName = name;
this.studentDept = dpt;}
public Student(int id, String name, String dpt)
{ this.studentdID = id;
this.studentName = name;
this.studentDept = dpt;
}
public Student(Parcel in) {
name = in.readString();
dpt = in.readString();
if(in.dataAvail() > 0) // is there data left to read?
id = in.readInt();
}
^ The above constructor will allow for the necessary variables to be instantiated correctly. Also, you define writeToParcel() something like:
public void writeToParcel(Parcel out) {
out.writeString(name);
out.writeString(dpt);
//0 is the default value of id if you didn't initialize it like
// in the first constructor. If it isn't 0, that means it was initialized.
if(id != 0)
out.writeInt(id);
}
Of course, you'll need to define your CREATOR like so:
public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
public Student createFromParcel(Parcel in) {
return new Student(in);
}
public Student[] newArray(int size) {
return new Student[size];
}
};
#u3l solution is not required..how many constructors are there it doesn't matter.
simple it works go as normal implementation.
I mean no special care is required when multiple constructors present in parcelable.
If I want to validate my input, should I make validation code as private helper methods or create a separate static helper class? Does the validation code increase the size of the object?
More Information
Let's say I have a class
import java.util.Vector;
public class Place {
private final double longitude;
private final double latitude;
private final String id;
private String address;
private String name;
private String types;
private String icon;
private String phoneNumber;
private String websiteUrl;
private int rating;
private Vector<Integer> challenges;
public static class Builder {
// required parameter
private final double longitude;
private final double latitude;
private final String id;
// optional parameter
private String address = "n/a";
private String name = "n/a";
private String icon = "n/a";
private String phoneNumber = "n/a";
private String websiteUrl = "n/a";
private String types = "n/a";
private Vector<Integer> challenges = new Vector<Integer>();
private int rating = 0;
public Builder(double longitude, double latitude, String id) {
assert(longitude >= -180.0 && longitude <= 180.0);
assert(latitude >= -90.0 && longitude <= 90.0);
this.longitude = longitude;
this.latitude = latitude;
this.id = id;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder types(String types) {
this.types = types;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder icon(String icon) {
this.icon = icon;
return this;
}
public Builder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public Builder websiteUrl(String websiteUrl) {
this.websiteUrl = websiteUrl;
return this;
}
public Builder builder(int rating) {
this.rating = rating;
return this;
}
public Place build() {
return new Place(this);
}
}
public Place(Builder builder) {
// required parameters
longitude = builder.longitude;
latitude = builder.latitude;
id = builder.id;
// optional parameters
address = builder.address;
types = builder.types;
name = builder.name;
icon = builder.icon;
phoneNumber = builder.phoneNumber;
websiteUrl = builder.websiteUrl;
rating = builder.rating;
challenges = builder.challenges;
}
public double getLongitude() {
return longitude;
}
public double getLatitude() {
return latitude;
}
public String getId() {
return id;
}
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
public String getTypes() {
return types;
}
public void setTypes(String types) {
this.types = types;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setIconUrl(String icon) {
this.icon = icon;
}
public String getIcon() {
return icon;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setWebsiteUrl(String websiteUrl) {
this.websiteUrl = websiteUrl;
}
public String getWebsiteUrl() {
return websiteUrl;
}
public void setRating(int rating) {
this.rating = rating;
}
public int getRating() {
return rating;
}
#Override
public String toString() {
return "(" + Double.toString(longitude) + ", " + Double.toString(latitude) + ")";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Place other = (Place) obj;
if (id == null) {
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
return true;
}
public Vector<Integer> getChallenges() {
return new Vector<Integer>(challenges);
}
public void addChallenges(Integer i) {
this.challenges.add(i);
}
public void showChallenges() {
for (Integer i : challenges) {
System.out.print(i + ", ");
}
}
}
If I have to validate address argument before setting it, where should I put the code for validating address in this case?
If you are talking just seeing if the entered String is formatted correctly or if the length is right, then you would use a private method. If you would on the other hand check if the address is correct (look it up on a map) or any more advanced stuff, it would make sense to create a AddressValidator interface and call it from that private method.
The reason for the private method being that you call this both from a constructor, setter or any other method that could suppy an address. The reason for the interface being that you might want to have e.g. an online / offline AddressValidator (MockAddressValidator, or one that calls a different class for each country etc).
As an AddressValidator could be reused in other classes, and to keep your code clean, I would create it as a top level interface + OnlineAddressValidator. This makes your class better readable as well. For full configurability, you might want to think about how you are going to supply the AddressValidator instance, e.g. through the constructor or one defined as a static final validator.
public interface AddressValidator {
static class AddressValidatorResult {
// some results, you might want to return some useful feedback (if not valid)
boolean isValid() {
throw new IllegalStateException("Method not implemented yet");
}
}
public static class AddressValidationException extends Exception {
private AddressValidationException(AddressValidatorResult result) {
// add some implementation
}
}
// don't throw ValidateException here, invalid addresses are normal for
// validators, even if they aren't for the application that uses them
AddressValidatorResult validateAddress(String address);
// don't throw ValidateException here, invalid addresses are normal for
// validators, even if they aren't for the application that uses them
}
public class DefaultAddressValidator implements AddressValidator {
public static class Params {
// some parameters for this specific validator
}
private final Params params;
public DefaultAddressValidator(Params params) {
// creates this validator
this.params = params;
}
#Override
public AddressValidatorResult validateAddress(String address) {
// perform your code here
// I don't like "return null" as it may lead to bugs
throw new IllegalStateException("Method not implemented yet");
}
}
// and use it like this
private void validateAddress(String address) throws AddressValidationException {
// e.g. field AddressValidator set in constructor
AddressValidatorResult result = addressValidator.validateAddress(address);
if (!result.isValid()) {
throw new AddressValidationException(result);
}
}
Should I make validation code as private helper methods or create a separate static helper class?
This totally depends on your context. It's impossible to say what should be the best design, without knowing what you are trying to realise.
After you edit: IMO, it is still not easy to tell you. If you only have to validate the address in one single point of your application (id: the setter method), I would validate it inside the setter method. If the input was invalid, I whould throw an IllegalArgumentException.
Does the validation code increase the size of the object?
However, the answer to your second question is No. To understand why, you have to know what Object Oriented Programming is.
Some references:
http://en.wikipedia.org/wiki/Object-oriented_programming
http://en.wikipedia.org/wiki/Class_(computer_science)
Should I make validation code as private helper methods or create a
separate static helper class?
It depends if you think that you'll need to reuse the same method also in another class for the same purpose(input validation) it is better write the method in a separate static helper class so you can reuse the method and maintain it easily.
If you write the same private helper method in several class each time that you need to make a changes you have to edit each method in each class, with a static helper class you change the code in one place only ...
Read about PropertyChangeListener and Bean Validation.
I tend to validate within the get() and set() methods wherever possible - calling external static methods for common tasks such as checking dates or cleaning input (i.e. to avoid sql injection)
If you only use (and are only ever going to use) the validation within one class, keep it as a private helper method. If in doubt, I tend to pull the functionality out into a static helper class. It makes very little difference to the amount of code, is no more effort to implement, and is much more flexible.
The short answer is: you should implement your validation code the way that your framework tells you to. Typically, this is a public method or an annotation. An interface could work too. If you add code, your class size will increase.
Data validation should be automatically called by your software's infrastructure. This helps to prevent programmers from forgetting to call the appropriate code. So, the methods should be public (an interface would work too).
Frameworks like Struts, Spring, Hibernate and have their own validation systems. Java EE leverages bean validation.
I recommend bean validation, because it performs validation regardless of the input source. When most people think of input validation, they think of data coming from the user e.g. HTTP Request, command console, Swing text field. Spring and Struts validation is often fine for those situations. But in long lived programs developed for enterprises, other data feeds often get introduced e.g. SQL database updates from another programs, database restoration after a crash, enterprise service bus, JMS.
That is why I prefer bean validation. The downside is that "safe sources" (data that you know is untainted) are validated unnecessarily. But with today's processing power, that should rarely be a significant concern.
Java EE Tutorial