I had an Activity that extended AppCompactActivity, and in onCreate method I setted the Toolbar using setSupportActionBar method in the usual way:
public class StepMasterActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_step_master);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);`
}
}
But now I have a ViewModel component and to share data between fragments that are the children of this activity and manages lifecycles I have to get this component in Activity and so I make this extend LifecycleActivity.
public class StepMasterActivity extends LifecycleActivity {
#Override
public class StepMasterActivity extends LifecycleActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_step_master);
// setToolbar();
SharedViewModel sharedViewModel = ViewModelProviders.of(this).get(SharedViewModel.class);
}
}
But I noticed that LifecycleActivity has nothing to do with AppCompatActivity neither FragmentActivity does.
public class LifecycleActivity extends FragmentActivity implements LifecycleRegistryOwner {
private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);
public LifecycleActivity() {
}
public LifecycleRegistry getLifecycle() {
return this.mRegistry;
}
}
Am I doing something wrong?
UPDATE 2017-10-05: LifecycleActivity has been deprecated. If you use 26.1.0 or higher of support-fragment and appcompat-v7, both FragmentActivity and AppCompatActivity implement LifecycleOwner.
The original answer appears below for historical (and possibly hysterical) purposes.
Quoting the documentation:
Note: Since the Architecture Components are in alpha stage, Fragment and AppCompatActivity classes cannot implement it (because we cannot add a dependency from a stable component to an unstable API). Until Lifecycle is stable, LifecycleActivity and LifecycleFragment classes are provided for convenience. After the Lifecycles project is released, support library fragments and activities will implement the LifecycleOwner interface; LifecycleActivity and LifecycleFragment will be deprecated at that time.
LifecycleActivity is tied to FragmentActivity, not AppCompatActivity.
You should be able to create your own AppCompatLifecycleActivity as follows:
public class AppCompatLifecycleActivity extends AppCompatActivity implements LifecycleRegistryOwner {
private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);
#Override
public LifecycleRegistry getLifecycle() {
return mRegistry;
}
}
The most recent support library revision 26.1.0 will allow you to use AppCompatActivity
Fragment and FragmentActivity (the base class for AppCompatActivity)
now implement the LifecycleOwner interface from Architecture
Components.
Related
I'd like to create a fragment using a generic Service, but can't find a way to define the service.
It could be represented like that.
Fragment MyGenericFragment<S service> extends Fragments
private S service;
Fragment FragmentA extends MyGenericFragment<SpecializedService>
In my FragmentA I try define my specialized service like this :
#Inject
SpecializedService service;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
((App) getActivity().getApplication()).inject(this);
}
Is there a way to construct Fragments this way.
Objective is to avoid duplicate code for a same representation.
I find a first solution, but I don't know if it's a good practice (quite sure not, but do the job).
FragmentA can declare a service, receiving it by Dagger inject and set it as the service
Fragment FragmentA extends MyGenericFragment<SpecializedService>
#Inject
DedicatedService dedicatedService;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
((App) getActivity().getApplication()).inject(this);
this.service = dedicatedService;
}
I have a BaseActivity which is an abstract activity and isn't registered in AndroidManifest. BaseActivity will call getPresenter in activity's lifecycle.
public abstract class BaseActivity extends AppCompatActivity{
public abstract Presenter getPresenter;
public abstract int getLayout();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayout());
getPresenter().attachView(this);
}
#Override
protected void onDestroy() {
super.onDestroy();
getPresenter().detachView();
}
}
I use ActivityTestRule to launch the BaseActivity, but the following error is shown.
java.lang.RuntimeException: Could not launch activity
How to test the getPresenter().attachView(this) and getPresenter().detachView() are called in correct activity's lifecycle?
I don't have quite big experience with Android Testing, especially unit testing, but I've already found this post, which may be useful for you:
Is it possible to test an Abstract activity with Robolectric
Also on Github page of Robolectric I'd found this: https://github.com/robolectric/robolectric/issues/1441
So all I can say according to your question, that yes you can test your abstract class, at least with Robolectric.
Read also: https://gualtierotesta.wordpress.com/2015/01/28/tutorial-java-abstract-classes-testing/
EDIT: Nowadays, Robolectric doesn't support directly API 23, but you can "downgrade" it in configuration of test class, like below:
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 21)
public class MainActivityTest {
MainActivity_ activity = Robolectric.setupActivity(MainActivity.class);
}
The error is shown because the BaseActivity isn't registered in Android Manifest. It seems that there are some solutions to add an activity in test package.
However, I finally choose another solution, delegate the activity's lifecycle to others.
This idea is mentioned in Mosby playbook.
http://hannesdorfmann.com/android/mosby-playbook/
New BaseActivity:
public abstract class BaseActivity extends AppCompatActivity implements BaseMvpView, DelegateCallback{
private ActivityMvpDelegate activityDelegate;
protected ActivityMvpDelegate getActivityDelegate() {
if (activityDelegate == null) {
activityDelegate = createActivityDelegate();
}
return activityDelegate;
}
protected ActivityMvpDelegate createActivityDelegate() {
return new ActivityMvpDelegateImpl(this, this);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivityDelegate().onCreate(savedInstanceState);
}
#Override
protected void onDestroy() {
super.onDestroy();
getActivityDelegate().onDestroy();
}
}
Finally, I can test the delegate class without activity's lifecycle.
I'm using Roboguice to inject my dependencies but it's not workink. I have a class that extends RoboActivity and my attribute still null.
public class SplashActivity extends RoboActivity {
#Inject
private PropertyReader propertyReader;
#Inject
Vibrator v1;
}
Should i do some aditional config?
Thank in advance.
Edit: it only works if i do RoboGuice.injectMembers in every class that i have objects to injects. Can i do it only one time for the whole app?
You should use the injected non view fields after the activity onCreate. InjectMembers runs in super.onCreate(savedInstanceState) you dont have to call it.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
v1.vibrate();
}
view fields should be used after onCreateView() is called.
I'm writing an application in which i have a set of code which i want to be available in all of my Activities and ActivityGroups. However, to achieve this, I have extended my activities as:
//custom Activity
public abstract class BaseActivity extends Activity
//custom ActivityGroup
public abstract class BaseActivityGroup extends ActivityGroup
//implemented activities in my app
public class PickUser extends BaseActivity
//and
public class Home extends BaseActivityGroup
Now the thing is, whatever the custom code i write in BaseActivity, I have to write the same in BaseActivityGroup too (as in current implementation). This is prone to code-sync problems and i believe not a good technique.
So, how can i make my extensions in such a way that I only write custom code in BaseActivity and my BaseActivityGroup extends ActivityGroup - which is conceived from BaseActivity class?
If i observe how android does this, so the ActivityGroup in android extends Activity class. And I also want to write my custom ActivityGroup class (known as BaseActivityGroup) that actually extends BaseActivity (which is an extended Activity).
Any ideas/suggestions?
First of all ActivityGroups are bad and should not be used. They are deprecated and it is preferred to use a single activity with multiple fragments.
If you must use an activitygroup you are probably best of by implementing a delegate pattern.
Create a delegate that handles all the common methods such as onCreate, onResume and use that in the bases. In this example I save a reference to the activity in the delegate. This circular referencing might not be the pretties. An alternative is to pass on the activity to the methods in the delegate.
public class ActivityDelegate() {
private Activity mActivity;
public ActivityDelegate(final Activity activity) {
mActivity = activity;
}
public void onCreate(final Bundle savedInstanceState) {
// Do stuff.
}
}
public abstract class BaseActivity extends Activity {
private ActivityDelegate mDelegate = new ActivityDelegate(this);
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate(savedInstanceState);
}
...
}
public abstract class BaseActivityGroup extends ActivityGroup {
private ActivityDelegate mDelegate = new ActivityDelegate(this);
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate(savedInstanceState);
}
...
}
Add an extra final class, called Base.
This one will only contain methods to be called by the other Base classes, such as for instance:
public static boolean createOptionsMenu(final Menu menu,
final MenuInflater inflater) {
inflater.inflate(R.menu.main_menu, menu);
return true;
}
Then, in your BaseActivity and BaseActivityGroup classes, you would call:
#Override
public final boolean onCreateOptionsMenu(final Menu menu) {
return Base.createOptionsMenu(menu, getMenuInflater());
}
Hope it helps!
Just Extend everything to BaseActivity including BaseGroupActivity as everything is a child of Activity in android
you can put your login in a separate file under a method. now call the same method from both BaseActivity and BaseActivityGroup if you need activity instance in file . pass context through constructor
Is there a way to replace the default Activity class with own implementation extending from this class using roboguice?
For instance an activity like this:
public class MyActivity extends Activity
{...}
would replace the default Activity class and would become the base activity for all other derived activities.
Yes. The easiest way is to have your base activity extend from RoboActivity.
Eg.
class MyBaseActivity extends RoboActivity { ... }
And then have all of your activities extend from MyBaseActivity.
However, if for some reason you don't wish to extend from RoboActivity, you can easily add injection to your own activities by doing the following:
class MyBaseActivity extends Activity {
public void onCreate(Bundle b) {
super.onCreate(b);
RoboGuice.getInjector(this).injectMembersWithoutViews(this);
}
public void onContentChanged() {
super.onContentChanged();
RoboGuice.getInjector(this).injectViewMembers(this);
}
}
Take a look at RoboActivity's source for more details. As long as you don't need events, the changes required are quite simple.