SavedIntanceState.getBoolean() is making my app crash (i think) - java

My Goal:
So I need help putting a boolean primitives into a bundle and retrieving it from the bundle when there is a screen orientation change in Android. I am using that boolean value in a conditional statement that helps decide if 2 Button views (mTrueButton, mFalseButton) should be enabled or not. What i have so far is causing the app to shut down (aka crash) when there is a screen rotation. I think I am not retrieving or writing my boolean from my bundle or into my bundle correctly, and it is causing the app to crash.
How The App Should Works:
When a user touches the mTrueButton or mFalseButton button to answer a question, both buttons become disabled so the user is not allowed to answer again. I want those buttons to keep being disabled when the user answers and then rotates the screen.**
I know that when a user rotates their Android device, onDestroy() is called because runtime configuration changes take place, causing the app to be relaunched without having knowledge of it's previous state, (unless store my necessary data onto a bundle and pass it onto my onCreate method).
These are SOME global variables in my activity class
private int index = 0;
priavate Button mTrueButton,mFalseButton;
private static final String KEY_INDEX = "index";
private static final String BTTN_ENABLED = "bttnEnabled";
private boolean trueFalseButtonsEnabled = true;
These are SOME statements in my onCreate() method of the same activity class
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate(Bundle) called");
setContentView(R.layout.activity_quiz);
if(savedInstanceState != null) {
index = savedInstanceState.getInt(KEY_INDEX, 0);
changeButtonEnableStatus(savedInstanceState.getBoolean(BTTN_ENABLED,true));
}
mTrueButton = (Button)findViewById(R.id.true_button);
mFalseButton = (Button)findViewById(R.id.false_button);
mTrueButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
checkAnswer(true);
changeButtonEnableStatus(false);
}
});
mFalseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
checkAnswer(false);
changeButtonEnableStatus(false);
}
});
}
These are SOME methods in the same activity class but not in my onCreate()
private void changeButtonEnableStatus(boolean bool){
trueFalseButtonsEnabled = bool;
mTrueButton.setEnabled(bool);
mFalseButton.setEnabled(bool);
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
Log.d(TAG,"onSavedInstanceState() called");
savedInstanceState.putInt(KEY_INDEX,index);
savedInstanceState.putBoolean(BTTN_ENABLED, trueFalseButtonsEnabled);
}
Note that:
index = savedInstanceState.getInt(KEY_INDEX, 0);
works properly. It is setting global variable "index" to equal to the int primitive what was stored in into keywork "KEY_INDEX".
However I don't think: changeButtonEnableStatus(savedInstanceState.getBoolean(BTTN_ENABLED,true)); is working properly. My app seems to crash when I include that statement and run the app, and then rotate the device.

Related

Can't get a game loop to work in Android Studio

So I understand the basics of java programming but when I'm trying to use my little knowledge in android studio it make everything harder having classes and different files needing to be referenced. Coming from python, when making a simple game I would define different functions, then run them in a game loop like
while running:
or something similar. I know to define something in java you go like
public void Example() {}
but when I use this in java, when I try to run the program my game either instantly crashes or doesnt load anything.
The code at the moment is
public class MainActivity extends AppCompatActivity {
//Variables
Boolean running = true;
public int years = 0;
//Setup Year Counter
TextView textView = (TextView) findViewById(R.id.year_counter);
//Advance Button
public void advance() {
ImageButton button = (ImageButton) findViewById(R.id.advance);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
years += 1;
textView.setText("" + years + "");
}
});
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Game Loop
while (running) {
advance();
}
}
}
And this results in the app not opening.
Any help at all would mean a lot to me.
Thanks in advance :)
Although I don't actually see a crash, since you didn't really upload one, I can see why you might think your app wont work.
What you are doing constantly in the while loop is that you are only setting the button's click listener over and over again.
public class MainActivity extends AppCompatActivity {
//Variables
Boolean running = true;
public int years = 0;
//Setup Year Counter
TextView textView;
ImageButton button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// you set up your views once, after the layout is inflated
setUpViews();
// you initialize your buttons functionality
initClickEvents();
//Game Loop
while (running) {
// do other stuff
}
}
private void setUpViews() {
textView = (TextView) findViewById(R.id.year_counter);
button = (ImageButton) findViewById(R.id.advance);
}
private void initClickEvents() {
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
years += 1;
textView.setText("" + years + "");
}
});
}
}
I'd recommend working with a game engine.
If you want to stick with java, libGDX is an option.
But if language (and IDE) doesn't matter, than a better option is Godot. The reason why I recommend Godot over some of the more popular game engines is because it's open source, 100% free and plus GDScript (godot's scripting language) is heavily influenced by python.
If you want to make you own game engine in java check out this: https://java-design-patterns.com/patterns/game-loop/#
Keep in mind that the while loop is calling the advance method. So every loop you are setting the view for button and then setting an OnClickListener for it. Not everything needs to be in the while loop.
You must implement (override) the render method (it is called in the game loop).
I suggest trying a complete example in the documentation.
``
#Override
public void render() {
ScreenUtils.clear(0, 0, 0.2f, 1);
advance();
...
``

Call void method from another method in the same class

At first my main problem was at how to call a method from the same class, even tough I think I found a way to do this, it's not working as I expected, and I would like to know what would be the best approach to my case.
This is the code I'm working on:
public class EscolhaAtendimento extends AppCompatActivity {
private ViewPager mSlideViewPager;
private LinearLayout mDotLayout;
String TAG = "TasksSample";
private TextView[] mDots;
private SliderAdapter sliderAdapter;
Dialog myDialog;
#Override
public void onCreate (Bundle SavedInstanceState){
super.onCreate(SavedInstanceState);
setContentView(R.layout.escolha_atendimento);
mSlideViewPager = findViewById(R.id.slideViewPager);
mDotLayout = findViewById(R.id.dotsLayout);
sliderAdapter = new SliderAdapter(this);
mSlideViewPager.setAdapter(sliderAdapter);
addDotsIndicator(0);
mSlideViewPager.addOnPageChangeListener(viewListener);
myDialog = new Dialog(this);
}
public void addDotsIndicator(int position){
mDots = new TextView[8];
mDotLayout.removeAllViews();
for (int i= 0; i < mDots.length; i++){
mDots[i] = new TextView(this);
mDots[i].setText(Html.fromHtml("•"));
mDots[i].setTextSize(35);
mDots[i].setTextColor(getResources().getColor(R.color.colorTransparentWhite));
mDotLayout.addView(mDots[i]);
}
if (mDots.length > 0){
mDots[position].setTextColor(getResources().getColor(R.color.colorWhite));
}
}
ViewPager.OnPageChangeListener viewListener = new ViewPager.OnPageChangeListener(){
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected (int i) {
switch (i) {
case 0: {
myDialog.show();
}
addDotsIndicator(i);
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
};
public void ShowPopup(View v) {
TextView txtclose;
//Button btnFollow;
myDialog.setContentView(R.layout.pop_upfinal);
txtclose = myDialog.findViewById(R.id.txtclose);
txtclose.setText("X");
//btnFollow = (Button) myDialog.findViewById(R.id.btnfollow);
txtclose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myDialog.dismiss();
}
});
myDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
myDialog.show();
}
}
This class is an activity that on user swipe, the text and image from the buttons will change, even though their IDs will stay the same. (That's controlled by another class, it's working well).
Now, I wanted the image button on the activity do something different depending on which page is selected, and that's why there is a initial switch on the onPageSelected method, inside the Page change listener. The image button in the layout has the android:onClick="ShowPopup" tag, and I guess that also complicates things for me, if I wanted it to do something different in that same activity? Also, calling it that way on the switch, every time I change pages, and go back to the first one the popup window will open, since my call is explicit there. (As I said, even tough I found a way to somehow call my method, or at least it's result, it's not working as I expected).
Edit
I tried then changing it like this, so that the button wouldn't rely on the android:onClick="ShowPopup" Tag, and also wouldn't need to call a void method directly on the switch:
Added
public ImageButton popupchoice;
And also this to onCreate method:
popupchoice = this.findViewById(R.id.imgslide1);
Inside the switch I called it like this to get the button ID:
popupchoice.setOnClickListener(image1);
And set the View.OnClickListener like this:
View.OnClickListener image1 = new View.OnClickListener() {
public void onClick(View v) {
TextView txtclose;
//Button btnFollow;
myDialog.setContentView(R.layout.pop_upfinal);
txtclose = myDialog.findViewById(R.id.txtclose);
txtclose.setText("X");
//btnFollow = (Button) myDialog.findViewById(R.id.btnfollow);
txtclose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myDialog.dismiss();
}
});
myDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
myDialog.show();
}
};
But that returns me:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setOnClickListener(android.view.View$OnClickListener)' on a null object reference at .EscolhaAtendimento$1.onPageSelected(EscolhaAtendimento.java:81) Line 81 is the one inside the switch with the popupchoice.setOnClickListener(image1).
This error happens on page change, when coming back to the first Page, and also the button click won't work anymore.
I think you can use
EscolhaAtendimento.this.ShowPopup from inside your switch.

How to save listview item checked

I'm using a listview to display grocery items with checkmark using android.R.layout.simple_list_item_checked. The problem is when i check an item and go to the previous page and comeback to the list my item is not checked anymore..i would like to use something else than sharedpreference is that possible and how can i do that?
I try to use SparseBooleanArray but it didnt work i probably use it wrong.
Since i use the previous phone button and after i click on the button that call my list activity i should use something in my onCreate method but i'm not sure what and how?
I also try to use oninstanceResore method like some people suggest me but i dont thin it what i'm looking for let say im on the activity 2 which is my item list with some item checked i decide to go back do something else using the phone previous button and then come back to the activity 2 using the button in my apps ...i want my item to still be checked. Can someone help me on how to do this i will be very grateful…
public class FruitList_Activity extends AppCompatActivity {
private ListView fruitsList;
private ArrayAdapter<String> adapterFruit;
private Button btn_Delete;
private Button btn_SelectAll;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_fruit_list_);
fruitsList = findViewById(R.id.list_Fruits);
fruitsList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
btn_Delete = findViewById (R.id.btn_delete);
CreateActivity.itemsFruit = FileHelper.readData(this);
adapterFruit = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, CreateActivity.itemsFruit);
fruitsList.setAdapter(adapterFruit);
/*Remove items*/
btn_Delete.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
SparseBooleanArray checkedItemPositions = fruitsList.getCheckedItemPositions();
int itemCount = fruitsList.getCount();
for(int i=itemCount-1; i >= 0; i--){
if(checkedItemPositions.get(i)){
fruitsList.setItemChecked(i,true);
adapterFruit.remove(CreateActivity.itemsFruit.get(i));
FileHelper.writeData(CreateActivity.itemsFruit, FruitList_Activity.this );
}
}
adapterFruit.notifyDataSetChanged();
}
});
}
}
Can you guide me on how i can do that i'm just starting with java so please explain me so i can understand. thanks!
You need to create a Bundle with the information of the list, and before calling the second activity, you'll set the data inside that bundle, and when you came back to the main activity just check the bundle and if is different at null is because you need to load the data.
I Hope this cal help you :D
this is saved Instance()
also, this cal help you when you have onConfigurationChanged()
Save your adapterFruit using onSaveInstanceState
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("adapter",(Serializable) adapterFruit);
}
The onRestoreInstance executes when you go back to the activity
#Override
protected void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if(saveInstanceState != null){
adapterFruit = (ArrayAdapter<Adapter> )savedInstanceState.getSerializable("adapter");
}
}
Hope it helps.
you can do like this
holder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(holder.checkBox.isChecked()==true) {
holder.checkBox.setChecked(true);
model_image.get(position).setSelected(true);
}
else
{
holder.checkBox.setChecked(false);
model_image.get(position).setSelected(false);
}
}
});

Android App stops after savedInstanceState is implemented

EDIT: After adding onPause() and onResume(), the app no longer crashes; however, the instance is still not saving, and I lose the text I put inside the EditText. I speculate that I'm supposed to save the instance using onPause(), onStop(), and recall it using onResume() (or maybe using this and onSaveInstanceState(), onRestoreInstanceState() together) - I'm reading up on how to use these three methods now, and I would appreciate any pointers.
I'm currently writing a simple Android App with only a four (maybe five) activities. The app's function is to provide help and advice to students in university, where they are required to add the courses themselves (which appear on the activity_main_page page as buttons) - when the button is pressed, it will take the student to the advice page.
What I'm currently working on is the course adding page: activity_add_course. I'm trying to add a way to save the state of the EditText's text (this is where the user adds the course name) when the activity is paused/stopped (for example when user presses the back button or home button), and to have it recalled when the user returns to the page.
The app worked fine (using dummy intents to connect activities - I havent added an SQL database to actually make the app work) before I tried adding instance state saving to the App. Now that I have added instance state saving and recalling, the app stops running when I click the back button and I have no idea why? or how to fix it? - This issue has been solved. Thanks #peresisUser
This is the code for the back button
btBk.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent New = new Intent(AddCourse.this, MainPage.class);
startActivity(New);
}
});
}
And these are the codes I use for instance save and restore.
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
//Save instance state
savedInstanceState.putString("edC1", edCourse1.getText()+"");
savedInstanceState.putString("edC2", edCourse2.getText()+"");
savedInstanceState.putString("edC3", edCourse3.getText()+"");
savedInstanceState.putString("edC4", edCourse4.getText()+"");
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//Restore instance state
String edC1 = savedInstanceState.getString("edC1");
edCourse1.setText(edC1+"");
String edC2 = savedInstanceState.getString("edC2");
edCourse2.setText(edC2+"");
String edC3 = savedInstanceState.getString("edC3");
edCourse3.setText(edC3+"");
String edC4 = savedInstanceState.getString("edC4");
edCourse4.setText(edC4+"");
}
edCourse1-4 are all different EditTexts.
From my understanding, the onSaveInstanceState() will save edC1 as the text from edCourse1.getText()+"" and so on, then the onRestoreInstanceState() will restore the String inside edC1 to edCourse1 and so on.
Having trouble on this, I have no idea how I would solve my next issue, which has to save the state of buttons on the page activity_main_page. Here I would have 10 buttons which start off as invisible and nameless, where activity_add_course will add a name to the button and make it visible. I speculate that the issue I will run into is: that all the buttons would become invisible when the app is restarted.
It looks to me that your should just add the super call in onPause() which is probably deleted in your code.
First row of the stack trace:
android.util.SuperNotCalledException: Activity {com.example.user.icecres/com.example.user.icecres.AddCourse} did not call through to super.onPause()
Let me know if that helped.
So I've figured out how to do all of this, next task: doing the same thing for buttons!
Feel free to add/edit anything appropriate to this answer.
This is my final source code:
package com.example.user.icecres;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.view.View;
public class AddCourse extends AppCompatActivity {
private EditText edCourse1, edCourse2, edCourse3,edCourse4;
private Button btConfirm, btReset, btBk;
public static final String PREFS_NAME = "MyPrefsFile";
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.activity_add_course);
if(state != null){
//restore state onStop()
SharedPreferences pText = getSharedPreferences(PREFS_NAME,0);
String edC1 = pText.getString("edC1", "");
String edC2 = pText.getString("edC2", "");
String edC3 = pText.getString("edC3", "");
String edC4 = pText.getString("edC4", "");
edCourse1.setText(edC1);
edCourse2.setText(edC2);
edCourse3.setText(edC3);
edCourse4.setText(edC4);
} else {
btConfirm = (Button) findViewById(R.id.btConfirm);
btReset = (Button) findViewById(R.id.btReset);
edCourse1 = (EditText) findViewById(R.id.edCourse1);
edCourse2 = (EditText) findViewById(R.id.edCourse2);
edCourse3 = (EditText) findViewById(R.id.edCourse3);
edCourse4 = (EditText) findViewById(R.id.edCourse4);
btBk = (Button) findViewById(R.id.btBk);
}
btConfirm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// add course to database
edCourse1.setText("");
edCourse2.setText("");
edCourse3.setText("");
edCourse4.setText("");
AlertDialog.Builder d = new AlertDialog.Builder(
AddCourse.this);
d.setTitle("Success");
d.setMessage("Courses have been added");
d.setPositiveButton("OK", null);
}
});
btReset.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder c = new AlertDialog.Builder(
AddCourse.this);
c.setTitle("Confirmation");
c.setMessage("Would you like to clear all fields?");
c.setPositiveButton("YES", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
edCourse1.setText("");
edCourse2.setText("");
edCourse3.setText("");
edCourse4.setText("");
}
});
c.setNegativeButton("NO",null);
c.show();
}
});
btBk.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent New = new Intent(AddCourse.this, MainPage.class);
startActivity(New);
}
});
}
#Override
protected void onPause() {
super.onPause();
SharedPreferences pText = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor edit = pText.edit();
edit.putString("edC1",edCourse1.getText()+"");
edit.putString("edC2",edCourse2.getText()+"");
edit.putString("edC3",edCourse3.getText()+"");
edit.putString("edC4",edCourse4.getText()+"");
edit.commit();
}
#Override
protected void onStop() {
super.onStop();
SharedPreferences pText = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor edit = pText.edit();
edit.putString("edC1",edCourse1.getText()+"");
edit.putString("edC2",edCourse2.getText()+"");
edit.putString("edC3",edCourse3.getText()+"");
edit.putString("edC4",edCourse4.getText()+"");
edit.commit();
}
#Override
protected void onResume() {
super.onResume();
SharedPreferences pText = getSharedPreferences(PREFS_NAME,0);
String edC1 = pText.getString("edC1", "");
String edC2 = pText.getString("edC2", "");
String edC3 = pText.getString("edC3", "");
String edC4 = pText.getString("edC4", "");
edCourse1.setText(edC1);
edCourse2.setText(edC2);
edCourse3.setText(edC3);
edCourse4.setText(edC4);
}
protected void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
//Save instance state
state.putString("edC1", edCourse1.getText()+"");
state.putString("edC2", edCourse2.getText()+"");
state.putString("edC3", edCourse3.getText()+"");
state.putString("edC4", edCourse4.getText()+"");
}
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
//Restore instance state on crash
String edC1 = state.getString("edC1","");
String edC2 = state.getString("edC2","");
String edC3 = state.getString("edC3","");
String edC4 = state.getString("edC4","");
edCourse2.setText(edC2+"");
edCourse3.setText(edC3+"");
edCourse1.setText(edC1+"");
edCourse4.setText(edC4+"");
}
}
So the onPause() and onStop() are used to save the text inside the EditText fields to the file initialized at the top. The onResume() is used to call the texts saved and apply them to the relevant EditText fields. The onSaveInstanceState() is used to save the state and onRestoreInstanceState() is used to restore the state on crash. The if else in the onCreate(), is used to determine if there was a previous state to be restored or not (by onStop), and the values are called/initialised depending on this condition.
Hope this helps someone with similar problems!

ImageView size valid only in onGlobalLayout()

I have a problem with getting the size of ImageView in an android app I'm making. I've read several solutions to this problem and none of them seem to solve my problem. I just want to get the size once at the beginning of the application like in onCreate() before loading anything to the ImageView (When it's empty.) and use it for the rest of my app.
The solution that almost works is the one with getViewTreeObserver().addOnGlobalLayoutListener.
I did that and it is getting me the right size and everything but only in the onGlobalLayout() method. All I want to do is to save that size in some class global variable but everything that happens in onGlobalLayout() stays there. It's like it has no effect on the rest of the class. I can't really write my whole application in that method it's ridiculous. Why is it happening and how can I fix that?
Also I tried the OnFocusChangeListener solution and it gives me the size only if I try to exit the app. As expected the focus is changed but this is not what I need.
Here is the code:
public class Fractaler extends Activity {
int finalWidth;
int finalHeight;
TextView txt;
ImageView fractal;
Fractal mandelbrot;
boolean viewIsMeasured = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initialize();
}
private void initialize() {
txt = (TextView) findViewById(R.id.txt);
fractal = (ImageView) findViewById(R.id.mainImage);
fractal.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!viewIsMeasured) {
finalWidth=fractal.getWidth();
finalHeight=fractal.getHeight();
viewIsMeasured = true;
mandelbrot=new Fractal("Mandelbrot",finalWidth,finalHeight);
fractal.setImageBitmap(mandelbrot.create());
}
}
});
txt.setTextColor(Color.CYAN);
//txt.setText(String.valueOf(mandelbrot.getWidth())+" "+String.valueOf(mandelbrot.getHeight()));
}
#Override
protected void onStart() {
super.onStart();
}
}

Categories

Resources