Fresco is not working when I am initializing it in the OnCreate or OnCreateView of the fragment. Is there something I am doing wrong?
You have to initialize Fresco only once, in your custom Application.
Example:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Fresco.initialize(this);
}
}
More info: http://frescolib.org/docs/
Related
I am wondering when #ViewById-annotated views are injected in AndroidAnnotations. Basically, I want to know if it is safe to access one of these views during onResume? I assume they are injected during onCreate but would like confirmation.
Thank you.
The easiest way to figure out exactly when injection happens is to inspect the code that AndroidAnnotations generates. For your examples, I made a simple Activity and Fragment as below:
#EActivity(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
#ViewById(R.id.textView)
TextView textView;
#AfterViews
public void activityTestMethod() {
}
}
#EFragment(R.layout.fragment_main)
public class MainFragment extends Fragment {
#ViewById(R.id.imageView)
ImageView imageView;
#AfterViews
public void fragmentTestMethod() {
}
}
and then ran ./gradlew app:assembleDebug to force AndroidAnnotations to generate the corresponding classes MainActivity_ and MainFragment_. Let's look at MainActivity_ first (irrelevant code omitted):
public final class MainActivity_
extends MainActivity
implements HasViews, OnViewChangedListener
{
#Override
public void onCreate(Bundle savedInstanceState) {
OnViewChangedNotifier previousNotifier = OnViewChangedNotifier.replaceNotifier(onViewChangedNotifier_);
init_(savedInstanceState);
super.onCreate(savedInstanceState);
OnViewChangedNotifier.replaceNotifier(previousNotifier);
setContentView(R.layout.activity_main);
}
private void init_(Bundle savedInstanceState) {
OnViewChangedNotifier.registerOnViewChangedListener(this);
}
#Override
public void setContentView(int layoutResID) {
super.setContentView(layoutResID);
onViewChangedNotifier_.notifyViewChanged(this);
}
#Override
public void onViewChanged(HasViews hasViews) {
this.textView = hasViews.internalFindViewById(R.id.textView);
activityTestMethod();
}
}
The sequence of events that results in our views being bound and our #AfterViews methods being called is as follows:
In onCreate, the MainActivity_ instance is registered as an OnViewChangedNotifier.
onCreate calls setContentView.
setContentView calls notifyViewChanged, which triggers a (synchronous) call to onViewChanged.
onViewChanged binds all fields annotated with #ViewById, then calls all methods annotated with #AfterViews.
Therefore, #ViewById-annotated views are bound and available for use after onCreate has been called, and #AfterViews-annotated methods will be executed at the end of onCreate and before any other Activity lifecycle method.
The story is similar for MainFragment_:
public final class MainFragment_
extends com.stkent.aatest.MainFragment
implements HasViews, OnViewChangedListener
{
#Override
public void onCreate(Bundle savedInstanceState) {
OnViewChangedNotifier previousNotifier = OnViewChangedNotifier.replaceNotifier(onViewChangedNotifier_);
init_(savedInstanceState);
super.onCreate(savedInstanceState);
OnViewChangedNotifier.replaceNotifier(previousNotifier);
}
private void init_(Bundle savedInstanceState) {
OnViewChangedNotifier.registerOnViewChangedListener(this);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
onViewChangedNotifier_.notifyViewChanged(this);
}
#Override
public void onViewChanged(HasViews hasViews) {
this.imageView = hasViews.internalFindViewById(R.id.imageView);
fragmentTestMethod();
}
}
The sequence of events that results in our views being bound and our #AfterViews methods being called is as follows:
In onCreate, the MainFragment_ instance is registered as an OnViewChangedNotifier.
onViewCreated calls notifyViewChanged, which triggers a (synchronous) call to onViewChanged.
onViewChanged binds all fields annotated with #ViewById, then calls all methods annotated with #AfterViews.
Therefore, #ViewById-annotated views are bound and available for use after onViewCreated has been called, and #AfterViews-annotated methods will be executed at the end of onViewCreated and before any other Fragment lifecycle method.
In both our examples, all view binding is performed in a lifecycle method that occurs much earlier than onResume, so you are safe to access them there :)
Do I need to put FacebookSdk.sdkInitialize(getApplicationContext()); in every activity? Or just the first activity?
They are asking to initialize it in Application class onCreate() Method.
public class MyApplication extends Application {
// Updated your class body:
#Override
public void onCreate() {
super.onCreate();
// Initialize the SDK before executing any other operations,
FacebookSdk.sdkInitialize(getApplicationContext());
AppEventsLogger.activateApp(this);
}
Link to the original answer
Just to make it clear, this is not I want. I want to access another Activity's context.
Suppose I've two activities, MainActivity and WebActivity. In MainActivity I used oAuth2 login, and after login I start the WebActivity. In WebActivity I need to logout with the function mTencent.logout(MainActivity.this);, the question is how can I access MainActivity from WebActivity?
If I do this directly, I get the error,
MainActivity is not an enclosing class?
Considering I'm a starter of android, here may be not the exact way to implement it.
Will someone help? Thank you!
The API : void com.tencent.tauth.Tencent.logout(Context context)
Use Application context in your login and logout methods. As they will be managed at Application level.
So change mTencent.logout(MainActivity.this); to mTencent.logout(getApplicationContext());.
Also change your login method to work in application context.
Instead of using context of one activity in other which may result in crashes sometimes.
u can use libraries like EventBus to link the code.
Define a class which implements event u want to perform eg:LogOutEvent.java
public static class LogOutEvent { /* Additional fields if needed */ }
U can post events like logout from WebViewActivity.java using following command
EventBus.getDefault().post(new LogOutEvent());
and in MainActivity you first need to register event bus
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
and then in MainActivity you can subscribe for events like this
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(LogOutEvent event) {/* Do log out here */};
There is a good practice solution to your problem which involves certain steps to be performed:
1- Define an interface:
public interface LogOutInterface {
public void logout();
}
2- Have your MainActivity implement this interface:
public class MainActivity extends ???? implements LogOutInterface {
...
#Override
public void logout(){
//your logout procedure
}
}
3- Have a public method for your WebActivity and allow it to accept LogOutInterface:
public class WebActivity ... {
private LogOutInterface logoutInterface;
...
public void setLogOut(LogOutInterface logoutInterface) {
this.logoutInterface = logoutInterface;
}
}
4- call setLogOut from MainActivity:
public class MainActivity ... {
public void yourmethod() {
...
webActivity.setLogOut(this);
}
}
5- call logout function from your WebActivity:
public class WebActivity ... {
...
public void yourmethod() {
logoutInterface.logout();
}
}
hope this helps.
This is a workable one.
In the MainActivity, public static Activity thisActivity; & thisActivity = this; then in the WebActivity mTencent.logout(MainActivity.thisActivity);
or just can put the logout function as public static function of MainActivity,
public static void logout() {
if (mTencent.isSessionValid()) {
mTencent.logout(thisActivity);
}
}
then call MainActivity.logout() from WebActivity.
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 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());