I have a beginners problem. Here is my situation:
I want to start a new activity from the main activity. The code to launch the new activity is found in a separate class file. I seem to be passing the wrong arguments and I am ending up in a nullpointerexception when trying to launch the new activity. The new activity launches fine when I place the code in the main activity class file, therefore the second activity and the manifest are fine. Here is a sample of my code:
In my main activity class where I instanciate the second class (THIS IS MY MAIN ACTIVITY. I OMITTED THE REST BECAUSE I DO NOT THINK IT IS RELATED TO THE PROBLEM):
Tester mytest = new Tester();
mytest.test(this);
In my second class file (THIS IS NOT AN ACTIVITY; IT IS A CLASS THAT IS INSTANTIATED IN THE ACTIVITY):
public class Tester extends Activity {
Intent myIntent;
public void test (Context context) {
myIntent = new Intent (Intent.ACTION_VIEW);
myIntent.setClass(context, newActivity.class);
thebutton.setOnClickListener(
new OnClickListener() {
public void onClick(View v) {
startActivity(myIntent);
}
}
):}
When I perform the click I receive a nullpointerexception at startactivity. Can anyone enlighten me on this please?I am sure that I am wrongly using the context.
Activities are started with Intents. Please read the Android Application Fundamentals first and try the Hello World app :)
I understood that you will use your separate Tester class at all cost ;) so I'm trying to adapt and help you out there.
First of all, don't let your class inherit from Activity. This won't help you, cause this calls will probably not have any valid context. Activity somehow implements the template pattern, providing you key method like onCreate(...), onPause(...) etc and is instantiated by the Android OS.
If you still want to use the class, you have to pass in the context. Probably you're aiming for some MVC/MVP pattern structure, anyway.
public class Tester {
private Context context;
public Tester(Context context){
this.context = context;
}
public void test () {
final Intent myIntent = new Intent(context, NewActivity.class);
//guess this comes from somewhere, hope through a findViewById method
thebutton.setOnClickListener(
new OnClickListener() {
public void onClick(View v) {
context.startActivity(myIntent);
}
}
)};
}
}
This would be a proposed solution from my side. A problem I still see here is on how you retrieve the button in that test() method. In order to have that work properly you have to retrieve it from some View class (with view.findViewByid(R.id.myButton)) or to create it dynamically and associate it with the view during the onCreate(...) of your Activity (probably using an Inflater).
Related
I am creating an abstract base class to keep my navigation drawer code in one place and want to implement an onClickListener on my app title (defined in the toolbar) to start my launch activity
I am using the following code :
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.toolbar_title:
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
return;
}
}
The app works properly, but I read somewhere that one must not use the Application context to start new activities. However, android studio doesn't let me use any other context apart from getApplicationContext and getBaseContext, maybe because this class is abstract.
Which context should I use then?
Have a look at Context.getApplicationContext() and ContextWrapper.getBaseContext(). Both have in common to be defined on a context instance. In your case it's even an Activity.
So you could even use this as a context to start your MainActivity. This is even better, because with any other context type you' have to include the flag FLAG_ACTIVITY_NEW_TASK to start a new activity.
If you get errors by using this for a context, it's because you define your OnClickListener as anonymous inner class which of course isn't a context. For that you'd have to write MyBaseActivity.this instead. This references the outer class instance.
Well, one of the ways can be: You can define an abstract method in your BaseActivity class:
abstract void launchMainActivity();
And call this method in your click listener:
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.toolbar_title:
launchMainActivity();
return;
}
}
The sub-classes can then implement this method as:
#Override
void launchMainActivity() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
I've a method which is making a huge calculation and then calls an intent as follows
public void sampleMethod(final Context cont)
{
.
.
(huge calculation [50-80 lines])
.
.
Intent intent = new Intent(cont, TimesheetMain.class);
finish();
startActivity(intent);
}
This is present in Activity 'SampleActivity'. When I'm trying to access it through on object of Activity 'SampleActivity' from Activity 'B' as follows:
Context context = this;
SampleActivity sa = new SampleActivity();
sa.sampleMethod(context);
I'm getting a NullPointerException at the startActivity line of code while accessing it from Activity 'B'. I can't figure out where am i going wrong in here. Please help me out
EDIT 2
This seem to work when i added context to it like cont.startActivity(intent), but i need to know why shouldn't i use another class or another activity's function in a secondary class? Is the android framework is the reason? I've been doing this (without the intent part) for the past two months or so, i never faced any sudden force close issues in either emulator or in device(Nextbook professional 7 SE); Please explain it with a legit example
You're not supposed to create explicit instances of activities by yourself as you're doing like this:
SampleActivity sa = new SampleActivity();
Please provide a better description for your problem and what you want to achieve with the outcome of this issue.
try the follwng updated code:
public void sampleMethod(final Activity cont)
{
Intent intent = new Intent(cont, TimesheetMain.class);
cont.finish();
cont.startActivity(intent);
}
also move this method to a util class and call it from activity and pass the activity reference as follows
class ActivityB extends Activity
{
.
.
.
Util.sampleMethod(this);
}
I have tried almost all the solutions from SO but no success :(.
I have a simple myJavaClass.java with a couple of functions.
One of the functions in myJavaClass : startActivity() starts MyCustomActivity
public startActivity(Context context)
{
Intent intent = new Intent(context, MyCustomActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
This launches MyCustomActivity() as expected.
Now I have another function in myJavaClass.java to close/finish MyCustomActivity but it is not able to do so!
I have tried
Making MyCustomActivity SingleTop in manifest and creating the activity via an intent as above
Passing an activity instance to "this" in onCreate() of MyCustomActivity and calling MyCustomActivity.activity.finish() from myJava.class but that doesnt work as well
Please help me. I have been stuck here for hours now. I know the solution is very simple and conceptual but I am a newbie. Just building Java/Android concepts!
EDIT
MyCustomActivity
public Activity activity;
OnCreate()
{
...
this = activity;
}
MyJavaClass
public closeActivity(Context context)
{
Activity customActivity = MyCustomActivity.activity;
customActivity.finish();
}
I think that what you are trying to do is fundamentally bad. For a start, outside of the Activity code, there are no guarantees that the activity still exists - the memory manager may have cleaned it up, the user may have pressed Back etc. Think of Activities as independent entities - you can start them, and you can optionally get a result back when they finish what they're doing, but that's it.
Think about whether you really have to programmatically close the activity from outside it - I'd say this is an unusual design, but there are circumstances where it may be appropriate.
If so, what I think you want is a publish/subscribe system whereby MyCustomActivity can register a listener with MyJavaClass, and then receive a callback whereupon it can 'finish' itself.
public Activity activity implements FinishListener
{
public void onCreate(...)
{
//where does MyJavaClass come from? see in a minute
MyJavaClass myjava = getMyJavaclass();
myJava.addFinishListener( this );
}
public void onFinishCallback()
{
this.finish();
}
}
and
public class MyJavaClass
{
private List<FinishListener> finishListeners = ...;
public void addFinishListener( FinishListener fl )
{
this.finishListeners.add(fl);
}
public closeActivity(Context context)
{
for ( FinishListener fl : finishListeners )
{
fl.onFinishCallback();
}
}
}
and
public interface FinishListener
{
void onFinishCallback();
}
Now the only remaining issue is how to get MyJavaClass from the Activity. That's up to you - you may already know how, you may be able to put it in your Application implementation, it could be a singleton (bad), the listeners could be static (bad) or various other options.
Oh, and don't forget to remove the listener again in the Activity's onDestroy() method!
Just try this....
public closeActivity(Activity _activity)
{
_activity.finish();
}
you can't finish activity from other class until you have the reference of instance of Activity in that class, give the reference in that class and call finish() method to stop the activity.
activity.finish();
I have 3 screens in my app, each of which are in their own classes. When the app launches, my Driver class sets up some GUI elements, and then launches the first Intent.
I have a separate GUI class (which Driver invokes) which handles everything from menu's to dialog boxes. Previously my app didn't use Intents so I could pass the activity/context from Driver to Gui in its constructor as an object of type Activity and as a result could define layouts etc like LinearLayout ll = new LinearLayout(activity) and everything would be operating in the same activity/context.
Since I've moved to using intents, each Activity/Class has its own context, thus the previous dialogs and popup boxes from the Gui class are in the background and not running. I get an error saying android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy#406629a0 is not valid; is your activity running? when I click on a button to launch a dialog.
To me, this indicates the new Intents have taken over the foreground and the objects from the previous context are out of scope.
So, is there a way I can still pass the same context through to the new Intents so I can still access these shared dialogs? Or will I have to bring the code into each class (duplicate code)?
In case thats a bit hard to understand, here is some basic source code:
public class Driver extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Gui display = new Gui(this);
display.showScreen();
}
}
/////////////GUI.java///////////////////////
public class Gui
{
private Activity activity;
private Gui()
{}
public Gui(Activity _activity)//,Context _context)
{
this();
activity = _activity;
}
public void showScreen()
{
if(isLocationMode())
{
Intent i = new Intent(activity,LocationScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//locatScreen = new LocationScreen(activity);
//mainLayout.addView(locatScreen.getView());
}
else if (isManageMode())
{
Intent i = new Intent(activity,ManageScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//manageScreen = new ManageScreen(activity);
//mainLayout.addView(manageScreen.getView());
}
else if (isForwardMode())
{
Intent i = new Intent(activity,ForwardScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//forwardScreen = new ForwardScreen(activity);
//mainLayout.addView(forwardScreen.getView());
}
}
}
Have a setContext(Activity _activity) method in your Gui and call this in the onCreate of each activity?
I have an Activity MyActivity with a Button MyButton.
I want to attach a MySpecialOnClickListener to MyButton.
I write MySpecialOnClickListener in an external class file.
public class MySpecialOnClickListener extends ButtonHandler implements OnClickListener {
public OnClickListenerWithSpeech (Context context)
{ super.context = context; }
#Override
public void onClick(View view) { handleClick(view); }
}
and ButtonHandler looks like this
public abstract class ButtonHandler {
protected Context context;
protected void handleClick (View view){
if (view.getid()==R.id.button_B) {
context.startActivity (new Intent(context, ActivityC.class));
}
}
}
I basically want to store all logic for Buttons in the ButtonHandler.
SO...as I said, I have the MySpecialOnClickListener defined in an external class file.
When I click MyButton I get the following fatal error.
Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
So I can't start an activity normally from within a non-Activity. Fair enough.
However, if I change MySpecialOnClickListener to be an inner class in 'MyActivity' it works fine. Remember 'ButtonHandler' is still an external class file. So it (where ActivityC is ultimately started from) doesn't change.
My question (finally) is: can someone explain the logic of why one is allowed and the other isn't. I presume its a scoping thing or something but I'm a bit confused. It seems the code to start the process of starting an activity has to literally be inside another Activity.
EDIT - PROBLEM SOLVED
See below. The location of the class is irrelevant. I just didn't pass in the context properly.
because the ButtonHandler 'context' field isn´t associated with any activity context. So, when you attach the MySpecialOnClickListener instance to a button you create it passing the context parametener, isn´t???
something like this:
MySpecialOnClickListener listener = new MySpecialOnClickListener(MyActivity.this);
aButton.setOnClickListener( listener );
in this way you´re constructing the Button with the correct context...
It's likely that you are not passing the Activity context to MySpecialOnClickListener. Could you show me the difference in the way you invoke the inner-class approach?
Apologies to those of you who tried to answer. It was my fault (and I didn't include the following info initially for people)
When I was passing in the context to the 'MySpecialOnClickListener' I would do:
view.setOnClickListener(new MySpecialOnClickListener(getApplicationContext()));
when I should have done:
view.setOnClickListener(new MySpecialOnClickListener(this));
So getApplicationContext() doesn't seem to get the "correct" context for the app.
Which leads me to my next question as to what getApplicationContext() actually returns :)