Move "preparation task" to a MainActivity before launching gui - java

I have a running Android java written application and I would like to improve it.
For know my mainactivity, called DrugListActivty extend AppCompat. In short it's a recyclerView with Room database management.
I would like to move some part of the code in a MainActivity, in charge of checking database or onPause for example.
For now (and it's not working) I made :
public class MainActivity extends AppCompatActivity {
//some stuff
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, DrugListActivity.class);
startActivity(intent);
}
And DrugListActivity became
public class DrugListActivity extends MainActivity {
//etc
I have blink effect, DrugListActivty is launch again and again and again.
Is my idea bad (move to simply code)?
If is a good idea, there must be a right way to do it but I can't find any help.
So I'm asking the experts.
Thanks in advance for reading me, your advises and your time.

Related

Passing custom parameters to a parent activity through onCreate method yields confusing linter error

Why does passing custom parameters to a parent activity through an onCreate method, while leaving overriding the root method to the parent, result in the following linter error:
Overriding method should call super.onCreate
Background
For example, I have a MainActivity class that extends from ParentActivity that extends Android's Activity.
UML Generator
In order to make my app more abstract I am trying to handle several things in ParentActivity that the developer need not see in their development and use of MainActivity.
I have several parameters I would like to pass to the ParentActivity, like booleans turning on and off log functionalities, but it seems passing them through the onCreate() method is not ~~possible~~ recommended since this throws linter errors. I will make a separate question regarding the best practices for passing such parameters upward to custom parent classes using custom methods or directly setting parent fields, but I was looking to verify my current understanding of why this is not ~~possible~~ recommended through the existing onCreate method and additional parameters.
What has been tried
As a starting point, if I have some basic MainActivity and ParentActivity:
Code 0.1
public class MainActivity extends ParentActivity{
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//Do stuff
}
}
public class ParentActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//Do stuff
}
}
and then try to add further parameters to onCreate, e.g. a boolean to turn on/off some logger functionality within ParentActivity:
Code 0.2
public class MainActivity extends ParentActivity{
boolean logOn = true;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState, logOn);
//Do stuff
}
}
public class ParentActivity extends Activity{
// No longer overriding Activity.onCreate() due to diff in params
protected void onCreate(Bundle savedInstanceState, boolean logOn){
super.onCreate(savedInstanceState);
//Do stuff
}
}
Android Studio first warns me that I am not overriding the parent's method, which makes sense as it has a different parameter count, but then I thought I can just remove the #Override and call it good since I'm still calling super.onCreate(savedInstanceState) in ParentActivity, which will pass the savedInstanceState up to Activity, and I'm still passing the savedInstanceState to ParentActivity from MainActivity. At this point I encountered my first unknown issue: back in MainActivity, I get a linter error that states
Overriding method should call super.onCreate
Whats confusing is that I do call super.onCreate(savedInstanceState, logOn) directly below where I get this error. Although the error message is not too informative, I can get rid of the error by calling super.onCreate(savedInstanceState) directly above the already existing call to super.onCreate(savedInstanceState, logOn), i.e.:
Code 0.3
public class MainActivity extends ParentActivity{
boolean logOn = true;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
super.onCreate(savedInstanceState, logOn);
//Do stuff
}
}
public class ParentActivity extends Activity{
// No longer overriding Activity.onCreate() due to diff in params
protected void onCreate(Bundle savedInstanceState, boolean logOn){
super.onCreate(savedInstanceState);
//Do stuff
}
}
Looking at the tooltip inline doc using Android Studio, I see that super.onCreate(savedInstanceState); is calling the onCreate method from Activity (i.e the parent class of ParentClass) and super.onCreate(savedInstanceState, logOn); is calling the onCreate method of ParentClass. With typical inheritance in mind, and matching parameter lengths and types, this makes sense.
What doesn't make sense to me is why I have to call the onCreate method of Activity in MainActivity. Why does the call to onCreate within ParentActivity not suffice? i.e. why does Code 0.2 throw the linter error:
Overriding method should call super.onCreate
? I note, as per the comment by #greeble31 that Code 0.2 compiles, and runs on my example smartphone, but the linter error remains.
I don't think it's too much to worry about, since the problem is limited to a lint warning. You just did something a little too complicated for the linter to follow; your program is not, in fact, incorrect.
You could suppress the warning (#SupressLint), or simply ignore it.
...I can just remove the #Override and call it good...
Not too sure I agree with you, there... Removing the #Override annotation can't really help anything; the linter/compiler still knows what's an override and what's not. I consider the annotation useful b/c the IDE will tell you if you think you're overriding a method, but you're actually not, i.e. due to a signature mismatch or something (as here).
SUGGESTED APPROACH
FWIW, I would've solved this problem a little differently. (Note that code 0.3 actually results in two calls to the base class onCreate(); that's probably illegal.) I would just change the method name (to reflect a semantic distinction between configuration and creation), and store some state information in the base class:
public class MainActivity extends ParentActivity{
boolean logOn = true;
#Override
protected void onCreate(Bundle savedInstanceState){
configure(logOn); //Required, per base class specification
super.onCreate(savedInstanceState);
//Do stuff
}
}
public abstract class ParentActivity extends Activity{
boolean logOn;
boolean configured = false;
/** Subclasses are obligated to call this before calling super.onCreate() */
protected void configure(boolean logOn)
{
this.logOn = logOn;
this.configured = true;
}
#Override
protected void onCreate(Bundle savedInstanceState){
if(!configured)
throw new IllegalStateException("configure() not called prior to onCreate()");
super.onCreate(savedInstanceState);
//Do stuff
}
#Override
protected void onDestroy() {
configured = false; //(just being pedantic)
}
}
It's really just a matter of taste.
Sometimes people don't realize that Android can spontaneously create Activities on its own, like when it restores the back-stack state of your app. (This is why you want to be able to serialize and deserialize your Activity state to/from the bundle; b/c your Activity might not be re-created using the same workflow that caused its creation the first time).
I don't think that's going to be an issue for you, though, since ParentActivity (which I've declared as abstract) is always going to be instantiated via a concrete subclass, and all subclasses are guaranteed to call configure() in their onCreate() methods. (IOW, ParentActivity wouldn't have a manifest entry, so the system is never going to try to instantiate a base-class ParentActivity by itself.)
Just something to be aware of. (You had logOn set to a constant value in MainActivity, so if you were planning on changing that dynamically based on the app state, before calling configure()/super.onCreate(), just bear in mind that -- if you don't take steps to prevent it -- that information could be lost when your app is restored to the foreground.)
IDE will check #CallSuper annotation when on compilation {#link Activity#onCreate}.

Communication Between Two Android Activities via Reference to Caller or Callee

I have two activities Activity A and Activity B inside of the same application and they need to be able to call methods on each other. A needs to communicate to B at the start (possibly see "code" below).
B will call a lot of methods on A (this means that I cannot use the startActivityForResult method for communication because this would close B (Activity B is a Bluetooth Client and Server because it is a Peer to Peer app)). I do use startActivityForResult to start B for more of a kill signal than anything as the result.
Activity A uses a SupportMapFragment and Activity B cannot be a fragment because I want to be able to switch from B to A and then never use B again.
Originally, I started with one activity and tried switching between views using a ViewFlipper and just a call to setContentView(R.layout.my_layout_A) or setContentView(R.layout.my_layout_B). The fragment of course caused a lot of problems for both.
Using Fragments were confusing. The SupportMapFragment is the code for a Google Map which is a Fragment.
When I click a menu option inside of the MapsActivity (Activity A), I would like to be able to start myBluetoothActivity (Activity B) with a reference to the MapsActivity (Activity A) OR start myBluetoothActivity and then be able to set a reference to the caller inside of myBluetoothActivity (but this option would require having a reference to the BluetoothActivity inside of the MapsActivity or having some way to obtain the started activity from the intent).
//the following code is in Kotlin, but this can easily be converted over to java:
//option A: (pass it inside of the constructor)
var mbta:myBluetoothActivity = myBluetoothActivity(this)
//line for intent that I am unsure of
//intent so that I can start the activity with the pointer to the caller already passed into the new activity
startActivity(mbta)
//option B: (set this reference after obtaining a reference from intent):
var mintent:Intent = Intent(this.applicationContext, myBluetoothActivity::class.java)
startActivity(mintent)
//obtain the reference to the BluetoothActivity from the intent (NOT SURE HOW TO DO THIS???)
mbta.setCallerReference(this)
How can I accomplish this communication between the two activities via reference between the two activities? Should I use an interface for communication? If I should use it, (which I did try) how should I?
In other words, I am trying to access the caller activity (Activity A) from (Activity B) directly via a reference to Activity A inside of B OR trying to get the reference to B from the intent that started it inside of Activity A. I am trying to get a reference to that, so I can use it for communication/method calling/member variable and UI modification purposes.
NOTES: 1. The BluetoothActivity and the MapsActivity are NOT SERIALIZABLE. I tried serializing it and then adding it to the extras Bundle in the Intent and it just crashed saying that that was impossible to serialize due to BroadCastReciever. As this also deals with WIFI. Which I am highly considering separating out to be put with the BluetoothActivity in a future release.
I am also ASSUMING that Activity B will never just be started up by anything other than my MapsActivity class.
I am also new to Kotlin, but I know Java.
When I tried using an interface, I caused a StackOverflow error and I have no idea why.
I have read the documentation for Intents on the website.
I have done some research on here which gave me those ideas above. I am not sure how to implement them.
You are using the wrong approach. The solution requires a bit more work than you would think. The correct approach is to:
First, realize that these activities Activity A and Activity B (and any other activities) are activities that are specific to your application and you want to establish direct communication between them.
Second, realize that you are trying to get the current (or a previous) activity's context. The context will help serve the reference.
Third, you can create your own Activity and Application classes by extending the desired classes. The Application class is a low-level class used for the activities.
From here, you will be able to make use of the getApplicationContext() which will return your custom Application class.
Design: It is inside of your CustomApplication class that you must track the references to the activities that you want. From there all that you have to do is cast the getApplicationContext() to your CustomApplication class and then call your methods that access the Activity(ies). You must of course cast your Activities if you want to access certain instances of a specific activity that you created to its "type." For example:
MapsActivity mact = (MapsActivity)(((MyApplication)(this.getApplicationContext())).getCurrentActivity())
You must of course note that this activity must be already created (the onCreate method was already called) for this to return the current activity. The same of course goes for the other life-cycle methods for the activity as you will make a baseActivity which will deal with these as well as you will also have an Application life-cycle that will help deal with this too.
To answer the question: "How to get the current foreground activity context in android?" I turned to StackOverflow and found user: gezdy 's answer to be exactly what I needed at: How to get current foreground activity context in android?.
(BEGIN QUOTATION FROM: GEZDY)
You should manage activities references. Add the name of the
application in the manifest file :
<application
android:name=".MyApp"
....
</application>
Your application class :
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
Create a new Activity :
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (this.equals(currActivity))
mMyApp.setCurrentActivity(null);
}
}
So, now instead of extending Activity class for your activities, just
extend MyBaseActivity. Now, you can get your current activity from
application or Activity context like that :
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
(END OF QUOTATION FROM: GEZDY)
Note: All code is written in java for this answer.

Toolbar style changes in Android 4 when activity called from a static method

Found a strange issue in the app.
Toolbar style changes itself just for one acitvity in whole app and only on devices below 5.0 Android version.
All the screens have the same <include> field for the toolbar.
The activities, where style changes, are all inflated with a static method:
public static void startAsRecent(Context context, TransferTemplate template) {
Intent starter = new Intent(context, TransferAnotherAccountActivity.class);
starter.putExtra(TransferCommonActivity.EXTRA_KEY_TEMPLATE, template);
starter.putExtra(TransferCommonActivity.EXTRA_KEY_IS_RECENT, true);
context.startActivity(starter);
}
Strange, that it works normail in devices with Android versions abowe 5.0.
What could be the reason of this kind of behavior? And where to look to fix this?
Thanks in advance!
Ok, the problem was in inheritance.
onCreate() method of inherited activities, where was the problem, called setContentView() first, and then super.OnCreate(). Still don't understand, why this affected only pre-lollipop devices, but the temporary solution is to make something like this in the superclass.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentViewId());
//other stuff
}
#LayoutRes
public abstract int getContentViewId();

trouble to complete app about incoming call blocking

i wanted to make an app to block incoming call with the help of this blog http://androidsourcecode.blogspot.in/2010/10/blocking-incoming-call-android.html In this blog it only declares only the specific classes but there is no launcher activity like MainActivity.java . I imagine the launcher activity is look like this
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PhoneCallReceiver abc=new PhoneCallReceiver();
abc.onReceive(getApplicationContext(),getIntent());
setContentView(R.layout.activity_main);
}
}
But it seems this way it does not work. I figure out there is several answer on this topics in stackoverflow. But i don't find which will be my launcher activity and how my app running background continuously .Please give me some link of complete tutorial on this or give me some direction.Thanks in advance:)

android, how to separate functionality of activity over multiple classes?

I'm implementing GCM for the first time and the sample app on google provides DemoActivity which deals with GCM functionality. (http://developer.android.com/google/gcm/client.html)
I can copy those gcm related codes over to my MainActivity, but I 'd like to keep things separate, ie. create a separate file for gcm and let MainActivity use it.
In python world, mixin would be great fit here.
But I'm not sure if mixin exists for java and if its the right tool here.
How would one implement the GCM functionality in a separate class in java?
I'm thinking something like the following.
Create GcmHelper.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-->
public void onCreate(Bundle savedInstanceState, Activity activity) {
context = getApplicationContext();
this.mActivity = activity;
MainActivity::onCreate creates GcmHelper() and calls GcmHelper.onCreate(bundle, this)
do make similar changes for onResume() and activity related code to use the handed-over activity.
Create a Seperate Class eg. GcmHelper
Make GcmHelper constructor using Context parameter
Copy Every GCM related functions to GcmHelper
Create object of GcmHelper by passing the context in MainActivity->OnCreate
Finally call the required methods...

Categories