How to send a Parcelable object to a DialogFragment? - android

I'm able to send my data from Activity1 to Activity2 with the typical..
Intent intent = new Intent(Activity1.this, Activity2.class);
intent.putExtra("state", getIntent().getParcelableExtra("state"));
intent.putExtra("schools", temp);
startActivity(intent);
and that works fine once I'm at the Activity2, the issue is how to make it work from Activity1 to a DialogFragment? How do you send the parcelable objects and retrieve them once I'm coding the DialogFragment? Any example available out there you can point me at?

I think this can help.
Basically by using setArguments() and later getArguments() in the Dialog's onCreate().

Use Bundle to pass Parcelable object to your DialogFragment.
http://developer.android.com/reference/android/os/Bundle.html
(EDIT:)
Let's say you need a TimePicker DialogFragment somewhere in your Activity1:
// This is a static inner class which resides inside your Activity1
// so you will face this limitation :
// You can only access static method from inside this. You also can
// not remove static keyword or you will face memory leak.
public static class StartTimePickerFragment extends DialogFragment
implements TimePickerDialog.OnTimeSetListener {
static StartTimePickerFragment newInstance (int arg, YourParcelableObj obj) {
StartTimePickerFragment DialogFrag = new
StartTimePickerFragment();
Bundle args = new Bundle();
args.putInt("Whatever", arg);
// for Parcelable :
args.putParcelable ("Whatever2", obj);
DialogFrag.setArguments(args);
return DialogFrag;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments().getInt("whatever");
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// now here you can not directly access class methods and
// and data members. so get the Activity object and then
// you are good to 'set/get' them here in your
// DialogFragment
Activity1 activity = (Activity1) getActivity();
activity.your_non_static_method(hourOfDay, minute);
activity.your_non_static_activitidy_member_Data = "whatever";
}
}

Related

Static initializer per Activity (just like Fragment)

We are encouraged to use static initializer (a.k.a. the newInstance() pattern) per Fragment when we are passing arguments. In case of Activity, there is no mentioning of such. And every time we are going to start an activity, we have to first create an Intent first, like below:
public class FirstActivity extends Activity {
...
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
...
}
And if there are some parameters we would like to pass, this gets even more complicated, since we need to give each parameter a name, like below:
public class FirstActivity extends Activity {
...
int age = 10;
int count = 20;
String message = "hello";
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("Age", age);
intent.putExtra("Count", count);
intent.putExtra("Message", message);
startActivity(intent);
...
}
and in the SecondActivity we should retrieve these parameters with the same name:
public class SecondActivity extends Activity {
...
int mAge;
int mCount;
String mMessage;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mAge = getIntent().getIntExtra("Age", 0);
mCount = getIntent().getIntExtra("Count", 0);
mMessage = getIntent().getStringExtra("Message");
}
...
}
Furthermore, these names we have used, "Age", "Count" and "Message" is hard-coded and error-prone. Most of the time we use a helper class, called something like IntentExtraKeys and use names from that class, like below:
public class IntentExtraKeys{
public static final String AGE_KEY = "age_key";
public static final String COUNT_KEY = "count_key";
public static final String MESSAGE_KEY = "message_key";
}
and in the activities:
public class FirstActivity extends Activity{
...
intent.putExtra(IntentExtraKeys.AGE_KEY, age);
...
}
and
public class SecondActivity extends Activity{
...
mAge = getIntent().getIntExtra(IntentExtraKeys.AGE_KEY, 0);
...
}
Instead of this, we could have something like below:
public class FirstActivity extends Activity{
....
SecondActivity.startActivity(this, age, count, message);
...
}
and
public class SecondActivity extends Activity{
...
private static final String AGE_KEY = "age_key";
private static final String COUNT_KEY = "count_key";
private static final String MESSAGE_KEY = "message_key";
public static void startActivity(Context context, int age, int count, String message){
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra(AGE_KEY, age);
intent.putExtra(COUNT_KEY, count);
intent.putExtra(MESSAGE_KEY, message);
context.startActivity(intent);
}
...
}
This way, we save ourselves from writing code for creating an Intent every time we want to start the activity and if we are going to pass some parameters, we don't need to give them name. Only the activity we are starting knows their name, and it looks a lot cleaner, just like in fragments.
Is this bad design? Why is this uncommon?
The static initializer pattern is used in fragments because even though you instantiate the fragment yourself for the first time the default constructor must exist so the platform can instantiate it again on it's own when the activity is rebuilt because of a configuration change.
Activities on the other hand are always instantiated by the system and they must not need any special factory method nor constructor in order to retain their ability to be exported as intents for use by other apps and the system itself; that's why static initializers don't make a whole lot of sense on Activities. They are quite valid though and you can use them if you want but they might complicate having custom initialization code for activities that perform the same function in various slightly-different ways and they create a false sense of coupling.
For fragment
There are some reasons to use static function to create Fragment
Having single point to create Fragment instances. This makes sure the multi Fragment initializing having the same input arguments handling, etc.
It helps developers avoid to create Non-static Nested fragment. Fragment & Activity must be de-coupling.
The utility function can be invoked multi times. For example: The fragment is being used in TabLayout, ViewPager.
For Activity
You can create utility like you did. No problem. It is hard to say it is bad code or uncommon code.
If you will use the function More than one Or the Activity has input arguments. You can create the Utility function like you did.

Call a method from an activity to a fragment of another activity. What is the proper way?

This might have already answered but I am still troubling with a function like this. Let's say I have activity A and activity B. B holds a viewpager with several fragments in it. I would like to call a function in the fragment held by activity B from activity A.
I used callbacks many times to communicate between activites and fragments but every single time it was only the fragment and its holder activity. I do not want to make a static method (the callback listener cannot be static anyway) so it causes a headache for me. The simple static solution to make a static method in the fragment and have it called from the other actually works very well, but I am not sure if it was a good idea as I need to change several things static.
So communicating between Activity B and its fragments is ok, but I cannot call this method in Activity A.
Activity B:
public class ActivityB extends FragmentActivity implements Fragment1.OnWhateverListener
{
...
#Override
public void onWhateverSelected(int position) {
//stuff, here I can call any function in Fragment 1
}
}
The following code snippet is a wrong solution (doesnt even work) but makes a better picture what I would like to do.
Activity A:
ActivityB ab = new ActivityB ();
ab.onWhateverSelected(number);
So how can I do this?
Thank you!
EDIT
Activity A: the method I call
Bundle args = new Bundle();
args.putString("ID", id); // the data to send
Intent frag_args = new Intent(Intent.ACTION_VIEW);
frag_args.setClass(this, MainActivity.class);
frag_args.putExtra("args", args);
startActivity(frag_args);
Activity B:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
...
processIntent(getIntent()); //last line of onCreate, always gets called here
}
#Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processIntent(intent); // this never gets called here only in OnCreate
}
private void processIntent(Intent intent) {
Bundle args = intent.getBundleExtra("args");
if (args != null) { // check if ActivityB is started to pass data to fragments
String id = args.getString("ID");
Log.i("ID_FROM", "id: " + id); //works well
if (id != null) {
List<Fragment> fragments = new ArrayList<Fragment>();
fragments = getSupportFragmentManager().getFragments();
//NULLPOINTER for the following line
FragmentMainDiscover fr = (FragmentMainDiscover) fragments.get(0);
fr.RefreshHoverView(id);
}
}
}
You are right to stay away from statics. Way too risky, for visual objects that may or may not be on screen.
I would recommend going through activity B, since it is the parent of your target fragment. Create an Intent that starts activity B, and include an intent extra that tells activity B what it should do to the target fragment. Then activity B can make sure that the fragment is showing, and pass the information on to it.
One other idea to pass the info to the fragment is to use setArguments, rather than direct calls. This is a nice approach because Android will restore the arguments automatically if the activity and its fragments are removed from memory.
Does this make sense? Do you want the code?
EDIT
To use arguments, you still need to have activity A go through activity B. This is because activity A doesn't know if activity B, and all its fragments, is running unless it sends it an Intent. But you can include data targeted for the fragments, by putting them inside the intent. Like this:
public class ActivityA extends Activity {
public static final String KEY_FRAG = "frag"; // tells activity which fragment gets the args
public static final String KEY_ARGS = "args";
public static final String KEY_MY_PROPERTY = "myProperty";
public void foo() {
Bundle args = new Bundle();
args.putString(KEY_FRAG, "frag1Tag"); // which fragment gets the data
args.putCharSequence(KEY_MY_PROPERTY, "someValue"); // the data to send
// Send data via an Intent, to make sure ActivityB is running
Intent frag_args = new Intent(Intent.ACTION_VIEW);
frag_args.setClass(this, ActivityB.class);
frag_args.putExtra(KEY_ARGS, args);
startActivity(frag_args);
}
}
public class ActivityB extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//TODO configure activity including fragments
processIntent(getIntent()); // this call is in case ActivityB was not yet running
}
#Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processIntent(intent); // this call is in case ActivityB was already running
}
private void processIntent(Intent intent) {
Bundle args = intent.getBundleExtra(ActivityA.KEY_ARGS);
if (args != null) { // check if ActivityB is started to pass data to fragments
String fragTag = args.getString(ActivityA.KEY_FRAG);
if (fragTag != null) {
Fragment frag = getSupportFragmentManager().findFragmentByTag(fragTag);
frag.setArguments(args);
//TODO either show the fragment, or call a method on it to let it know it has new arguments
}
}
}
}
public class Fragment1 extends Fragment {
public static final String TAG = "frag1Tag";
#Override
public void onResume() {
super.onResume();
Bundle args = getArguments();
String value = args.getString(ActivityA.KEY_MY_PROPERTY);
...
}
}

How to pass/share object from fragment to fragment?

I want to pass realtime object from fragment to fragment.
I dont want to pass data.
I dont found way to do that.
The only way that I think is by intent but I am not sure.
i read about Singleton pattern,interfaces and Bundle,Global varible.
I would like to see example if it is possible to use share/pass object from one fragment to secend fragment. many Thanks.
Passing real objects between activities or fragments can be achieved through implementing model beans Parcelable or Serializable interface.
Parcelable: A Parcel is similar to a Bundle, but is more sophisticated and can support more complex serialization of classes. Applications can implement the Parcelable interface to define application-specific classes that can be passed around, particularly when using Services.
You can see how to implement Parcelable interface in this article here.
public class Foo implements Parcelable {
...
}
Serializable: A serializable interface is java standard serialization. You can read more about it here.
public class Foo implements Serializable {
private static final long serialVersionUID = 0L;
...
}
Suppose you have a class Foo implements Parcelable properly, to put it into Intent in an Activity:
Intent intent = new Intent(getBaseContext(), NextActivity.class);
Foo foo = new Foo();
intent.putExtra("foo", foo);
startActivity(intent);
To get it from intent in another activity:
Foo foo = (Foo) getIntent().getExtras().getParcelable("foo");
** EDIT **
As the original question asked for Fragments, then this is how it works:
Fragment fragment = new Fragment();
Foo foo = new Foo();
Bundle bundle = new Bundle();
bundle.putParcelable("Foo", foo);
fragment.setArguments(bundle);
To get it from bundle in another fragment:
Foo foo = (Foo) bundle.getParcelable("Foo");
Hope this helps!
Pass object from one Fragment to another Fragment can be acheived by using these simple steps:
First of all, you have to make your model class as Parcelable:
class Car implements Parcelable
Then implements the override functions of Parcelable class: e-g
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
}
From First Fragment:
// Set data to pass
MyFragment fragment = new MyFragment(); //Your Fragment
Car car = new Car(); // Your Object
Bundle bundle = new Bundle();
bundle.putParcelable("carInfo", car) // Key, value
fragment.setArguments(bundle);
// Pass data to other Fragment
getFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment)
.commit();`
On Second Fragment
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = this.getArguments();
if (bundle != null) {
Car receivedCar = bundle.getParcelable("carInfo"); // Key
}
}
Hope it will help :)
There is another method you can pass object by just making a simple setter function.
From your current fragment make object of target fragment. Your target fragment should have a setter function like
public void setObjectFunction(Object obj){this.mObj = obj}
YourFragment yourFragment = new YourFragment();
Object passingObj = new Object();
yourFragment.setObjectFunction(passingObj);
Then
getFragmentManager()
.beginTransaction()
.replace(R.id.container, yourFragment)
.commit();`

send data to fragment from another activity in android

I have an activity which is a container for several fragments. One of the fragments starts another activity and from the second activity I want to send some data to one of the fragments. How can I do that? Basically the first activity stays beyond the second one and one of the EditViews will be updated with a new value when the second activity closes. I could've used an intent but how can I send it if the activity is already started? Thank you.
You would need to start your second activity using startActivityForResult(). In your second activity before you finish it, you need to add the data to a bundle pass this to an intent and then set the result to the intent.
Bundle bundle = new Bundle();
bundle.putString("myData", "myValue");
Intent intent = new Intent();
intent.putExtra(bundle);
setResult(intent, 0);
finish();
And then in activity 1 there should be an onactivityresult method which retrieves the value from the intent and sets it where you want in your fragment
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Bundle bundle = data.getData();
string value = bundle.getString("myData");
}
I'm not sure if I have it exactly right as remembering it at the top of my head but should be enough to get you started I think.
If you want to pass data back to its containing activity from your fragment, can do it by declaring an interface handler and through that interface pass the data. And ensure your containing activity implements those interfaces.
For example: In your fragment, declare this interface as follows :
public interface CallBackInterface {
public void onCallBack(String param);
}
//Declare this interface in your fragment
CallBackInterface callBk;
#Override
public void onAttach(Activity a) {
super.onAttach(a);
callBk= (CallBackInterface ) a;
}
Within your fragment, when you need to handle the passing of data, just call it on the "callBk " object:
public void callBack(String param) {
callBk.onCallBack(param);
}
Finally, in your containing activity which implements CallBackInterface ...
#Override
public void onCallBack(String param) {
Log.d("TAG","hi " + param);
}

how to pass 2D Array as a parameter to another Activity?

how to pass 2D Array as a parameter to another Activity?? i try it stack over flow solution but is not work im using this code
in activity 1 is correctly show value in this line bundle.putSerializable("xmlResponee", xmlRespone);
but is not showe value in activity2 class what is wrong? tell me please
public class Activity1 extends Activity {
private String[][] xmlRespone;
Intent i = new Intent(this.getApplicationContext(), Activity2.class);
Bundle bundle = new Bundle();
bundle.putSerializable("xmlResponee", xmlRespone);
i.putExtras(bundle);
startActivity(i);
and
public class Activity2 extends Activity {
private String[][] xmlRespone;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity2);
Bundle bundle = getIntent().getExtras();
String[][] xmlRespone2 = (String[][]) bundle.getSerializable("xmlResponee");
You can make a static class.. with private String[][] xmlRespone. in first Activity you can Assign value to it,and in another activity you can call data from it..
Activity A ---> Static class X ---> Activity B.
Hey just use Parcelable objects to pass objects between android activities.
Here is a really awesome example. I guess this is the same thing you want to achieve.
You can put it directly on the intent no need bundle.
Intent intent = new Intent();
intent.putExtra("MyXML", xmlRespone);
And to read:
#Override
public void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
String[] xmlRespone = intent.getStringArrayExtra("MyXML");
}

Categories

Resources