I can't for the life of me figure this out, and I've searched as thoroughly as I can.
I've got a block of code like so:
public class TwoPlayerGame extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
}
public GameStuff game = new GameStuff();
public Player playerOne = new Player();
public Player playerTwo = new Player();
public Player[] players = {playerOne, playerTwo};
public Button cardOne=(Button)findViewById(R.id.card1);
public Button cardTwo=(Button)findViewById(R.id.card2);
public Button cardThree=(Button)findViewById(R.id.card3);
public Button cardFour=(Button)findViewById(R.id.card4);
public Button cardFive=(Button)findViewById(R.id.card5);
public Button[] buttons={cardOne, cardTwo, cardThree, cardFour, cardFive};
#Override
public void onStart(){
super.onStart();
for(int i=0; i<=1; i++){
dealCards(players[i]);
}
for (int i = 0; i<=4; i++){
buttons[i].setText(playerOne.cardsInHand[i]);
}
}
}
As written this will crash as soon as the Activity starts (it'll even crash if I change the onStart override into a new method altogether). If I move all the Button declarations into the onStart method, everything works fine, but then they won't be global. If I move them into onCreate, they won't be global, according to Eclipse, and I get errors that won't let me compile.
All the other global variables work fine where they are, and I need the buttons to be global so I don't have to keep re-declaring them in new methods.
Am I overlooking something blindingly obvious (probably)? And what is it?
try
public class TwoPlayerGame extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
cardOne=(Button)findViewById(R.id.card1);
cardTwo=(Button)findViewById(R.id.card2);
cardThree=(Button)findViewById(R.id.card3);
cardFour=(Button)findViewById(R.id.card4);
cardFive=(Button)findViewById(R.id.card5);
}
public GameStuff game = new GameStuff();
public Player playerOne = new Player();
public Player playerTwo = new Player();
public Player[] players = {playerOne, playerTwo};
public Button cardOne;
public Button cardTwo;
public Button cardThree;
public Button cardFour;
public Button cardFive;
public Button[] buttons={cardOne, cardTwo, cardThree, cardFour, cardFive};
#Override
public void onStart(){
super.onStart();
for(int i=0; i<=1; i++){
dealCards(players[i]);
}
for (int i = 0; i<=4; i++){
buttons[i].setText(playerOne.cardsInHand[i]);
}
}
}
you can not get the Buttons from the findViewById before calling setContentView. It is impossible.
You should realize that lines
public Button cardOne=(Button)findViewById(R.id.card1);
... and others
are called when the class is created. But this is before onCreate is called. It crashes because to use findViewById you need to first call
setContentView(R.layout.activity_game);
but its actually called after the initialization of the class and therefore after findViewById calls.
Related
I have done I game in which I want to call on a method I have in a view from another view. I figured I would somehow have to send the "first view" into the "second view" through the my MainActivity in order for the second view to be able to call on the first view methods. However, I couldn't come up with any way of sending in the first view to the second view through my MainAcitivity, so I decided to change tactics. I now tried to have a function in my MainActivity to handle the interection between the views, but once again I was not able to call on the method from the second View.
Therefore my question is how do you send a view into another view through an Activity, or If that's not possible how do you call on an activity method through a view?
Here is the code (I added some comments to better show the problem I'm having):
public class MainActivity extends AppCompatActivity {
private FishView gameView;
private SmallBall smallBall ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout screen = findViewById(R.id.gameScreen);
gameView = new FishView(this);
smallBall = new SmallBall(this);
screen.addView(gameView); // first view
screen.addView(smallBall); //second view
}
//this is the method I want to reach through the View
public void handleAvoidedBall(){
gameView.avoidedBall();
}
}
public class SmallBall extends View {
private final Bitmap sodaCan;
private final static long smallBallPeriod = 60;
private final Handler handler = new Handler();
public SmallBall(Context context) {
super(context);
Paint smallBall = new Paint();
smallBall.setColor(Color.GRAY);
smallBall.setAntiAlias(false);
resetBall();
sodaCan = BitmapFactory.decodeResource(getResources(),R.drawable.sodacan);
Timer movementTimer = new Timer();
movementTimer.scheduleAtFixedRate(smallBallTask, 0, smallBallPeriod);
}
private final TimerTask smallBallTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
invalidate();
if (isBallLanded()){
//Here I want to call on a handleAvoidedBall() in MainActivity
//OR simply have gameView here if possible
// gameView.avoidedBall();
//OR
//SomeMainAcitvityObject.handleAvoidedBall();
}
}
});
}
};
#Override
protected void onDraw(Canvas canvas) {
..... //Do stuff}
}
So as I hopefully have explained somewhat decent now, I'm wondering how to either send gameView into the SmallBall view OR how to call on handleAvoidedBall() in MainActivity from the SmallBall view?
Thank you for your time and hope you have a wonderful day!
Your best option would be to define a listener that you would set on the SmallBallView.
Define the listener:
public interface BallListener {
void onAvoided(SmallBall ball);
}
And then inside your SmallBall class, you would have this method:
public void setListener(BallListener listener){
this.listener = listener;
}
And then call this in your activity, after you've instantiated the SmallBall class:
smallBall.setListener(new SmallBallListener(){
#Override
public void onAvoided(SmallBall ball){
// Do stuff here
}
})
As #LukeWaggoner mentioned, you should consider using listeners instead of making view static in your activity.
You told us, that you'd like to add more than one SmallBall views, so I figure that you don't want to write a listener's code for each of them.
It is easily doable with MainActivity implementing SmallBallListener.
Listener:
public interface SmallBallListener {
void onAvoidedBall();
}
SmallBall class:
public void setListener(SmallBallListener listener){
this.listener = listener;
}
MainActivity:
public class MainActivity extends AppCompatActivity implements SmallBallListener {
private FishView gameView;
private SmallBall smallBall ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout screen = findViewById(R.id.gameScreen);
gameView = new FishView(this);
screen.addView(gameView); // first view
// Add 10 small ball views
for(int i = 0; i < 10; i++) {
SmallBall ball = new SmallBall(this);
ball.setListener(this); // MainActivity is a listener here, so each ball has the same listener code
screen.addView(ball);
}
}
//this is the method I want to reach through the View
public void handleAvoidedBall() {
gameView.avoidedBall();
}
#Override
public void onAvoidedBall() { // this is the SmallBallListener method
this.handleAvoidedBall();
}
}
So whichever SmallBall view call listener.onAvoidedBall(), it will fire onAvoidedBall() method in MainActivity class.
Turns out all I had to do was to set:
private FishView gameView;
to:
public static FishView gameView;
And then simply use "MainActivity.gameView" in the SmallBall view. This gave me no additional warings either, so that was good also.
I decided to try and make my code more object oriented and avoid repetitive code in another class.
Source code for Activities :
public class EasyMode extends MainActivity {
GameActivityPVP game = new GameActivityPVP();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_layout_pvp);
game.initializeButtons();
}
}
public class GameActivityPVP extends MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_layout_pvp);
initializeButtons();
}
public void initializeButtons() {
button[0] = (Button) findViewById(R.id.button1);
}
}
The second the program gets to the line where I try to call a method using game.methodName(); the program crashes. No compiling errors or anything.
I am new to programming in general so please take it easy on me and I tried to simplify my code as much as possible.
Android Monitor/logcat :
W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
and
W/art: Before Android 4.1, method int android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView
You can use another class's method by creating object of parent class.
See below example;
Here you want to use method from 'GameActivityPVP' class. So you need to create one object in this class only.
public class GameActivityPVP extends MainActivity {
public static GameActivityPVP mGameActivity;
public GameActivityPVP getInstance(){
return mGameActivity; // assign value in onCreate() method.
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_layout_pvp);
mGameActivity = this; // Do not forget this, otherwise you'll get Exception here.
initializeButtons();
}
public void initializeButtons() {
button[0] = (Button) findViewById(R.id.button1);
}
}
Now use this Object in another class 'EasyMode' like this;
if(GameActivityPVP.getInstance()!=null){
GameActivityPVP.getInstance().initializeButtons();
}
Try This:
Make one Class Utils:
In Utils:
public class Utils{
private Activity context;
Button button;
public Utils(Activity context) {
this.context=context;
}
public void inititializeButton(Activity context){
button[0]= (Button) context.findViewById(R.id.button_flasher);
}
}
And in your Class use:
public class EasyMode extends MainActivity {
Utils utils;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_layout_pvp);
utils=new Utils(this);
utils.initializeButtons();
}
}
As already stated, you shouldn't use nested activities, they are not supposed to interact like this. If you want two activities to interact you have to do it through an intent. Regarding the duplicated code, you have few solution presented but my personal opinion is that the OOP rules are not followed. If I had to write that logic, I would create a BaseActivity to hold the common logic of the other two activities and use inheritance to extend them.
public class BaseActivity extends Activity {
protected List<Button> buttons = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_layout_pvp);
initializeButtons();
}
protected void initializeButtons() {
buttons.add((Button) findViewById(R.id.button1));
}
}
public class EasyMode extends BaseActivity {
// Add here logic that is used only in EasyMode activity
}
public class GameActivityPVP extends BaseActivity {
// Add here logic that is used only in GameActivityPVP activity
}
Note that in this way you don't have to override onCreate again to initialise the buttons and so on. Also, I saw that you used the same layout for both activities, but if you want to use different layouts you can do it as usual and then call initializeButtons.
I am creating some EditTexts with button, I created a class which implements OnClickListener, and I want to save those EditTexts after screen rotation but they always disappear. I know that
Activity on rotation is destroyed and created again
I cant save EditText in Bundle since it does not implement Parcelable or something like that
So I tried to save at least their ID's and Text they have in them with the onSaveInstanceState(Bundle savedInstanceState)
but it is not called because it is not in main class, but in another called ViewControl. I need to save some private variables (text and ids) so that is the reason why I have this method inside my class. I tried to call this method from another onSaveInstance which is in main but no luck neither. Can you tell me some easy way to programatically create EditTexts one below another and KEEP them after screen rotation? I really cant find any easy way...
Main class
public class MainActivity extends Activity {
private ViewControl vc;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vc = new ViewControl(this);
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
vc.onSaveInstanceState(savedInstanceState);
}
ViewControl class
import java.util.ArrayList;
public class ViewControl extends Activity implements View.OnClickListener{
private Button btn;
private RelativeLayout rl;
private Activity act;
private ArrayList<Integer> id;
private ArrayList<String> userpath;
private int lastId;
public ViewControl(Activity activity) {
this.act = activity;
this.id = new ArrayList<Integer>();
this.userpath = new ArrayList<String>();
this.rl = (RelativeLayout)act.findViewById(R.id.layout);
this.btn = (Button)act.findViewById(R.id.btn);
this.id.add(Integer.valueOf(R.id.btn));
this.btn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(id.size() != 1)
lastId = id.get(id.size() - 1);
else
lastId = R.id.btn;
RelativeLayout.LayoutParams par = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
par.addRule(RelativeLayout.BELOW, lastId);
EditText et = new EditText(act);
et.setId(++lastId);
id.add(Integer.valueOf(lastId));
et.setText(Integer.toString(lastId));
rl.addView(et, par);
lastId = et.getId();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putIntegerArrayList("ids", id);
savedInstanceState.putStringArrayList("userpaths", userpath);
savedInstanceState.putInt("lastId", lastId);
Toast.makeText(act, "Onsave", Toast.LENGTH_LONG).show();
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
this.id = savedInstanceState.getIntegerArrayList("ids");
this.userpath = savedInstanceState.getStringArrayList("userpaths");
this.lastId = savedInstanceState.getInt("lastId");
Toast.makeText(act, "Onrestore", Toast.LENGTH_LONG).show();
for(int i = 0; i < id.size(); i++)
{
RelativeLayout.LayoutParams par = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
par.addRule(RelativeLayout.BELOW, lastId);
EditText et = new EditText(act);
et.setId(this.id.get(i));
}
}
}
The calls are in the wrong order (both in MainActivity and ViewControl). First you should add your data, then pass the Bundle to super to save it (see the docs here). (Your onRestoreInstanceState is OK)
I have a function named 'func()'. I want to run this function when application start without clicking any button. just when application load I want to show a massage.that massage in that function. I just want to run that function when app start what will be the code.
public class TextViewActivity extends Activity {
public static EditText etxt;
public final void func(){
etxt.setText("Massage");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etxt= (EditText) findViewById(R.id.etxt2);
}
}
Just put a call to the function on the onCreate
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etxt= (EditText) findViewById(R.id.etxt2);
func(); //A call to the function.
}
Hope that helps.
I don't recommend subclassing the Application in order to do this. When the application starts it will go to the main activity. So I would say just keep a SharedPreference boolean value if it has been set. If not show the message.
So keep state of the application here: http://developer.android.com/reference/android/content/SharedPreferences.html, just set a boolean. Remember when you app gets called, the activity onCreate always gets called of the main activity, so its just a matter of not calling it again.
try using below code.. you need to call ur function after you initialize edittext etxt. so it can not cause you NPE
public final void func(){
etxt.setText("Message");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etxt= (EditText) findViewById(R.id.etxt2);
func();// here your function call.
}
Try this:
public class TextViewActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.etxt2).setText("SMTH");
}
}
In case you really need a function to be called, you can use this:
public class TextViewActivity extends Activity {
public final void func() {
findViewById(R.id.etxt2).setText("SMTH");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
func();
}
}
Hi guys I can't figure out why I cant get it to work, to check the CheckBox of an activity from within another class.
In the onCreate method of the activity I'm passing a reference of itself to another class
public MainActivity()
...
dbi = new DBPrefsInterface(this);
...
}
public DBPrefsInterface(Context ctx)
{
MainActivity pma = (MainActivity)ctx;
this.ma = pma;
}
Now I try to Check a checkbox which is placed on the activity
this.ma.cbx.setChecked(true);
but it isn't working.
It seems I didn't pass a reference, only a Copy of MainActivity.
Thanks in adcance
Try passing a handler and a reference to the checkbox in the constructor of the other class
and make the handler send a message to the checkbox's original context
hanlder.post(new Runnable() {
#override
void run {
checkbox.setChecked(true);
}
});
Why don't you pass in the CheckBox itself? So your constructor becomes public DBPrefsInterface(CheckBox cbx) and you manipulate that reference.
Here is an example of a simple activity to demonstrate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.checkbox);
CheckBox cbx = (CheckBox) findViewById(R.id.box);
Button button = (Button) findViewById(R.id.button);
final DBPrefsInterface iface = new DBPrefsInterface(cbx);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
iface.toggle();
}
});
}
private class DBPrefsInterface {
CheckBox cbx = null;
public DBPrefsInterface(CheckBox cbx) {
this.cbx = cbx;
}
public void toggle() {
cbx.setChecked(cbx.isChecked());
}
}
I don't see why you would want to do this, but I think using the following constructor would do the work:
private MainActivity ma;
public DBPrefsInterface(MainActivity a){
ma = a;
}
Then to set the checkbox (but checkbox needs to be public in order to work):
ma.cbx.setChecked(true);