Cannot put extra on an intent - java

I'm trying to put an object as extra on an intent. The class of the object was created by me, so I made it Parcelable.
public class NavigationDataSet implements Parcelable {
private ArrayList<Placemark> placemarks = new ArrayList<Placemark>();
private Placemark currentPlacemark;
private Placemark routePlacemark;
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
// TODO Auto-generated method stub
out.writeList(placemarks);
out.writeValue(currentPlacemark);
out.writeValue(routePlacemark);
}
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
public static final Parcelable.Creator<NavigationDataSet> CREATOR = new Parcelable.Creator<NavigationDataSet>() {
public NavigationDataSet createFromParcel(Parcel in) {
return new NavigationDataSet(in);
}
public NavigationDataSet[] newArray(int size) {
return new NavigationDataSet[size];
}
};
// example constructor that takes a Parcel and gives you an object populated with it's values
private NavigationDataSet(Parcel in) {
in.readTypedList(placemarks, Placemark.CREATOR);
this.currentPlacemark = in.readParcelable((ClassLoader) Placemark.CREATOR);
this.routePlacemark = in.readParcelable(Placemark.class.getClassLoader());
}
}
In the Activity, I declared the variable like this:
private List<NavigationDataSet> ds;
And the intent creation:
public static Intent mapIntent(Context context){
Intent i = new Intent(context, mapsView.class);
i.putExtra("NavSet", ds);
return i;
}
The variable ds is initialized on an AsyncTask that is executed on the onCreate method.
And I got a precompiling error on the putExtra instruction:
Cannot make a static reference to the non-static field ds
But here http://developer.android.com/reference/android/content/Intent.html it doesn't say it has to be a static variable.
And if I change it to static, the it says:
The method putExtra(String, boolean) in the type Intent is not
applicable for the arguments (String, List)
But I'm not passing a boolean, it's a Parcelable!!! So what do I do? I really don't understand the way this is working.

ArrayList<ParcelableObject> pointsExtra = new ArrayList<ParcelableObject>();
intent.putExtra("", pointsExtra);
http://developer.android.com/reference/android/content/Intent.html#putParcelableArrayListExtra%28java.lang.String

In your case, ds is not a static variable, therefore you can't reference it in a static method. Either make ds static, pass is as an argument to your mapIntent function, or make your mapIntent function not static.

Related

Modify variables in an instance from another class Android

I simplified this for brevity; hopefully this example isn't actually functional. I'm creating and doing things with a variable, then I'm having another class do some stuff, then that class refers back to the original and tells it to do more stuff with that variable.
I've done exactly this with views. I simply pass the activity and then when I need to use it I use activity.findViewById(id) to do stuff. With variables, you can't just do activity.variable. I tried using a getter (as shown in this example), but maybe I'm still just doing it wrong or it can't be done how I'd like:
public class MyActivity {
private int test;
public void onCreate(Bundle savedInstanceState) {
test = 5;
int data = 100;
//Pass something to it
new NotAnActivity().func(MyActivity.this,data);
}
public int gettest() {
return test;
}
public void func(Activity instance, int response) {
int test = new MyActivity().gettest();
//Do stuff with test
}
}
public class NotAnActivity {
public void func(Activity instance, int data) {
//Do stuff with data
int response = 20;
//Try to pass information back
new MyActivity().func(instance,response);
}
}
You can't use a activity.gettest() because you're passing the superclass Activity between classes. To have access to the gettest() method you need to pass the specific child activity (MyActivity extends Activity, pass MyActivity instead of Activity) or you can cast to your specific activity.
((MyActivity)activity).getter();
So here, instead of:
public void func(Activity instance, int data) {
//Do stuff with data
int test = ((MyActivity)instance).gettest();
}
or
public void func(MyActivity instance, int data) {
//Do stuff with data
int test = instance.gettest();
}
It's not a good idea to instantiate your activities yourself new A()
public class MainActivity extends AppCompatActivity {
private int test;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
test = 5;
int data = 100;
new NotAnActivity().func(this,data);
}
public int gettest() {
return test;
}
public void func(MainActivity instance, int response) {
//int test = new MainActivity().gettest();
int test = instance.gettest();
Log.v("variable", "test = " + test);
}
}
class NotAnActivity {
public void func(MainActivity instance, int data) {
//Do stuff with data
int response = 20;
//Try to pass information back
instance.func(instance,response);
}
}
You can try it. Your mistake is [new MyActivity()]

Reading ArrayList in Parcelable

I have a class called SuperMedia that implements Parcelable. One of the fields of the class is an ArrayList children. When I create a Bundle and try to pass a "SuperMedia" object from one activity to another, all the fields get passed fine with the exception of the ArrayList "children" which just shows up as being empty every time.
In my first Activity I do:
Bundle a = new Bundle();
a.putParcelable("media",media); //media is an object of type "SuperMedia" and all the "children" have been initialized and added to the array
final Intent i = new Intent("com.tv.video.subcategories");
i.putExtra("subcategories", a);
On my Second Activity I do:
Intent i = getIntent();
Bundle secondBun = i.getBundleExtra("subcategories");
SuperMedia media = secondBun.getParcelable("media"); //For some reason the ArrayList"children" field shows up as empty.
Im not sure why this is happening. If anybody can guide me on the right path that would be greatly appreciated. Below is my SuperMedia class btw.
public class SuperMedia implements Parcelable{
public URI mthumb;
public String mTitle;
public ArrayList<SuperMedia> children = new ArrayList();
public SuperMedia(URI thumb, String title) {
this.mthumb = thumb;
this.mTitle = title;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString(mTitle);
dest.writeString(mthumb.toString());
dest.writeTypedList(children);
}
public static final Parcelable.Creator<SuperMedia> CREATOR = new Parcelable.Creator<SuperMedia>() {
public SuperMedia createFromParcel(Parcel in) {
return new SuperMedia(in);
}
public SuperMedia[] newArray(int size) {
return new SuperMedia[size];
}
};
private SuperMedia(Parcel in) {
mTitle = in.readString();
try {
mthumb = new URI(in.readString());
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
in.readTypedList(children, SuperMedia.CREATOR);
}
public SuperMedia(){
}
}
If you want simply pass object through intent then you can make SuperMedia Serializable no need to Parcelable.
public class SuperMedia implements Serializable{...}
put it as
Bundle a = new Bundle();
a.putSerializable("media",media);
and we get it as.
Intent i = getIntent();
Bundle secondBun = i.getBundleExtra("subcategories");
SuperMedia media = (SuperMedia)secondBun.getSerializable("media");
if you really needed Parcelable then may it help you.
Arraylist in parcelable object
Use Bundle's putParcellableArrayList for storing SuperMedia object
Bundle args = new Bundle();
args.putParcelableArrayList("media", "media");
and for restroring
getArguments().getParcelableArrayList("media");
This way will ensure bundle save your list objects as implemented in parcelable instance.
Also, be aware of using only ArrayList, other List subclasses not supported.

How to pass Parcelable array to fragment and Activity

I'm working with custom parcelable class. I need to pass this class as array to another activity and new fragments. I googled, but I found arrayList but not arrays. Please mind that I need to pass arrays not Array lists. How to achieve that? Please mind again, performance is a big issue. So any solutions with less performance consumption is very welcome.
Any helps would be very appreciated.
You can pass your arrayList as below snipts.
TestFragment testFragment = new TestFragment();
Bundle args = new Bundle();
args.putSerializable("parsedData", (Serializable)mTestModelList);
testFragment.setArguments(args);
And Get these parcable data in Model as like below:
mTestModelList = (List<TestModel>)getArguments().get("parsedData");
YES, Serialisation is slow bit than Parcelable.
And you can implement that using parceler
Of course, the ParcelWrapper can be added to an Android Bundle to transfer from Activity to Activity using this:
Bundle bundle = new Bundle();
bundle.putParcelable("example", Parcels.wrap(example));
And dereferenced in the onCreate() method:
Example example = Parcels.unwrap(getIntent().getParcelableExtra("example"));
You can get more detail of performance related to Parcelable vs Serializable here.
Here is the write answer
// write parcelable array
final Bundle arguments = new Bundle();
MyParcelable[] myArray = new MyParcelable[10];
arguments.putParcelableArray("key"myArray);
// read parcelable array
MyParcelable[] myArray = (MyParcelable[])getArguments().getParcelableArray("key");
use like following class of your parcealble array
public class ParcelableLaptop implements Parcelable {
private Laptop laptop;
public Laptop getLaptop() {
return laptop;
}
public ParcelableLaptop(Laptop laptop) {
super();
this.laptop = laptop;
}
private ParcelableLaptop(Parcel in) {
laptop = new Laptop();
laptop.setId(in.readInt());
laptop.setBrand(in.readString());
laptop.setPrice(in.readDouble());
laptop.setImageBitmap((Bitmap) in.readParcelable(Bitmap.class
.getClassLoader()));
}
/*
* you can use hashCode() here.
*/
#Override
public int describeContents() {
return 0;
}
/*
* Actual object Serialization/flattening happens here. You need to
* individually Parcel each property of your object.
*/
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(laptop.getId());
parcel.writeString(laptop.getBrand());
parcel.writeDouble(laptop.getPrice());
parcel.writeParcelable(laptop.getImageBitmap(),
PARCELABLE_WRITE_RETURN_VALUE);
}
/*
* Parcelable interface must also have a static field called CREATOR,
* which is an object implementing the Parcelable.Creator interface.
* Used to un-marshal or de-serialize object from Parcel.
*/
public static final Parcelable.Creator<ParcelableLaptop> CREATOR =
new Parcelable.Creator<ParcelableLaptop>() {
public ParcelableLaptop createFromParcel(Parcel in) {
return new ParcelableLaptop(in);
}
public ParcelableLaptop[] newArray(int size) {
return new ParcelableLaptop[size];
}
};
}
now make Arraylist of ParcelableLaptop and put in the bUndle with argument
intent.putParcelableArrayListExtra("laptop", parcelableLaptopArray);
Where parcelableLaptop is your Arraylist of the Model. And to get the List:
Intent intent = getIntent();
ArrayList<ParcelableLaptop> parcelableLaptop = (ParcelableLaptop) intent
.getParcelableArrayListExtra("laptop");

Android getter setter returns null data?

I have one class ApplicationDetails, with getter and setter methods.
public class ApplicationDetails {
String supportURL;
String companyURL;
String copyRightText;
// with getter and setter methods
}
I am setting all data in my splash screen activity.
ApplicationDetails appDetails = new ApplicationDetails();
String supportURL = getResources().getString(R.string.support_url);
appDetails.setSupportURL(supportURL);
For sample I just setting data from string file but in app its coming from different sources.
But when I tried to access data in different activity its returns null value.
e.g.
public class AboutViewController extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ApplicationDetails appDetails = new ApplicationDetails();
System.out.println(" app support url " + appDetails.getSupportURL());
}
}
output
I/System.out(2242): app support url null
any help.
You get null, because you create a new object and all fields are initialized to zero.
In your case, I see these fields are going to be the same through application, so you can use a Singleton pattern and instantiate only one object for your application and refer to it later on. You don't need to create a new object each time you refer to it. It would be ok for this class and you can also make them constants. (I guess these variables won't change through execution)
As fast solution you can make your supportURL object static, but this isn't good solution.
public class ApplicationDetails {
static String supportURL;
static String companyURL;
static String copyRightText;
// with getter and setter methods
}
better solution is to pass strings from one activity to another with intents, when you are starting your AboutViewController Activity.
You can use the shared preference to store data to be used through your application.
Here the Context in the constructor is nothing but your Activity.
public class ApplicationDetails {
public static final String SUPPORT_URL = "support_url";
public static final String COMPANY_URL = "company_url";
public static final String COPYRIGHT_URL = "copyright_url";
String supportURL;
String companyURL;
String copyRightText;
private Context context;
public ApplicationDetails(Context context) {
super();
this.context = context;
}
private String getPreference(String key)
{
return PreferenceManager.getDefaultSharedPreferences(context).getString(key, null);
}
private void setPreference(String key, String value)
{
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(key, value).commit();
}
public String getSupportURL() {
if(supportURL == null)
supportURL = getPreference(SUPPORT_URL);
return supportURL;
}
public void setSupportURL(String supportURL) {
this.supportURL = supportURL;
setPreference(SUPPORT_URL, supportURL);
}
public String getCompanyURL() {
if(supportURL == null)
supportURL = getPreference(COMPANY_URL);
return companyURL;
}
public void setCompanyURL(String companyURL) {
this.companyURL = companyURL;
setPreference(COMPANY_URL, companyURL);
}
public String getCopyRightText() {
if(copyRightText == null)
copyRightText = getPreference(COPYRIGHT_URL);
return copyRightText;
}
public void setCopyRightText(String copyRightText) {
this.copyRightText = copyRightText;
setPreference(COPYRIGHT_URL, copyRightText);
}
}
Thanks all for all suggestions. Now I am using only one instance of a class.
public class ApplicationDetails {
private static ApplicationDetails instance = null;
String supportURL;
String companyURL;
String copyRightText;
// with getter and setter methods
public static ApplicationDetails getInstance() {
if (instance == null) {
instance = new ApplicationDetails();
}
return instance;
}
}
And I am setting and getting like this
ApplicationDetails appDetails = ApplicationDetails.getInstance();
appDetails.setSupportURL(supportURL);
and in activity
ApplicationDetails appDetails = ApplicationDetails.getInstance();
appDetails.getSupportURL();
Its wrks fine.
Update
As you setting value in Splash screen that object in memory was different and in another activity you creating another object that also different in memory that's why you getting null.
If this was your requirement to init url in splash screen and used in another then there are many ways.
You directly get the string in your activity as you getting in splash screen.
In splash screen make appDetails object as public static so you can access in another activities also
Implement serialization on ApplicationDetails and put this object in putExtra as we put string,int etc value for passing data between activity and get this data using bundle in started activity
Edited
For using single object you need make that object declare as public static in splash screen
public static ApplicationDetails appDetails;
now assign value in splash screen oncreate() and used in another activity or even another class also like this way
public class AboutViewController extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// direct use object by class name
System.out.println(" app support url " + SplashScreen.appDetails.getSupportURL());
}
}

pass class name via context and use it to store static value in different class

The dialogue and the array displays just fine, I just want to be able to set the static variable from the originating class within the onClick that is in a method that is in a different class. All of the try, catch and
<?> were things that I put in at the insistence of the compiler:
public class Setter
{
public void myList(Context context, Class<?> thisclass, int arrayid, String choice)
{
return new AlertDialog.Builder(context)
.setItems(arrayid, new OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
setChoice(thisclass, context, arrayid, which, choice);
}
})
.create();
}
public void setChoice(Class<?> thisclass, Context context, int arrayid, int which, String choice)
{
String[] array = context.getResources().getStringArray(arrayid);
try
{
Field f = thisclass.getDeclaredField(choice);
f.set(null, array[which]);
}
catch (SecurityException e)
{
e.printStackTrace();
}
catch (NoSuchFieldException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
}
public class ClassA extends Activity
{
static String stringa;
Setter setted = new Setter();
...
public void onCreate()
{
super.onCreate();
...
AlertDialog thinga = setted.myList(this, getclass(), R.array.thinga, stringa).show();
...
}
}
When I select an item from the list, I get this from debugger:
ClassCache.findFieldByName(Field[], String) line: 438
Class.getDeclaredField(String) line: 666
Setter.setChoice(Class, Context, int, int, String) line: 45 // the line with the Field
I think I'm passing it the class wrong but this is a bit out of my current depth.
I have a number of different classes each with their own static Strings. I am passing the method below the name of the String (in choice) and the context of what I had hoped was the original class that called a method that called a method that led to the code below. I was hoping I could call context.choice = something and the machine would read that as ClassA.stringa = something; how do I do that?
Briefly, I want to have a list of items that the user can choose from be the content of a dialogue, and have their selection be saved and accessible to the class that called for the creation of the dialogue. Perhaps I'm going about this all wrong but I got tired of dealing with other 'kludges' involving using spinners to do the same thing.
Because onClick can't have non-final objects declared elsewhere (at least that is my understanding) I thought maybe I could get around that by calling to another method, setChoice that would store the value of whatever was chosen. I would definitively say this is a kludge and would love to be shown the light as to how you are supposed to deal with these things.
Java does not have closures, but you can get close with anonymous inner classes.
String output;
public void onCreate() {
Setter.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
output = "selected";
}
});
}
See also this swing tutorial: http://download.oracle.com/javase/tutorial/uiswing/events/actionlistener.html
Edit:
In spirit of your example, this should look like this:
public class Setter
{
public void setChoice(IsetString setter, String something)
{
setter.setString(something);
}
}
class ClassA extends Activity implements setString
{
static String stringa;
string polka = "dots";
Setter setted = new Setter();
...
public void onCreate()
{
super.onCreate();
...
setted.setChoice(new IsetString() {
#Override
public void setString(String s) {
stringa = s;
}
}, polka);
...
}
}
interface IsetString {
void setString(String s);
}
The short answer - use the Reflection API.
The long answer - you'll need to obtain access to the Fields of the desired Context Class. Once you gain access to the Field instances, you can set their values using the set() method; the API call is a bit tricky in that you'll need to pass in the object reference (the context object and not the context class) whose field you wish to modify.
It is necessary that your Context, choice and something parameters to the method, contain the necessary information to make this operation as simple as possible. In other words, the Context class might have to contain the actual Class object (or provides a way to get one) that contains the field.
You can use reflection for that. Suppose you context is class itself
public void setChoice(Class<?> context, String choice, String something)
{
try {
Field f = context.getDeclaredField(choice);
f.set(null, something);
} catch (....) {
}
}
Add proper exception handling
Note that first argument to set is null. That is only valid for static methods. So you may want to check that method is static using f.getModifiers().

Categories