I am developing a Quizz App in which an activity shows question and options from SQLite and on selecting option, another activity is showing result for 2000 ms(it has a timer)and then it calls First Activity via an Intent.
So, Most of the interaction is between 2 activities. But each time my MainActivity is called, it re-initializes all the variables again and again.
I am opening my database connection in onCreate() and also keeping a counter (that can count how many questions have been asked yet) whose value is not retained after the intent from Second Activity. I am worried on how to solve this.
I am a bit confused about the life cycle that is followed. Whether the call to First Activity from Second one starting with onCreate() or it's also initializing the instance variables again.
This is onCreate() method I wrote:
public class MainActivity extends Activity {
protected static final int SCORE_INCREMENT = 5;
TextView question;
Button score, opt1, opt2, opt3;
MyDatabaseManager dbManager;
QuizManager quizManager;
private int quiz_counter =1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbManager = new MyDatabaseManager(getApplicationContext());
dbManager.open();
quizManager = new QuizManager(MainActivity.this, dbManager);
Toast.makeText(MainActivity.this, "Asking The First Question", 0).show();
askQuestion();
}
}
Is there any difference between the above written code and the one I am writing now... if the activity is called again via an Intent
public class MainActivity extends Activity {
protected static final int SCORE_INCREMENT = 5;
TextView question;
Button score, opt1, opt2, opt3;
MyDatabaseManager dbManager = new MyDatabaseManager(getApplicationContext());
QuizManager quizManager = new QuizManager(this, dbManager);
private int quiz_counter =1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(MainActivity.this, "Asking The First Question", 0).show();
askQuestion();
}
}
This might be a silly question. But it's a bit confusing for me. Suggestions are welcome.
If you have variables that you want to maintain between changing activities, then you should either
Store them in SharedPreferences
or
Pass them between the Activites in the Intents (see Starting another activity)
Related
I have a Parent activity that sets a view on Resume based on some check like this :
public class AppLockActivity extends AppCompatActivity {
#BindView(R.id.btnSubmit)
Button submitButton;
private static final String TAG = "AppLockActivity";
private static TimeElapsed timeElapsedInstance;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
timeElapsedInstance = TimeElapsed.getInstance();
timeElapsedInstance.resetTime();
timeElapsedInstance.setStartTime();
}
#Override
protected void onResume() {
super.onResume();
//check if app has passed a time threshold
if(timeElapsedInstance.getStartTime() != 0){
timeElapsedInstance.setEndTime(Calendar.getInstance().getTimeInMillis());
long threshold = timeElapsedInstance.getEndTime()-timeElapsedInstance.getStartTime();
Log.d(TAG,"Threshold : "+threshold);
//Current timeout threshold set to 30s
if(threshold>30000){
setContentView(R.layout.activity_app_lock);
ButterKnife.bind(this);
}else{
}
}
}
#OnClick(R.id.btnSubmit) void onSubmit() {
//destroy current(Parent) view and show the previous
}
}
This activity is extended by other activities like MainAcitivty ,etc...
public class MainActivity extends AppLockActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
}
}
When the app goes in background and is resumed the onResume function is called and based on the check the new View is set - R.layout.activity_app_lock. What I want to do is onClick of the submit button in this view I want to destroy the current view i.e (R.layout.activity_app_lock) and show the previous view that was in the child activity like MainActivity (R.layout.activiyt_main)...
Anybody have any idea how can I do this?
Thanks
You can actually call setContentView again with a different view. All your bindings need to be reset and your On_____Listeners need to be cleared or else you'll get a memory leak. Other than that, it'll be up and ready for you to go.
Though I suggest an alternative approach to changing the layout. Instead, create a new Activity that you start in replacement of the layout your currently submitting. Then, rather than worrying about leaks, you just call finish() on the lock Activity when the user submits. The effect would be the same and it would be more versatile (In my opinion).
sounds stupid but a simple increment counter doesn't work in my android app.
I have two activities in the app and one counter in each, which is incremented each time when onCreate method is called. When I'm switching between the activities the first one works well, but the other one just doesn't count.
I'm using the same line to create the variable like this:
private int mCreate;
Then I'm just incrementing it in the same way in each class in the onCreate method:
mCreate++;
This variable is used in two different classes, so it shouldn't be a problem. This is my first android app, so I need some help.
The whole code of the second activity. I'm not showing the first one because the only difference is in the setOnClickListener method.
public class ActivityTwo extends Activity {
private final static String TAG = "Lab-ActivityTwo";
private int mCreate;
private TextView mTvCreate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
mTvCreate = (TextView) findViewById(R.id.create);
Button closeButton = (Button) findViewById(R.id.bClose);
closeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
Log.i(TAG, "Entered the onCreate() method"); // to check if the inCreate method was called
mCreate++;
mTvCreate.setText("onCreate() calls: " + mCreate);
Log.i(TAG, "mCreate = " + mCreate); // just to check if I implemented the TextView worng
displayCounts();
}
The reason your second counter doesn't work because after finishing an activity all the variables and objects are destroyed and make free by GC. The next time you call for that activity it is created from scratch and your count remain same everytime.
Like #Opoo said if you want to get count you should define static variable in Application class.
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...
I have an activity group and it starts 2 activities. When the user presses a button on one of the activities, the activity group populates an ArrayList.
I am wondering if there is a way to allow both of my activities to access this ArrayList.
Here's what I have at the moment:
public class ExampleGroup extends ActivityGroup {
public static ExampleGroup group;
ArrayList<String> strs = new ArrayList<String>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
group = this;
View exampleView = getLocalActivityManager().startActivity(
"Example",
new Intent(this, Example.class).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP))
.getDecorView();
setContentView(exampleView);
}
public void populateArrayList(){
//code to do it
}
}
public class Example extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
ExampleGroup.group.populateArrayList();
ArrayList<String> strs2 = ExampleGroup.group.strs;
Log.i("ArrayList contents", strs2);
}
}
The arraylist returns null. Is there something I am missing, or is there a better way to do it?
Yes essentially you're wanting to share a model object between two activities, and this has much to do with the structure of your program. See this post for more details on how that can be done:
Where should I put global methods and variables in an Android app?
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.