Static initializer per Activity (just like Fragment) - android

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.

Related

Android : Can't put a string through an intent from a fragment to an activity

I'm new in android development and I have an issue with simple string in an intent.
I create an Intent in a fragment to launch a new activity. I have no error but I can't put a string through the intent.
Here is my code :
public class AboutFragment extends Fragment {
private static Context mContext;
I have this in the onCreateView method :
mContext = this.getContext();
This method in the same class
public static void openModalPolicy() {
Intent intent = new Intent(mContext, ModalActivity.class);
intent.putExtra("section", "policy");
mContext.startActivity(intent);
}
And in my new activity :
String section = this.getIntent().getStringExtra("section");
So the problem is that section is never equal to "policy"
If someone can help me :) Have a good day !
Just to be sure, you are using section.equals("policy") for your equality check.
Not section == "policy". Right?
Check out this post for more information: How do I compare strings in Java?

pass data from activity one to activity three directly while going through activity two but data should not be passed to activity two

I have three activities A,B and C. I need to pass some data from activity A to activity C. But the navigation is from A to B to C i.e. I can't go to activity C from activity A directly. I don't want to pass my data to activity B from A and I don't want to use any external storage like sqlite or shared preferences. Can it be done through intent ? If yes , how ? If no, is there any other way ?
use Interface to communicate with other Activity.
or you can make your variable public static on Activity1
The problem is that your third activity has no way of knowing which activity sent the bundle. You need to add a field that identifies what type of bundle this is so you can process accordingly. For instance, in activity 1:
Intent i = new Intent(ActivityOne.this, ActivityTwo.class);
i.putExtra("activity", (int)1);
i.putExtra("key", value);
startActivity(i);
Then in 3rd activity:
Bundle extras = getIntent().getExtras();
if(extras !=null) {
int typeAct = extras.getInt("activity");
if (typeAct == 1) {
//do something with data
}
There are various ways to send the data from one activity to other activity,
Now as you can not use intent so I would suggest you to go with either Application class or create a Global singleton class to hold your data.
Please refer following link
https://androidresearch.wordpress.com/2012/03/22/defining-global-variables-in-android/
Following are the steps to create an application class:
Step 1: Create any class and extend it with the Application class:
public class Globals extends Application{
private int data=200;
public int getData(){
return this.data;
}
public void setData(int d){
this.data=d;
}
}
Step 2: Defining the application class in the manifest file:
<application
android:name=".Globals"
.... />
Step 3:Now by calling getApplication() in any of the activity you get your application class. Just typecast it and call the methods required.
Globals g = (Globals)getApplication();
int data=g.getData();
I hope this will help.
make one interface :
public interface PassData {
public void data(String data);
}
if you want to pass the data from activity A to activity C then :
from Activity A you need to pass the data like this:then on Activity A.
PassData passData;// make it global variable
passData.data("Your DATA WHICH YOU WANT TO SEND TO ACTIVITY C");
In Activity C :
ActivityC extends AppCompatActivity implements PassData{
//onCreate Stuff
#Override
public void data(String data) {
// print this data and see it's coming or not
}
yes sure.
for example in your Activity
class ActivityA extend Activity{
public static String abc = "hello";
}
in ActivityC
ActivityC extend Activity{
onCreate(){
String a = ActivityA.abc;
Log.d("test",a);
}
}

How to pass data from fragment to ActionBarActivity?

I have PatientList class that extends fragment and other AddPatient class that extends ActionBarActivity. Now i want to pass static string from PatientList to AddPatient then its getting null.Where is the problem?? Why it is getting null???
not sure if I'm understanding but you can add a method in AddPatient and within PatientList call ((AddPatient) getActivity()).yourmethod(string)
in AddPatient:
public receiveString(String mystring)
{
// do whatever with mystring
}
in PatientList where needed e.g. onClick or something
((AddPatient) getActivity()).receiveString("hello")
if you want to pass data to an Activity you are starting with startActivity() instead you should do something like (if you are inside a fragment)
Intent intent = new Intent(getActivity(), AddPatient.class);
intent.putExtra("param_string", mystring)
getActivity().startActivity(intent);
in AddPatient
private String mMyString;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.yourlayout);
mMyString = getIntent().getStringExtra("param_string");
}
you can add Integer, Strings and Serializable stuff, multiple times
Instead of some dark magic proposed by #sherpya you should check how it is done by google at http://developer.android.com/training/basics/fragments/communicating.html
You should create an interface that is for that instead of creating dependency upon concrete Activity. What if you decide later to reuse this fragment in another Activity ?
In same cases you can use some event bus http://square.github.io/otto/

Share the object on real-time, singeltond pattern

I simply have not found a solution to share a real-time data between the activitys. My first activity receives real-time object (type double, a random numbers). And i want to pas this numbers to second activity. It all works, only the second Activity shows only one time the data. I have to refresh the activity by going back to first activity and only then the second activity show the latest data. I implemented a Singelton pattern:
public class FirstActivity extends Activity{
public double xAxis;
public double yAxis;
public static FirstView instance;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_view);
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
int data1 = msg.arg1;
xAxis = (double) data1;
dataX.setText(String.valueOf(xAxis));
int data2 = msg.arg2;
yAxis = (double) data2;
dataY.setText(String.valueOf(yAxis));
}
};
secondview.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent nextScreen = new Intent(getApplicationContext(),
SecondActivity.class);
startActivity(nextScreen);
}
});
}
public static void initInstance(){
if(instance == null)
{
instance = new FirstActivity();
}
}
public static FirstActivity getInstance(){
return instance;
}
}
SecondView class
public class SecondActivity extends Activity{
private double valueX;
private double valueY;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.linegraph);
valueX = FirstActivity.getInstance().xAxis;
valueY = FirstActivity.getInstance().yAxis;
}
}
Application class
package com.bluetoothcomm;
import android.app.Application;
public class MyApplication extends Application {
#Override
public void onCreate(){
super.onCreate();
initSingeltons();
}
public void initSingeltons(){
FirstActivity.initInstance();
}
}
You may implement a background service capable of providing the real time data to Activity1 and also to Activity2. I am guessing that your problem ocurrs if you are passing data from Activity1 to Activity2 through an Intent with putExtras, on this way it will only do this at the moment you start Activity2.
I have found my problem and the solution is to use Application. Only this dose not solves my problem. The problem is that the static variable instance public static FirstView instance is bound to the class loader, the first class that initilize that. So when the static variable inside any class has been initilized by an Activity and when the second Activity is started the first Activity is destroyed, so this means the static variable is also uninitilized. Thats why the SecondActivity dose not gets the up to date data or real time data, it catches only static constant data.
I changed my code a littele bit with the combination of Singelton and Application, couse this way the static variable should never be uninitilized when SecondActivity is activated. But i still get the same results, the static variable instance is uninitilized when i swtich to Second Activity. I am doing somethink wrong, does any one sees it. I added my code.
#Max Rasguido, #Orabig
You should use the intent process. docs
How is your data supposed to change when activity2 is shown, if you say that it's received by activity1 ?
However, I would use a preference, or an attribute of your application class (which is a singleton itself), but you give too little informations to fully understand your needs...

Where is the memory leak?

my dear friends. Could you help me to figure out where do I have memory leak in my application.
There are two activities.
In first activity I'v got a rather big static ArrayList consists of bitmaps and another needed information. I made it static, because I need to take it from another activity, and It's loading takes to much time.
In another activity, I also have one static field, using as a key for getting data which present in an Intent from previous activity.
If I try to start one activity from another and go back several times, I get shutting down VM.
To be more clear, here is a snippet of my code:
public class MoviesGallery extends Activity
{
...
private static ArrayList<Movie> films = new ArrayList<Movie>();
...
public void contextButtonsClickHandler(View v)
{
switch(v.getId())
{
case R.id.play_button:
Log.d("Context Button", "Play button has clicked");
mContextButtonHasPressed = true;
Intent filmData = new Intent(MoviesGallery.this, MovieInfo.class);
filmData.putExtra(MovieInfo.mPOS,mPOSITION_OF_CLICKED_ITEM);
startActivityForResult(filmData, 1);
break;
...
}
And this is another activity:
public class FilmInfo extends Activity
{
public static String mPOS = "pos";
private int mNumOfFilm = -1;
private LinearLayout mWall;
...
protected void onCreate(Bundle savedInstanceState)
{
Bundle extra = getIntent().getExtras();
mNumOfFilm=extra.getInt(mPOS);
...
Drawable d = new BitmapDrawable(MoviesGallery.getMoviesArray().get(mNumOfFilm).getWall()));
mWall = (LinearLayout) findViewById(R.id.Wall);
mWall.setBackgroundDrawable(d);
...
setResult(0);
}
I would suggest that potentially memory-leak point is in FilmInfo class member:
private LinearLayout mWall;
Layout has reference to Activity, which each time changes.
So to avoid keeping reference to dead Activity just use in FilmInfo class
#Override
public boolean onContextItemSelected(MenuItem item)
{
//blah-blah
mWall=null;
}
Anyway recipe is simple - try to avoid keeping objects which might contain references to Activity/Context objects.

Categories

Resources