Initializing variables in onCreate, but updating them in onResume() - java

Here is my situation:
I have an OnCreate code like the following:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bunz = Bunz.getInstance(); //getting instance of bunz
bunz.setBunz(50);
bunz.setMoney(0);
bunz.setIncrement(1);
Button upgradeButton = (Button) findViewById(R.id.upgradeButton);
upgradeButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
Intent startIntent = new Intent(getApplicationContext(), UpgradeMenu.class);
startActivity(startIntent);
}
});
moneyCount = (TextView) findViewById(R.id.moneyCount);
bunzCount = (TextView) findViewById(R.id.bunzCount);
ImageButton bun = (ImageButton) findViewById(R.id.bun);
}
Notice how in my OnCreate code, I do 2 things; first, I initialize all the values I need:
bunz.setBunz(50);
bunz.setMoney(0);
bunz.setIncrement(1);
and then I display these values on TextViews and set up some Buttons and intents:
Button upgradeButton = (Button) findViewById(R.id.upgradeButton);
upgradeButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
Intent startIntent = new Intent(getApplicationContext(), UpgradeMenu.class);
startActivity(startIntent);
}
});
moneyCount = (TextView) findViewById(R.id.moneyCount);
bunzCount = (TextView) findViewById(R.id.bunzCount);
ImageButton bun = (ImageButton) findViewById(R.id.bun);
I'm new to Android studio, and here is the problem I'm having. I want to use onResume() to update these values in the TextView (I update them in another activity) every time I go back to this activity. However, if I move all the code in onCreate into onResume, then every time I go back to this activity, the values will be set to 50,0, and 1. I understand I could use a boolean, so that onCreate() triggers the first time the app is launched, but onResume() doesn't trigger, and then onResume() triggers after that, and simply copy and paste the second half of the onCreate code into onResume(), but that seems inefficient, and isn't how Android studio is designed to work. Can I somehow initialize the values in another location?
I have a global Bunz class that looks like the following:
public class Bunz {
private int bunz;
private int money;
private int increment;
//singleton code
private static Bunz instance;
private Bunz(){
}
public static Bunz getInstance(){
if (instance == null){
instance = new Bunz();
}
return instance;
}
public int getBunz() {
return bunz;
}
public void setBunz(int num){
bunz = num;
}
public int getMoney(){
return money;
}
public void setMoney(int num){
money = num;
}
public int getIncrement(){
return increment;
}
public void setIncrement(int num){
increment = num;
}
}
so maybe I could initialize these values here somehow?
Thanks!

here's one thing you could alternatively do:
public static Bunz getInstance(){
if (instance == null){
instance = new Bunz();
instance.setBunz(50);
instance.setMoney(0);
}
return instance;
}
in your instance creation here, try setting the values you want here, instead of in onCreate of the app.
you could just be making the changes in the constructor as well.

While your code uses statics, which I believe is unnecessary. Statics are not your average goto solution, they come with a hefty price of an object not eligible for GC.
You can get the result from the second activity via onActivityResult method.
First, start second activity using startAtivityForResult() //This takes in a request code(Int), it can be whatever you set.
First activity
Intent intent = new Intent(this, SecondActivity.class);
startActivityForResult(intent , 100);
Second Activity
//Do you work in the second activity, generate new data
Intent returnIntent = new Intent();
returnIntent.putExtra("bunz", 100);
returnIntent.putExtra("money", 200);
returnIntent.putExtra("increment", 2);
setResult(Activity.RESULT_OK, returnIntent);
finish();
Capture Second Activity Result
This code is supposed to be written in your first activity.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100) { //Remember the code we set in startActivityForResult? This is where we identify our work
if(resultCode == Activity.RESULT_OK){ //Code to check if data is passed
Int bunz =data.getIntExtra("bunz")
bunz.setBunz(bunz)
.....
}
}
}

Related

Android resume activity variables gone

Short:
I have Three classes: A (MainActivity), B (Secondary), C(Third).
A is parent of B is parent of C.
In A I make an Intend with Extra int idForUsage on B. B stores idForUsage in a variable int chosenId(works fine).
B does Stuff and makes an Intent with Extra int chosenId and int secondIdForUsage(works also fine).
C does Stuff and it works all fine.
When I´m now clicking the litte "back button" in the upper left corner to get to the parent activity the app crashes because I´m trying to access the Variable chosenId which seems to being set to default -1 (even if I´m trying to read the Extra again.)
public class MainActivity extends AppCompatActivity {
//references to Buttons etc
...
public static final String ChosenID = "com.example.Abzeichenschwimmer.ChosenSwimmerID";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//set up button stuff
...
//ListView which has clickable Items which trigger the Activity
lv_swimmerList = findViewById(R.id.lv_schwimmerListe);
//Listeners
lv_swimmerList.setOnItemClickListener(this::onListViewItemClick);
}
#Override
protected void onResume(){
super.onResume();
updateSchwimmerliste(dataBaseHelper);
}
public void onListViewItemClick(AdapterView<?> parent, View view, int position, long id) {
SchwimmerModel clickedSchwimmer = (SchwimmerModel) parent.getItemAtPosition(position);
Intent intent = new Intent(MainActivity.this, DisplaySchwimmer.class);
//Toast.makeText(MainActivity.this, String.valueOf(clickedSchwimmer.getId()), Toast.LENGTH_SHORT).show();
intent.putExtra(ChosenSwimmerID, clickedSchwimmer.getId());
startActivity(intent);
}
}
public class DisplaySchwimmer extends AppCompatActivity {
int chosenSwimmerID;
public static final String SchwimmerID = "com.example.Abzeichenschwimmer.schwimmerID";
public static final String AufgabenID = "com.example.Abzeichenschwimmer.aufgabenID";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_schwimmer);
lv_exc = findViewById(R.id.lv_aufgaben);
refreshValues();
showAufgabenOnListView(dataBaseHelper);
lv_exc.setOnItemClickListener(this::onListViewItemClick);
}
public void getIntentExtra(){
Intent intent = getIntent();
chosenSwimmerID = intent.getIntExtra(MainActivity.ChosenSwimmerID,-1);
}
public void onDeleteClick(View view){
SchwimmerModel toDeleteSwimmer = (SchwimmerModel) dataBaseHelper.getSchwimmerByID(chosenSwimmerID);
dataBaseHelper.deleteSchwimmer(toDeleteSwimmer);
Toast.makeText(this, "deleted", Toast.LENGTH_SHORT).show();
DisplaySchwimmer.this.finish();
}
public void refreshValues(){
getIntentExtra();
SchwimmerModel schwimmer = dataBaseHelper.getSchwimmerByID(chosenSwimmerID); <--- Main Error
}
private void showAufgabenOnListView(DataBaseHelper dataBaseHelper) {
getIntentExtra();
ArrayAdapter<ExcerciseModel> schwimmerArrayAdapter = new ArrayAdapter<ExcerciseModel>(DisplaySchwimmer.this, android.R.layout.simple_list_item_1, dataBaseHelper.getExcersisesForSwimmerByID(chosenSwimmerID));
lv_exc.setAdapter(schwimmerArrayAdapter);
}
public void onListViewItemClick(AdapterView<?> parent, View view, int position, long id) {
ExcerciseModel clickedExcerciseModel = (ExcerciseModel) parent.getItemAtPosition(position);
Intent intent2 = new Intent(DisplaySchwimmer.this, DisplayAufgabe.class);
intent2.putExtra(SchwimmerID, chosenSwimmerID);
intent2.putExtra(AufgabenID, clickedExcerciseModel.getId());
Log.e("aaa", String.valueOf(chosenSwimmerID));
startActivity(intent2); <-- Intentstart
}
#Override
protected void onResume(){
super.onResume();
showAufgabenOnListView(dataBaseHelper);
}
}
I hope the code (deleted many lines) is ok for an overview. Maybe someone knows the solution for this.
Thanks Maximus
When you press back from DisplayAufgabe to DisplaySchwimmer (the intent always is null)
Because you call getIntent di DisplaySchwimmer, you will get default value which is -1 (null intent extra)
When you try to call dataBaseHelper.getSchwimmerByID(chosenSwimmerID); is mean you try to get index -1 on database. You will always get error because accessing index -1.
My Suggestion
Add validation before call dbHelper i.e
if (chosenSwimmerID > -1){
SchwimmerModel schwimmer = dataBaseHelper.getSchwimmerByID(chosenSwimmerID);
}
Only getExtra when value available
if (intent.hasExtra(MainActivity.ChosenSwimmerID)){
chosenSwimmerID = intent.getIntExtra(MainActivity.ChosenSwimmerID,-1);
}
It all boiled down on using sharedPreferences. This helped a lot. A Second post from me explanined this problem more simplified and I found a solution.

Android memory leak on device, not on emulator

I'm writing a game to help teach my son some phonics: it's my first attempt at programming in Java, although I've previously used other languages. The game has four activities: a splash screen which initializes an array of variables before you dismiss it; another to choose a user; a third to choose which level of the game to play; and a fourth to actually play the game.
My problem was that if you go in and out of the game activity repeatedly, that activity would eventually crash -- logcat showed an OOM error. Watching the heap size as I did this, and looking at a heap dump with MAT, it looked as though I was leaking the whole of the fourth activity -- GC was just not being triggered.
I've tried lots of things to track down and fix the leak -- most of which are, I'm sure improvements (e.g. getting rid of all non-static inner classes from that activity) without fixing the problem. However, I've just tried running the same thing on an emulator (same target and API as my device) and there's no leak -- heap size goes up and down, GC is regularly triggered, it doesn't crash.
So I was going to post the code for the activity on here and ask for help spotting what might be causing the leak, but I'm no longer sure that's the right question. Instead I'm wondering why it works on the emulator, but not the phone... Does anyone have any ideas?
IDE: Android Studio 2.1
Target: Android 6, API 23 (Minimum SDK 8)
Emulator: Android Studio
Device: Sony Xperia Z2 (Now running 6.0.1, but I had the same issue pre recent update, i.e. on API 22)
Code for the activity:
public class GameActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {
//TTS Object
private static TextToSpeech myTTS;
//TTS status check code
private int MY_DATA_CHECK_CODE = 0;
//LevelChooser request code
public static Context gameContext;
private int level;
public static String user;
private Typeface chinacat;
public static Activity gameActivity = null;
private static int[] goldstars = {R.drawable.goldstar1, R.drawable.goldstar2, R.drawable.goldstar3};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
gameActivity = this;
gameContext = this;
level = getIntent().getIntExtra("level", 1);
user = getIntent().getStringExtra("user");
chinacat = Typeface.createFromAsset(getAssets(), "fonts/chinrg__.ttf");
Intent checkTTSIntent = new Intent();
checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);
}
#Override
public void onStop() {
if (myTTS != null) {
myTTS.stop();
}
super.onStop();
}
#Override
public void onDestroy() {
if (myTTS != null) {
myTTS.shutdown();
}
Button ok_button = (Button) findViewById(R.id.button);
ok_button.setOnClickListener(null);
ImageView tickImageView = (ImageView) findViewById(R.id.tickImageView);
tickImageView.setOnClickListener(null);
super.onDestroy();
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
myTTS = new TextToSpeech(this, this);
} else {
Intent installTTSIntent = new Intent();
installTTSIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installTTSIntent);
}
}
}
public void onInit(int initStatus) {
//if tts initialized, load layout and level and assign listeners for layout elements
if (initStatus == TextToSpeech.SUCCESS) {
myTTS.setLanguage(Locale.ENGLISH);
setContentView(R.layout.activity_main);
ImageView imageView = (ImageView) findViewById(R.id.myImageView);
PhonemeGroup levelGroup = MainActivity.gamelevel[level]; //set possible words
levelGroup.setSubset(); //randomize subset of possible words for actual test
PhonicsWord[] testSet = levelGroup.getSubset(); //fill array of test words
TextView[] targetView = new TextView[3]; //textviews for beginning, middle & end of word
targetView[0] = (TextView) findViewById(R.id.targetWord0);
targetView[1] = (TextView) findViewById(R.id.targetWord1);
targetView[2] = (TextView) findViewById(R.id.targetWord2);
TextView[] answersView = new TextView[3]; //textviews for possible user answer choices
answersView[0] = (TextView) findViewById(R.id.letter0);
answersView[1] = (TextView) findViewById(R.id.letter1);
answersView[2] = (TextView) findViewById(R.id.letter2);
//set first target word, image for word, and possible answers
testSet[0].setWord(levelGroup, targetView, answersView, imageView);
testSet[0].speakWord(myTTS);
//subset index is equal to array index for testSet, but visible to & settable by methods
levelGroup.setSubsetIndex(0);
for(int i=0; i<3; i++) {
answersView[i].setTypeface(chinacat);
}
TextView letter0 = (TextView) findViewById(R.id.letter0);
letter0.setOnClickListener(new LetterOnClickListener(testSet, levelGroup, targetView, answersView, 0) );
TextView letter1 = (TextView) findViewById(R.id.letter1);
letter1.setOnClickListener(new LetterOnClickListener(testSet, levelGroup, targetView, answersView, 1) );
TextView letter2 = (TextView) findViewById(R.id.letter2);
letter2.setOnClickListener(new LetterOnClickListener(testSet, levelGroup, targetView, answersView, 2) );
Button ok_button = (Button) findViewById(R.id.button);
ok_button.setOnClickListener(new OKButtonOnClickListener(testSet, levelGroup, targetView, level) );
ImageView tickImageView = (ImageView) findViewById(R.id.tickImageView);
tickImageView.setOnClickListener(new TickClick(myTTS, testSet, levelGroup, targetView, answersView, imageView) );
imageView.setOnClickListener(new WordImageClick(testSet, levelGroup) );
}
/*else if TODO*/
}
private static class WordImageClick implements View.OnClickListener {
//speaks the test word when the test image is clicked
PhonicsWord[] testSet;
PhonemeGroup levelGroup;
public WordImageClick(PhonicsWord[] testSet, PhonemeGroup levelGroup) {
this.testSet = testSet;
this.levelGroup = levelGroup;
}
#Override
public void onClick(View view) {
testSet[levelGroup.getSubsetIndex()].speakWord(myTTS);
}
}
private static class LetterOnClickListener implements View.OnClickListener {
PhonemeGroup levelGroup;
PhonicsWord currentWord;
PhonicsWord[] testSet;
TextView[] targetView;
TextView[] answersView;
int item;
int phonemeclicked;
public LetterOnClickListener(PhonicsWord[] testSet, PhonemeGroup levelGroup, TextView[] targetView, TextView[] answersView, int phonemeclicked) {
this.testSet = testSet;
this.levelGroup = levelGroup;
this.targetView = targetView;
this.answersView = answersView;
this.phonemeclicked = phonemeclicked;
}
#Override
public void onClick(View view) {
this.item = this.levelGroup.getSubsetIndex();
this.currentWord = this.testSet[item];
int i = currentWord.getOmit_index();
targetView[i].setText(answersView[phonemeclicked].getText());
}
}
private void crossClick(View view) {
view.setVisibility(View.INVISIBLE);
if(view.getTag()==4){
finish();
}
}
The static variable gameActivity is used so that when you've finished a level an external class can call GameActivity.gameActivity.finish() after it's displayed how many stars you've got for the level (it's also used to call GameActivity.gameActivity.findViewById in another external class).
public class ShowStarsWithDelay extends Handler {
public void handleMessage(Message msg) {
ImageView starView = (ImageView) ((LevelEndScreens) msg.obj).starView;
ImageView highscoreView = (ImageView) ((LevelEndScreens) msg.obj).highscoreView;
int num_currentstars = (int) ((LevelEndScreens) msg.obj).num_currentstars;
int num_finalstars = (int) ((LevelEndScreens) msg.obj).num_finalstars;
Boolean highscore = (Boolean) ((LevelEndScreens) msg.obj).highscore;
int[] goldstars = (int[])((LevelEndScreens) msg.obj).goldstars;
if(num_currentstars == num_finalstars) {
if(!highscore) {
starView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
GameActivity.gameActivity.finish();
}
});
}
else {
highscoreView.setImageResource(R.drawable.highscore);
highscoreView.setVisibility(View.VISIBLE);
highscoreView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
GameActivity.gameActivity.finish();
}
});
}
}
else {
starView.setImageResource(goldstars[num_currentstars++]);
Message message = new Message();
LevelEndScreens endScreens = new LevelEndScreens(starView, highscoreView, num_currentstars, num_finalstars, highscore, goldstars);
message.obj = endScreens;
this.sendMessageDelayed(message, 1000);
}
}
}
In general, you want to avoid having any static reference to a Context anywhere in your application (this includes Activity classes, of course). The only reference to a Context which MAY be acceptable is referencing the application context (as there is only one and it is always in memory while your app is alive anyway).
If you need a reference to the calling activity in one of your children, you'll need to pass the context as a parameter, or else use one of the child views methods to retrieve the context (such as getContext() for views and fragments).
More information that should help understand memory leaks and why this is important is here:
http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
As an example, in your code for calling finish(), you could safely change it to this:
highscoreView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getContext() instanceof Activity) {
((Activity)v.getContext()).finish();
}
}
});
To sum up, in order to fix your memory leaks, you'll need to remove the static keyword for all of your Context fields.

setText on button from another activity android

I have a problem, I want to click on the list, calling a new activity and rename the button to another name.
I tried several things, nothing worked, can someone please help me?
My class EditarTimes:
private AdapterView.OnItemClickListener selecionarTime = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView arg0, View arg1, int pos, long id) {
t = times.get(pos);
CadastroTimes cad = new CadastroTimes();
CadastroTimes.salvar.setText("Alterar");
Intent intent = new Intent(EditarTimes.this, CadastroTimes.class);
startActivity(intent);
}
};
public class CadastroTimes extends AppCompatActivity {
private Time t;
private timeDatabase db;
private EditText edID;
private EditText edNome;
public Button salvar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cadastro_times);
edID = (EditText) findViewById(R.id.edID);
edNome = (EditText) findViewById(R.id.edNome);
db = new timeDatabase(getApplicationContext());
salvar = (Button) findViewById(R.id.btnCadastrar);
salvar.setText("Cadastrar");
String newString;
if (savedInstanceState == null) {
Bundle extras = getIntent().getExtras();
if(extras == null) {
newString= null;
} else {
newString= extras.getString("Alterar");
}
} else {
newString= (String) savedInstanceState.getSerializable("Alterar");
}
//button in CadastroTimes activity to have that String as text
System.out.println(newString + " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
salvar.setText(newString);
}
public void salvarTime(View v) {
t = new Time();
t.setNome(edNome.getText().toString());
if (salvar.getText().equals("Alterar")) {
db.atualizar(t);
exibirMensagem("Time atualizado com sucesso!");
} else {
db.salvar(t);
exibirMensagem("Time cadastrado com sucesso!");
}
Intent intent = new Intent(this, EditarTimes.class);
startActivity(intent);
}
private void limparDados() {
edID.setText("");
edNome.setText("");
edNome.requestFocus();
}
private void exibirMensagem(String msg) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
}
public class EditarTimes extends AppCompatActivity {
private Time t;
private List<Time> times;
private timeDatabase db;
private ListView lvTimes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editar_times);
lvTimes = (ListView) findViewById(R.id.lvTimes);
lvTimes.setOnItemClickListener(selecionarTime);
lvTimes.setOnItemLongClickListener(excluirTime);
times = new ArrayList<Time>();
db = new timeDatabase(getApplicationContext());
atualizarLista();
}
private void excluirTime(final int idTime) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Excluir time?")
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage("Deseja excluir esse time?")
.setCancelable(false)
.setPositiveButton(getString(R.string.sim),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if (db.deletar(idTime)) {
atualizarLista();
exibirMensagem(getString(R.string.msgExclusao));
} else {
exibirMensagem(getString(R.string.msgFalhaExclusao));
}
}
})
.setNegativeButton(getString(R.string.nao),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
builder.create();
builder.show();
atualizarLista();
}
private void atualizarLista() {
times = db.listAll();
if (times != null) {
if (times.size() > 0) {
TimeListAdapter tla = new TimeListAdapter(
getApplicationContext(), times);
lvTimes.setAdapter(tla);
}
}
}
private AdapterView.OnItemClickListener selecionarTime = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long id) {
t = times.get(pos);
Intent intent = new Intent(EditarTimes.this, CadastroTimes.class);
String strName = "Alterar";
intent.putExtra("Alterar", strName);
startActivity(intent);
}
};
private AdapterView.OnItemLongClickListener excluirTime = new AdapterView.OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int pos, long arg3) {
excluirTime(times.get(pos).getId());
return true;
}
};
private void exibirMensagem(String msg) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
public void telaCadastrar(View view) {
Intent intent = new Intent(this, CadastroTimes.class);
startActivity(intent);
}
public void botaoSair(View view) {
Intent intent = new Intent(this, TelaInicial.class);
startActivity(intent);
}
}
You can pass the button caption to CadastroTimes with intent as
Intent intent = new Intent(EditarTimes.this, CadastroTimes.class);
intent.putExtra("buttontxt","Changed Text");
startActivity(intent);
Then in CadastroTimes.java set the text of the button to the new value that you passed. The code will look like:
button = (Button)findViewById(R.id.button); // This is your reference from the xml. button is my name, you might have your own id given already.
Bundle extras = getIntent().getExtras();
String value = ""; // You can do it in better and cleaner way
if (extras != null) {
value = extras.getString("buttontxt");
}
button.setText(value);
Do remember to do it in onCreate after setContentView
//From Activity
Intent intent = new Intent(EditarTimes.this, CadastroTimes.class);
intent.putExtra("change_tag", "text to change");
startActivity(intent);
//To Activity
public void onCreate(..){
Button changeButton = (Button)findViewById(R.id.your_button);
// Button to set received text
Intent intent = getIntent();
if(null != intent &&
!TextUtils.isEmpty(intent.getStringExtra("change_tag"))) {
String changeText = intent.getStringExtra("change_tag");
// Extracting sent text from intent
changeButton.setText(changeText);
// Setting received text on Button
}
}
1: Use intent.putExtra() to share a value from one activity another activity, as:
In ActivityOne.class :
startActivity(
Intent(
applicationContext,
ActivityTwo::class.java
).putExtra(
"key",
"value"
)
)
In ActivityTwo.class :
var value = ""
if (intent.hasExtra("key")
value = intent.getStringExtra("key")
2: Modify button text programatically as:
btn_object.text = value
Hope this will help you
For changing the button text:
Use a static method to call from the other activity to directly modify the button caption.
Use an intent functionality, which is preferable.
Use an Interface and implement it, which is used for communicating between activities or fragment in a manner of fire and forget principle.
Now, i got you:
Your EditarTimes activity with listview:
//set setOnItemClickListener
youtListView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
Intent i = new Intent(EditarTimes.this, CadastroTimes.class);
//text which you want to display on the button to CadastroTimes activity
String strName = "hello button";
i.putExtra("STRING_I_NEED", strName);
}
});
In CadastroTimes activity,
under onCreate() method, get the text string as:-
String newString;
if (savedInstanceState == null) {
Bundle extras = getIntent().getExtras();
if(extras == null) {
newString= null;
} else {
newString= extras.getString("STRING_I_NEED");
}
} else {
newString= (String) savedInstanceState.getSerializable("STRING_I_NEED");
}
//button in CadastroTimes activity to have that String as text
yourButton.setText(newString);
Ok, so the first step would be to take the button you want and make it a public static object (and put it at the top of the class).
public static Button button;
Then you can manipulate that using this in another class:
ClassName.button.setText("My Button");
In your case it is
CadastroTimes.salvar.setText("Alterar");
if you want to change value from that do not do not go the activity via intent you can use file to save value to file or you have multiple values the use database and access
the value oncreate to set the value of text....
In my case, I had to send an EditText value from a Dialog styled Activity, which then got retrieved from a Service.. My Example is similar to some of the above answers, which are also viable.
TimerActivity.class
public void buttonClick_timerOK(View view) {
// Identify the (EditText) for reference:
EditText editText_timerValue;
editText_timerValue = (EditText) findViewById(R.id.et_timerValue);
// Required 'if' statement (to avoid NullPointerException):
if (editText_timerValue != null) {
// Continue with Button code..
// Convert value of the (EditText) to a (String)
String string_timerValue;
string_timerValue = editText_timerValue.getText().toString();
// Declare Intent for starting the Service
Intent intent = new Intent(this, TimerService.class);
// Add Intent-Extras as data from (EditText)
intent.putExtra("TIMER_VALUE", string_timerValue);
// Start Service
startService(intent);
// Close current Activity
finish();
} else {
Toast.makeText(TimerActivity.this, "Please enter a Value!", Toast.LENGTH_LONG).show();
}
}
And then inside my Service class, I retrieved the value, and use it inside onStartCommand.
TimerService.class
// Retrieve the user-data from (EditText) in TimerActivity
intent.getStringExtra("TIMER_VALUE"); // IS THIS NEEDED, SINCE ITS ASSIGNED TO A STRING BELOW TOO?
// Assign a String value to the (EditText) value you retrieved..
String timerValue;
timerValue = intent.getStringExtra("TIMER_VALUE");
// You can also convert the String to an int, if needed.
// Now you can reference "timerValue" for the value anywhere in the class you choose.
Hopefully my contribution helps!
Happy coding!
Accessing view reference of another Activity is a bad practice. Because there is no guarantee if the reference is still around by the time you access it (considering the null reference risk).
What you need to do is to make your other Activity read values (which you want to display) from a data source (e.g. persistence storage or shared preferences), and the other Activity manipulates these values. So it appears as if it changes the value of another activity, but in reality it takes values from a data source.
Using SharedPreferences:
Note: SharedPreferences saves data in the app if you close it but it will be lost when it has been deleted.
In EditarTimes.java:
private AdapterView.OnItemClickListener selecionarTime = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView arg0, View arg1, int pos, long id) {
t = times.get(pos);
SharedPreferences.Editor editor = getSharedPreferences("DATA", MODE_PRIVATE).edit();
editor.putString("btnText", "Your desired text");
editor.apply();
Intent intent = new Intent(EditarTimes.this, CadastroTimes.class);
startActivity(intent);
}
};
In CadastroTimes.java
public Button salvar;
salvar.setText(getSharedPreferences("DATA", MODE_PRIVATE).getString("btnText", ""));
//note that default value should be blank
As far as my thoughts go, I can realize that the problem is not with the code you provided as it seems to be implemented correctly. It is possible that you have saved the activityState somewhere in your actual code and because it is not implemented properly, the savedInstanceState found in the onCreate method is not null but the required information is missing or not correct. That's why newString is getting null and salvar textview is getting blank.
Here, I need to know which one is more useful to you - information from getIntent() or from savedInstanceState? The code you provided insists me to assume that savedInstanceState has got the preference.
If you prefer savedInstanceState, then you may use SharedPreferences like this to get the same value you want:
private SharedPreferences mPrefs;
private String newString;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
........
// try to get the value of alterarValue from preference
mPrefs = getSharedPreferences("MyData", MODE_PRIVATE);
newString = mPrefs.getString("alterarValue", "");
if (newString.equals("")){
// we have not received the value
// move forward to get it from bundle
newString = getIntent().getStringExtra("Alterar");
}
// now show it in salvar
salvar.setText(newString);
}
protected void onPause() {
super.onPause();
// you may save activity state or other info in this way
SharedPreferences.Editor ed = mPrefs.edit();
ed.putString("alterarValue", newString);
ed.commit();
}
Or if you don't need to get it from savedInstanceState, please use it:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
........
// try to get the value of alterarValue from bundle
String newString = getIntent().getStringExtra("Alterar");
// now show it in salvar
salvar.setText(newString);
}
That's all I know. Hope it will help. If anything goes wrong, please let me know.

In Android Studio, cannot invoke Activity B from Activity A more than once

Further to my previous post, I now want to invoke a child activity from the main activity a number of times. In my real project (as opposed to the noddy test below), when the child activity is invoked, its header displays, "Enter first data set" then invites the user to enter some data. This data is actually stored in a common class rather than being returned to the main activity. Then the child needs to be called again with a new prompt "Enter second data set", and the same thing happens.
What I cannot work out is how to do this. If I include two calls to the child, every time, only the second call appears to happen, the prompt appearing in the child activity being "Enter second data set" every time. This startActivityForResult() method is I believe, designed to be used when you want to call an activity and wait for the result (which you do with an onActivityResult() do you not), but it does not wait.
How on earth do I do this? Sample code follows.
Thank you to anyone who can clearly explain where I'm going wrong and what the right code should be.
MainActivity code extract
#Override
public void onResume(){
super.onResume();
TextView maintop = (TextView)findViewById(R.id.maintop);
maintop.setText(Common.mess1);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button mainbutton = (Button)findViewById(R.id.mainbutton);
mainbutton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Intent intent1 = new Intent(MainActivity.this,Child.class);
intent1.putExtra("Prompt", "Enter first data set");
startActivityForResult(intent1,1);
onActivityResult(1,1,intent1);
}
});
mainbutton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Intent intent2 = new Intent(MainActivity.this,Child.class);
intent2.putExtra("Prompt", "Enter second data set");
startActivityForResult(intent2,1);
onActivityResult(1,1,intent2);
}
});
}
You can only have one click listener in the button, so when you call set for the 2nd time it replaces the listener.
What you need to do is set the click listener for the enter first data, don't call to onActivityResult(1,1,intent1) that's not how you do it, you need override the method, and in onActivityResult call the 2nd.
Something like this:
static final int FIRST_INTENT = 1;
static final int SECOND_INTENT = 2;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button mainbutton = (Button)findViewById(R.id.mainbutton);
mainbutton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Intent intent1 = new Intent(MainActivity.this,Child.class);
intent1.putExtra("Prompt", "Enter first data set");
startActivityForResult(intent1,FIRST_INTENT);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FIRST_INTENT) {
if (resultCode == RESULT_OK) {
Intent intent2 = new Intent(MainActivity.this,Child.class);
intent2.putExtra("Prompt", "Enter second data set");
startActivityForResult(intent2,SECOND_INTENT);
}
}
}
And in your child activity
//DO SOMETHING
....
setResult(RESULT_OK)
finish();
}
For more check
[http://developer.android.com/intl/es/training/basics/intents/result.html]
[http://developer.android.com/intl/es/reference/android/app/Activity.html#setResult%28int%29]

Returning back to main activity from gameover screen

Hi so even though I have seen a couple of topics about linking activities or returning I can not get my return back to activity to work. I abit of back ground the the app when the user gets an answer wrong or runs out of time it goes to game over taking the score across with it and displaying it on the game over, here's the working code for that if it helps solve my issue:
Main Class:
public void fail(){
{
Intent myIntent = new Intent(MainActivity.this,gameover.class);
myIntent.putExtra("number", score);
MainActivity.this.startActivity(myIntent);
finish();
}
gameover class:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameover);
re_run = (Button) findViewById(R.id.retry);
EndScore = (TextView) findViewById(R.id.show);
int getVal;
getVal = getIntent().getExtras().getInt("number");
String s = String.valueOf( getVal );
EndScore.setText(s);
}
Now the reason I shared the above working code because I have the feeling the intent that takes the user and score to the gameover screen, is messing with the retry/return code as shown below:
private void setButtonOnClickListeners(){
re_run.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
Intent retry = new Intent(getApplicationContext(),
MainActivity.class);
startActivity(retry);
}
});
}
From what I can find from those topics these seems to be the correct method. but when the code is run the re_run button does nothing. Any help?
You use "setButtonOnClickListeners()" to implement setOnClickListener and so override the onClick. But when did you call setButtonOnClickListeners?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameover); re_run = (Button)
findViewById(R.id.retry);
EndScore = (TextView) findViewById(R.id.show);
int getVal;
getVal = getIntent().getExtras().getInt("number");
String s = String.valueOf( getVal );
EndScore.setText(s);
setButtonOnClickListeners();
}
You can maybe check that your OnClick is working correctly adding a log line in LogCat. Log.d("GameOver", "Retry onclick ok");
You are finding a view before it was inflated (R.id.retry).
Change the sequence of commands to:
super.onCreate(savedInstanceState);
setContentView(R.layout.gameover);
re_run = (Button) findViewById(R.id.retry);
Also try changing the intent to:
Intent retry = new Intent(GameOver.this, MainActivity.class);
retry.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
I personally used startActivityForResult(Intent) to start the game over screen, and once the player inputted his name or pressed something or quit the activity with Back, then it returned a value to onActivityResult(..) in which I called finish().
EDIT:
Game ends, so I started activity using
Intent i = new Intent();
i.putExtra("Score", scoreCount);
i.setClass(context, HighScoreInputActivity.class);
context.startActivityForResult(i, 0);
Then when you insert the scores and stuff, you close the game screen in GameActivity with
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
this.finish();
}

Categories