Unable to instantiate activity ComponentInfo, Runtime and NullPointer exceptions - java

I get that error whenever I attempt to run this app. It's simple right now, I'm just trying to make sure the first button does what I want it to. It also mentions NullPointerException.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
calendarButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ComponentName cn = new ComponentName("com.android.calendar", "com.android.calendar.LaunchActivity");
Intent i = new Intent();
i.setComponent(cn);
startActivity(i);
}
});
}
This (and declaring the buttons) are all I have done in the activity's Java file. I have set placeholders for listeners on other buttons but commented them out until I figure this one.
I have tried starting a new project running the same code (even pieced the layout back together) to make sure the Manifest wasn't accidentally messed with. Same issue.

I derped. Hard. I assigned the button variables a value during instantiation (which I have above onCreate) rather than INSIDE onCreate. I fixed it myself. Sorry about that.

Related

How to pass a parameter out of an onClick

New to Android Studio. I'm creating an app project for practice and I am trying to create a Menu Activity. I want to test to see if I can mute sounds and hide the display of text (score) via a Menu UI. I get that I can use Intent to pass values back and forth between activities and that I can use those values to turn features on and off across the app.
I cannot figure out with a button and onClick how to get a variable to change so that I can pass it via Intent. I've only seen it done INSIDE the onClick. I'm trying to change the variable OUTSIDE the onClick.
Example Code:
public class Menu extends AppCompatActivity {
private boolean soundOn = true;
private Button isSoundOn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
isSoundOn = findViewById(R.id.isSoundOn_button);
isSoundOn.setOnClickListener(v -> {
soundOn = false;
});
Now when I attempt to access the soundOn parameter and pass it on via Intent to another activity the value remains true, it never changes after the button is clicked.
I did figure out one trick, I can use intent and pass the value to the same activity, like so:
soundOff.setOnClickListener(v -> {
Intent intent = new Intent(Menu.this, Menu.class);
intent.putExtra("soundOn", false);
startActivity(intent);
This reloads the Activity after the button is clicked, it makes it appear as though a glitch happened as it is run, but I think that issue could be resolved via altering the transition animation...I think. However, this seems like a clumsy approach, especially in a Menu Activity that could have numerous settings to edit (sound, score, language, timer, color, background, etc.).
I get that I can have the onClick go back to the original Activity with the change, but I want to create a menu where I can have multiple selections made and then pass them all back to the original Activity.
I hope this makes sense, I know this is rather basic, but I'm new to this and my searching hasn't been able to yield a solution. Thanks.
If you are doing an intent to the same Activity you should retreive your intent on the onCreate method:
isSoundOn = intent.getBooleanExtra("soundOn", true) //true is the default parameter in case intent does not contain that key;
That way you are always checking your intent in case you need it.
You also need to use your variable in the intent; right now you are always setting it to false:
soundOff.setOnClickListener(v -> {
Intent intent = new Intent(Menu.this, Menu.class);
intent.putExtra("soundOn", soundOn);
startActivity(intent);
}
There are other solutions, for example: you can use SharedPreferences for persisting your values and then call this.recreate to recreate Activity again and avoid using intents. Then you can retreive your SharedPreferencesvalues on the onCreate method to do whatever you want.
Now when I attempt to access the soundOn parameter and pass it on via
Intent to another activity the value remains true, it never changes
after the button is clicked.
Lets start with keeping track of soundOn
When Menu activity is first launched soundOn = true
When isSound button is clicked soundOn = false
Intent intent = new Intent(Menu.this, Menu.class);
intent.putExtra("soundOn", soundOn); // false is the value that is extra.
startActivity(intent);
When MenuActivity is again launched due to the intent soundOn = true this is because of this line
private boolean soundOn = true; //<---
You are passing Extra in intent but you arent storing the intents extra value in soundOn
Thats why it is true always
to solve this use need to Get the Intent Extra that you have passed and we do it in onCreate method
private boolean soundOn = true;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
Intent intent = getIntent();
if(intent != null) { // we need to get this cause when we first start our app we dont start it with any intents
soundOn = intent.getExtra("soundOn");
}
}

How to use the same UI with multiple java files? ANDROID JAVA

I'm a newbie and I'm working on a Unit Converter.
I would like to open the same UI regardless of which button I click(Weight or Length)
main_activity.xml UI
Below is the UI I want to open: activity_conversion.xml UI
And I would like each button in the main_activity to run on a different java class.
So, (minus the main_activity.java and it's .xml file)
I have 1 xml file(activity_conversion.xml) and 2 java files one for each button of the main_activity.xml
activity_main.xml Weight button
android:onClick="weightPage"
activity_main.xml Length button
android:onClick="lengthPage"
MainActivity.java
public void weightPage(View view){
Intent intent = new Intent(this, WeightActivity.class);
startActivity(intent);
}
public void lengthPage(View view) {
Intent intent2 = new Intent(this, LengthActivity.class);
startActivity(intent2);
}
Length_Activity.java code for Length button
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_conversion);
}
setContentView() method doesn't work for me:(
Thanks in advance!
I would like to open the same UI regardless of which button I click(Weight or Length)
You can do that by creating an activity and its layout XML file. And then start that activity via explicit intent like this:
//Place this code inside the onClick method
Intent intent = new Intent(SoucreActivity.this, DestinationActivity.class);
startActivity(intent);
And I would like each button in the main_activity to run on a different java class.
No, you cannot. All UI elements on a screen are always in the same activity; they cannot run on different java classes. (Unless you are using fragments of which you need not worry about as you are a newbie)
Apparently, you want the two buttons in your main activity to open the same activity. Which you can achieve using intents using the code snippet mentioned above.

Restoring state not working when returning to activity, savedInstanceState is null

So im having some trouble restoring the state of my Activity.
At this point I figure that its probably a problem with my understanding rather then anything else.
My goal is to move from my MainActivity to a Main2Activity.
Am I correct in thinking that when a user moves from one page to another, it should be done by changing Activity via Intent?
I am doing this like so:
The onCreate() for my MainActivity has this in it.
Button currentButton = (Button) findViewById(R.id.button2);
currentButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.activity_main2);
Intent nextIntent = new Intent(getApplicationContext(), Main2Activity.class);
startActivity(nextIntent);
}
}
);
Which as I understand should call onCreate(), onStart() and onResume() for Main2Activity, then onSaveInstanceState() for MainActivity, then onStop() for MainActivity.
Ive overloaded all those functions with logging and seen that indeed they are being called and in that order.
Here is my onSaveInstanceState() for MainActivity:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
System.out.println("onSaveInstanceState called, saving state");
savedInstanceState.putInt("mySuperUniqueKey", testInt);
super.onSaveInstanceState(savedInstanceState);
}
Once in Main2Activity, I return back to MainActivity in the same way. I.e. findViewById() the button, overload its onClickListener(), create a new Intent and start it.
Then MainActivity class's onCreate() has this :
if (savedInstanceState != null) {
System.out.println("savedInstanceState is not null");
testInt = savedInstanceState.getInt("mySuperUniqueKey");
} else {
System.out.println("savedInstanceState is null");
}
When returning back the MainActivity from Main2Activity, I can see from the logging that onCreate(), then onStart(), then onResume() for MainActivity is called, then onStop() for Main2Activity. Unfortunatly the logging shows that savedInstanceState always comes back as null.
To add to this, when in the emulator, switching the orientation back and forth causes this to work perfectly; savedInstanceState is not null and features the saved testInt.
Thus I figure its a problem with my understanding and that there must be something im missing.
My gradle has minSdkVersion set to 16, and targetSdkVersion set to 28. Am I maybe targeting too low a minSdkVersion?
I have read through the "Understand the Activity Lifecycle" on the official android developer documentation but still cant get it.
https://developer.android.com/guide/components/activities/activity-lifecycle
I did find similar problems but none of them match my situation exaclty, also the solutions they have suggested I am already doing anyway.
Any insight would be greatly appreciated, thanks in advance.
The saved instance state bundle is intended to save the state of the current activity across things like orientation changes. It is not designed to persist across activities. You should use Intent#putExtra:
nextIntent.putExtra("mySuperUniqueKey", testInt);
Then, in your next activity, access this passed value using:
int testInt = getIntent().getIntExtra("mySuperUniqueKey");

How to refer to a randomly generated button's elements

I need to randomly generate a button and then grab elements from it from the activity that the button opens. Specifically the universal ID of a "character" that I have specified in PersistentData. (That whole class works fine, though. The problem is between this activity and the next.) The child activity has multiple activities that can call it. (There are several activities with lists made from different characters from a pool, and each list has these buttons that are shown below, which all point to the same activity that loads information from PersistentData based on the data that its supposed to pull from said button.) The following 1 block of code is in the onCreate method for this activity. (Automatically generated, I just added this in after I called the layouts from the XML file)
for (fID = 0; fID < PersistentData.fName.size(); fID++) {
if (PersistentData.fName.get(fID) != null) {
Button[] Btn = new Button[PersistentData.fName.size()];
Btn[fID].setHeight(200);
Btn[fID].setWidth(200);
Btn[fID].setTextSize(40);
Btn[fID].setText(PersistentData.fName.get(fID));
Btn[fID].setTag(fID);
Layout.addView(Btn[fID]);
Btn[fID].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int btnID = fID;
gotoActivity(v);
}
});
} else continue;
}
Here is gotoActivity(). (In the class, not onCreate)
public void gotoActivity(View view) {
Intent intent = new Intent(this, TargetActivity.class);
startActivity(intent);
intent.putExtra("btnClicked", /*IDK WHAT TO PUT RIGHT HERE*/);
}
I have put several things there, actually. Mostly, they have been various ways of declaring a variable on the creation of the button.
Here's the TargetActivity.class
public class Fighter extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fighter);
Intent intent = getIntent();
Bundle bundle =
intent.getExtras(); //line ***
**
TextView viewName = (TextView) findViewById(R.id.fighterName);
viewName.setText(PersistentData.fName.get(fID));
}
}
What should I put in the other class that I should get here**? (fID) is the thing that I'm trying to get. I have tried putting and getting fID using the methods as described in the Create an Activity page from Android and it continued to give me a NullPointerException at line *** (I split the line to be precise.)
Any help is appreciated. I would not be surprised if there is a better way to do this, requiring me to scrap all my work and restart. I would prefer not to, though lol. I will be checking this post periodically throughout the day, so if you have any questions or require more detail, just post or message me. Thank you beforehand.
I think the reason you got a NullPointerException because you started the activity before persing the extra.
In the gotoActiviy, make sure the extra(s) method are called before you start the activity. that is
public void gotoActivity(View view) {
Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra("btnClicked", "Strings");
startActivity(intent);
}
As you can see, a string was the extra, you can put any variable type as the extra just make sure at the activity being called, the same variable type gets the extra.
as an example
String getValue = getIntent().getExtras().getString("btnClicked");
Int getValue = getIntent().getExtras().getInt("btnClicked");
/** If integer was the value activity extra */

How to Correctly Start Activity from custom View (Java Class)?

I'm trying to define a custom Java class (extending a LinearLayout), which needs to start an activity on click. My code looks like this :
public ArizaSatiri(Context context/*, AttributeSet attrs , final Activity aktivite*/ , JSONObject mysql_satiri)
{
super(context/*, attrs*/);
// code to initialize my view :
final Context finalContext = context;
this.setOnClickListener(new OnClickListener() {#Override
public void onClick(View v) {
Intent newIntent = new Intent(finalContext, ArizaDetaylari.class);
finalContext.startActivity(newIntent);
}//onClick
});
}
But when I clicked on the instantiated view, I get the error :
Calling startActivity() from outside of an Activity context requires the
FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
As you can see from the code, I tried passing the Activity to the constructor, and that worked. But is that the correct way? Which way would you reccomend ?
Edit:
And I also need to call setTypeFace() at some point. Should I use context, or Activity for that ?
Try this:
this.setOnClickListener(new OnClickListener() {#Override
public void onClick(View v) {
Intent newIntent = new Intent(finalContext, ArizaDetaylari.class);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
finalContext.startActivity(newIntent);
}//onClick
});
You can put your code into onAttachedToWindow() of your custom view class.
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final Context context = ArizaSatiri.this.getContext();
Intent intent = new Intent(context , ArizaDetaylari.class);
context.startActivity(intent);
}
});
}
This helps because this function is called after your view is added to the activity, the view has the reference of it. Constructor of views probably run before being added to the activity, thus the error.
This should also work if you declare your view in xml instead of creating it programmatically. (Not tested yet)
If take a look to the Context class reference you could see that Activity is an indirect subclass. So if you use an Activity as Context your code should work.
For example:
public ArizaSatiri(Context context, JSONObject mysql_satiri){ ...}
you can change the call to the ArizaSatiri constructor:
new ArizaSatiri(myActivity, mysql_satiri);
Hope it helps.
If context (finalContext) that you are using is referring to ApplicationContext then you need to use the flag. Just add the sentence newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); before finalContext.startActivity(newIntent);
Problem with this approach especially when you are starting something outside of your app for ex: mail client etc, is it will continue to be there in the recent apps stack even after the activity is completed, in case of mail client it continues to be there even after mail has been sent

Categories

Resources