two build types - duplicate code. Not good solution - android

Android Studio 3.4
I have the next activity:
public class CartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
someCommonMethod()
}
private void someCommonMethod() {
// some code
}
}
Now I have 2 build types: debug and release.
In debug I add method someDebugMethod() to activity
public class CartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
someCommonMethod()
someDebugMethod()
}
private void someCommonMethod() {
// some code
}
private void someDebugMethod() {
// some debug code
}
}
In release I add method someReleaseMethod() to activity
public class CartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
someCommonMethod()
someReleaseMethod()
}
private void someCommonMethod() {
// some code
}
private void someReleaseMethod() {
// some debug code
}
}
I read official documentation
and now project's stucture is:
app\src\debug\java\com\myproject\CartActivity.java
app\src\release\java\com\myproject\CartActivity.java
I remove CartActivity.java from app\src\main\java.
So, as a result, I have two files CartActivity.java.
Nice.
And now when I start the app in debug build type then runCartActivity in debug folder.
And when I start the app in release build type then runCartActivity in release folder.
Nice. It's work fine.
But suppose now I need to update the common method someCommonMethod(). This method used in both build types.
As a result, I need to update TWICE this method. First in app\src\debug\java\com\myproject\CartActivity.java and
then update same method with same code in app\src\release\java\com\myproject\CartActivity.java
So I think this is not good.
Because this is duplicate code. I need to copy & paste EVERY time in TWO files when update method someCommonMethod().
It's really bad.
How to avoid this duplicate code?
The ideal approach is when in CartActivity.java has only delta.
In app\src\debug\java\com\myproject\CartActivity.java has ONLY method someDebugMethod()
In app\src\release\java\com\myproject\CartActivity.java has ONLY method someReleaseMethod()
and common code is in app\src\main\java\com\myproject\CartActivity.java
Is it possible?
P.S. Suppose I have 3 build types.
As result, I need to update same code in three files. It's really not good.

Just create a CommonCartActivity in
app\src\main\java\com\myproject\CommonCartActivity.java
Then extend the class overriding the methods in the flavor implementations.
public class CartActivity extends CommonCartActivity {
protected void someCommonMethod() {
// some code
}
}
In this way CartActivity just inherits from CommonCartActivity with nothing else, duplicated in two flavors.

I think you do not need to complicate the structure of the project. Just use the real-time check.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
someCommonMethod();
if(BuildConfig.DEBUG){
someDebugMethod();
}else{
someReleaseMethod();
}
}
private void someCommonMethod() {
// some code
}
private void someDebugMethod() {
// some debug code
}
private void someReleaseMethod() {
// some release code
}
But, if you need to separate the code, try using one activity, but create a new class (for example, Fork) in two copies for release and debug. Create an instance of the class in the activity. In this class there will be a doMetnod() which will have the necessary code depending on the type of project. So you avoid duplication of the activity code.

Related

Nothing shows up while calling a method

I was developing an exam score calculator app.
When I want to call AD methods,advertisements don't show up.
Calculation process happens in OnCreate method:
public class resultActivity extends AppCompatActivity {
public String responseId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
/*Calculation...*/}
and other voids like:
public void requestAd() {
/*AD RQUESTING PROCESS...*/
}
and
public void showAd() {
/*AD SHOWING PROCESS...*/
}
AD team gave me this code to call the method and it works well:
requestButton.setOnClickListener(v -> requestAd());
showButton.setOnClickListener(v -> showAd());
But the Problem is I don't have buttons to call them so I tried this:
public class resultActivity extends AppCompatActivity {
public String responseId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
requestAd();
showAd();
/*Calculation...*/}
But when the activity starts ads don't show up!
The whole question is I want this methods to be called while this activity starts.
thank you.
Try building up the release version APK and test on it. Maybe your Ad-provider have some restrictions in debug version?
I made another class and moved request Ad and showAd there. Then, I made an object and called the method through object.
I have to mention that I changed a minor thing in requestAd but the main job was done by the object.
Thank You All.

Debugging Mysterious RecyclerView Error that Closes App

I am working on an app with a RecyclerView, and I thought I almost had it running, but ran into a strange error.
I had made a few small changes to correct a small bug, and after that the app would no longer finish setting up the main activity layout. Instead I got the following screens:
App closed --- App keeps closing
My first thought was to look back at my small changes. But they did not cause this problem. (Undoing those changes did not fix the problem.)
I now believe that the problem is related to a change in the way the app operates between the first "successful" (though buggy) run and the following runs that fail.
In the first run, the app had to request permission from the user in order to access the documents folder. But after that, the app no longer needs to ask, because the user has already granted permission.
This means the order of execution has changed prior to the RecyclerView layout being created. But I can't (yet) figure out what's going wrong or how to fix it.
Here's the OnCreate() method in my main activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_prog_summary);
}
Here's the OnCreate() method & other related methods in the superclass (the class that implements the permissions request):
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.state = savedInstanceState;
if (state != null) {
isInPermission = state.getBoolean(STATE_IN_PERMISSION, false);
}
if (hasAllPermissions(getDesiredPermissions())) {
onReady(state);
}
else if (!isInPermission) {
isInPermission = true;
ActivityCompat.requestPermissions(this,
netPermissions(getDesiredPermissions()),
REQUEST_PERMISSION);
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions,
int[] grantResults) {
isInPermission = false;
if (requestCode == REQUEST_PERMISSION) {
if (hasAllPermissions(getDesiredPermissions())) {
onReady(state);
}
else {
onPermissionDenied();
}
}
}
Here's the OnReady() method in my activity class (called when permission is granted):
#Override
protected void onReady(Bundle savedInstanceState) {
_alEntries = new ArrayList();
TaskData tdSource = new TaskData();
// load task item array & trim the excess (unused) ArrayList space
tdSource.LoadData(this, _alEntries);
_alEntries.trimToSize();
// create summary item array & populate it based on task item array
_alSummaries = new ArrayList();
PopulateSummaryList();
_rv = (RecyclerView) findViewById(R.id.rvBookList);
_li = getLayoutInflater();
_rv.setLayoutManager(new LinearLayoutManager(this));
_adapter = new TaskItemAdapter();
_rv.setAdapter(_adapter);
}
The app actually closes when the call to setLayoutManager is executed. Any thoughts on where I've gone wrong or how to proceed in tracking this down?
Seems like it could be a NullPointerException in that your _rv variable is null. Judging by the code it makes sense, your superclass's onCreate method calls onReady() BEFORE setContentView() is called in your subclass's onCreate therefore by the time onReady() is called in your subclass findViewById(R.id.rvBookList) will return null as you haven't set the content of the class yet. To fix this I recommend making your superclass an abstract class. For example, in your superclass do this:
public abstract class BaseActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
this.state = savedInstanceState;
// ... remaining code from your superclass's onCreate()
}
public abstract int getLayoutId();
}
Now in your MainActivity, extend BaseActivity. Since BaseActivity is abstract and getLayoutId() is an abstract method, it will force you to implement getLayoutId() like so:
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public int getLayoutId() {
return R.layout.activity_prog_summary;
}
}
Doing this will ensure that all classes that inherit your superclass will perform the correct order of operations, in that setContentView is called before anything else.

Butterknife not detecting the source of event

I have just started working with Butterknife library and written the following code:
class myActivity extends AppCompatActivity
{
#BindView(R.id.button) Button app1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
public void selectApp(View b)
{
Button clicked=(Button)b;
if(clicked==app1)
Toast.makeText(this,"First App clicked",Toast.LENGTH_LONG).show();
}
}
here selectApp is attached through onClick in the xml view file.
But the problem is clicked==app1 is returning false even when pressing app1. The method is being called but the if condition is coming false.
Can anybody clarify.
Thanks
I think this would work:
if(clicked.getId()==R.id.button)
Also, you can use View b and not parse into a button:
if(b.getId()==R.id.button)
¿Is this your actual code? seems to lack an annotation on the method.

onResume for android annotations

I am using android annotations and have some code that I need to execute in the onResume() function in my activity.
Is it safe to just override the onResume function from the android annotation activity (ie with #EActivity)?
Yeah, you should use these lifecycle methods just like with plain Android activities. There is one thing though: injected Views are not yet available in your onCreate method, this is why #AfterViews exist:
#EActivity(R.layout.views_injected)
public class ViewsInjectedActivity extends Activity {
#ViewById
Button myButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// myButton is not yet available here
}
#AfterViews
void setupViews() {
// myButton is first available here
myButton.setText("Hello");
}
#Override
protected void onResume() {
super.onResume();
// just as usual
}
}
Yeah. Just call super.onResume() and then add your code.
I'd do it just like their on create example here: https://github.com/excilys/androidannotations/wiki/Enhance-activities
You can bind your custom class with lifecycle component of android. It holds life cycle information of android component so that your custom class observe lifecycle changes.
public class MyObserver implements LifecycleObserver {
#OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void connectListener() {
...
}
#OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void disconnectListener() {
...
}
}
myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

#Override on my own methods?

I have a setup similar to what you see below. I have just noticed that "YourClass" is actually implementing some of my logic from "MyClass." Ugh. I tried to throw an #Override above setupViews() in "YourClass" but it won't compile stating, "The method setupViews() of type DataManagerActivity must override a superclass method"
Code changed. It was an example. I just typed the wrong thing. Same question. How can I keep YourClass that extends MyClass from implementing setupViews() from MyClass?
public class MyClass extends Activity {
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setupViews();
...
}
private void setupViews() {
....
}
}
public class YourClass extends MyClass {
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setupViews();
...
}
private void setupViews() {
....
}
}
#Override instructs the compiler to fail unless the method underneath it overrides a method in the superclass (the one you extend from) or one of the interfaces it implements.
Edit: sorry I may have misinterpreted what you meant. The reason why you can't override setupViews() is that it's private in MyClass so that you cannot access or override it from any subclasses.
If that's what you want, then you want your method to be protected - as in, accesible and overrideable in subclasses of the class it's defined in, but not accessible from outside.
Edit 2': so bottom line:
If you want setupViews() to be overridable in subclasses (such as YourClass), make it protected. Otherwise, make it private.
I think you want to use
this.setupViews();

Categories

Resources