in my App I created a BaseActivity, from which I extend all my Activities.
Inside the BaseActivity I recognize the activity that is running through the following statement: this.getClass().getSimpleName() (ex: ActivityA)
Until I open new Activity (ActivityB, ActivityC, etc ...) everything works correctly.
The problem occurs when I use the back button of the phone (I get back from activityC to ActivityB). In this case the ActivityB is properly resumed from the Stack, but in BaseTable (of ActivityB) the value of this.getClass().getSimpleName() remains ActivityC.
How can I avoid this problem? You know you help me?
All you need to do is create a protected final String in your BaseActivity as follows...
public class MyBaseActivity extends Activity {
protected final String TAG = getClass().getSimpleName();
// Any other code here
}
Any Activity which extends MyBaseActivity will inherit the TAG field and it will be instantiated with the correct name at the time it's created.
I put a TAG field in all of my Android base classes so I can use it with Log to identify different objects when they log to logcat.
Related
I have two activities A and B, and a non activity class C.
To use the methods of C, I create an instance c of C from the currently running activity (say A is in the foreground, and A has created C).
Now, I want to use the instance variables of activity A from c. What should I do?
I am trying to use the non activity C class for multiple activities. Please help me! I have researched it a lot, but still couldn't find anything useful about it. :(
This is the example code:
ActivityOne.java:
package com.example.vaibhav.a21matchsticks;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class Example extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
// Now comes the method, I want to use in the non-activity java class.
public void buttonClick(View view) {
EditText editText = (EditText) findViewById(R.id.editMe); //finds the view from the activity
int i = Integer.parseInt(editText.getText().toString());
//Below code changes the view state, if the condition is true
if(i<4) {
findViewById(R.id.button).setEnabled(false);
}
}
Assume the xml file to have a linear layout having one EditText view (with id 'editMe') and a Button (with id 'button'). There are more than 1 activities like this, each having at least the above two views (and may be more).
My job is to create a non activity class C, to handle the conditional statement for different activities and change the respective layout accordingly.
Even though a but vague, your Class C seems to be a helper class. Now, since you want to access instance variables (and possibly other information) in your C class, you need to pass them manually. Depending on what you are passing, it can be provided to Class C either in its constructor or via instance methods of the Class C itself.
For eg: based on the last statement of your question you can pass a ViewGroup reference from your activity to Class C via something like this:
public void initLayout(ViewGroup parent) {
// Hide/unhide/perform actions/etc based on current activity needs
}
Similarly, you can also pass an enum value to Class C to differentiate between your activities in Class C. For a Class C to activity communication, you can look at interface in Java. Hope this helps.
I have been using this example as a base for my project.
I have changed the project to use an ArrayAdapter for the titles-fragment's ListItems and changed the DetailsFragment's View to display a custom layout, which as a Button that is supposed to add an entry into a database.
Instead of generating widgets like in the example, I just inflate a custom XML into the FrameLayout besides the TitlesFragment in the 'layout-land' version of the layout.
My problem stems from the fact that DetailsFragment is plugged into the MainActivity when in Landscape mode but gets it's own DetailsActivty if it is in Portrait mode.
The Button I have in my custom layout for the details-fragment calls a function in its onClick() that is called AddNewItem.
So when the Button was clicked in Landscape mode, it crashed, because there was no AddNewItem in the MainActivity. I solved this by using a BroadcastReceiver, so when the button is clicked, a method named AddNewItem in MainActivity.java instead broadcasts a custom event and i have a BroadcastReceiver that calls the AddNewItem in DetailsFragment.java.
It looks like this:
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Intent Detected.", Toast.LENGTH_LONG).show();
DetailsActivity m = (DetailsActivity) DetailsActivity.getActivityInstance(); // see below for what getActivityInstance does
LayoutInflater mInf = LayoutInflater.from(context);
View myView = mInf.inflate(R.layout.customlayout, null);
((DetailsActivity) m).AddNewItem(myView);
}
}
But this gives me:
08-11 13:37:50.687: E/AndroidRuntime(6766): java.lang.RuntimeException: Unable to start receiver in.falkeninc.umt_v0_9_8_1.MyReceiver: java.lang.NullPointerException
I am not sure what is happening. Because I am also using a static variable in DetailsActivity.java to be able to reach it inside the BroadcastReceiver. The code looks like this:
public class DetailsActivity extends SherlockFragmentActivity {
...
public static SherlockFragmentActivity activityInstance;
...
activityInstance = this; // in the onCreate
...
public static SherlockFragmentActivity getActivityInstance(){
return activityInstance;
}
}
My problem stems from the fact that DetailsFragment is plugged into
the MainActivity when in Landscape mode but gets it's own
DetailsActivty if it is in Portrait mode.
This shouldn't be a problem. Although you have two activities you have the same DetailsFragment class in both of them. If a Button from that fragment is doing something then you should keep it at that fragment's level(that would be an ideal fragment, one that is self contained, a fragment that doesn't know or care where is put). If you do require the activity for the work in that method, you should add extra details.
Also, if the behavior is common to both activities you could make a base activity holding that method and let the two current activities inherit from that, so it will be available to the fragment no matter what.
public static SherlockFragmentActivity activityInstance;
Don't keep static references to activities, you risk leaking them.
Also, don't access activities from outside their own context. When an activity is not the one interacting with the user(it's onPause() has been called) that activity could as well be completely destroyed and trying to access it in another activity could bring you lots of problems.
I realise you can set the LAUNCHER activity of your app in the manifest file, but is there anyway you can statically do this in code before the activity is loaded by the Dalvik VM? Something like:
public class MyActivity extends Activity{
RunTime.LAUNCHER = MyActivity.class
...
}
I realise this might not be possible, but if it is I would appreciate a safe and reliable code example to achieve this?
Many thanks
What is possible, however, is to have a first empty activity that starts whatever activity you need next, without displaying itself.
public void onCreate(Bundle stuff) {
super.onCreate(stuff);
startActivity(new Intent(...whatever...);
finish();
}
In my application there are 14 activities. Out of that 9 activity contains custom title bar and tab pane. so here I need to write this common code at one place instead of redundant code in each activity that contain custom title bar and tab pane code (i.e layout and it's activity specific code)
What are the possible ways to do this?
The common way is:
Create a super class called, for instance, CommonActivity which extends Activity
Put the boilerplate code inside that class
Then make your activities extend CommonActivity instead of Activity:
Here a simple example:
public class CommonActivity extends Activity{
public void onCreate(Bundle b){
super.onCreate(b);
// code that is repeated
}
protected void moreRepeatitiveCode(){
}
}
And your current activities:
public class AnActivity extends CommonActivity{
public void onCreate(Bundle b){
super.onCreate(b);
// specific code
}
}
Hmm.. Common code doesn't always need to be in Activity class but just regular class. Than we could call those methods according to our needs referring to the common code class.
Am I right with this example?
Of course in case we need it like Activity, above proposal would work perfectly if we take care of Activity lifecycle and we don't forget to add it to manifest file.
In general Activities should just create UI, handle events occurrences and delegate business logic and/or other actions to the other components in our App.
Cheers
I want to go to homePage of my application on clicking button where i was in inner page.
Can any one tell me how to do that ?
Thanking you ,
Srinivas
I suggest creating an Application class. In that class have a boolean field that is false by default. Every Activity should check if that field is true in onResume() and call finish() if it is true (except for the main activity that always sets the field to false in onResume()). You can even create a custom Activity that does this and then have all activities extend that activity.
Resources:
http://d.android.com/resources/faq/framework.html#3
The android.app.Application class
The android.app.Application is a base class for those who need to maintain global application state. It can be accessed via getApplication() from any Activity or Service. It has a couple of life-cycle methods and will be instantiated by Android automatically if your register it in AndroidManifest.xml.
Reference: http://d.android.com/reference/android/app/Application.html
Stripped-down example:
MyApp
public class MyApp extends Application { public boolean goBack = false; }
MyActivity
public class MyActivity extends Activity {
protected void onResume() {
if ( ((MyApp) getApplication()).goBack ) finish();
}
}
SomeActivity
public class SomeActivity extends MyActivity {
// nothing special here, it's all been implemented in MyActivity!
}
MainActivity
public class MainActivity extends Activity {
protected void onResume() {
((MyApp) getApplication()).goBack = false;
}
}
AndroidManifest.xml
[...] <application android:name=".MyApp" [...]> [...]
Note: You don't need to declare MyActivity in AndroidManifest.xml because it will never be launched directly (it will only be extended).
On your button click event add the following lines of code
moveTaskToBack(true);
There are probably two ways of doing that (general concepts):
The first one would be to simply launch the home actvity again, if you don't mind having it re-created again, unless that activity is a "singleTask" or "singleInstance" activity.
The second one would be to close the top activity in the stack as long as it is not your home activity. I don't see an easy way to achieve that, maybe by finishing the current activity with a specific result that gets checked by the launching activity, who will in turn close and send the result until the home activity is reached.