Following a brilliant tutorial I've come stuck with a casting issue .
The app is basically a stackoverflow api which uses retrofit and makes calls to retrieve questions and question details etc...
This all said and done I'm lost why it longer launches.
Something is wrong with the cast inn the base activity:
BaseActivity
public class BaseActivity extends AppCompatActivity {
private ControllerCompositionRoot mControllerCompositionRoot;
protected ControllerCompositionRoot getCompositionRoot() {
if(mControllerCompositionRoot == null) {
mControllerCompositionRoot = new ControllerCompositionRoot(
((CustomApplication) getApplication()).getCompositionRoot(),
this
);
}
return mControllerCompositionRoot;
}
}
which gets called inn this class activity
public class QuestionsListActivity extends BaseActivity implements QuestionsListViewMvcImpl.Listener {
private StackoverflowApi mStackoverflowApi;
private QuestionsListViewMvc questionsListViewMvc;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
questionsListViewMvc = getCompositionRoot().getViewMvcFactory().getQuestionListViewMvc(null);
questionsListViewMvc.registerListener(this);
mStackoverflowApi = getCompositionRoot().getStackoverflowApi();
setContentView(questionsListViewMvc.getRootView());
}
#Override
protected void onStart() {
super.onStart();
fetchQuestions();
}
private void fetchQuestions() {
mStackoverflowApi.fetchLastActiveQuestions(Constants.QUESTIONS_LIST_PAGE_SIZE)
.enqueue(new Callback<QuestionsListResponseSchema>() {
#Override
public void onResponse(Call<QuestionsListResponseSchema> call, Response<QuestionsListResponseSchema> response) {
if (response.isSuccessful()) {
bindQuestions(response.body().getQuestions());
} else {
networkCallFailed();
}
}
#Override
public void onFailure(Call<QuestionsListResponseSchema> call, Throwable t) {
networkCallFailed();
}
} );
}
private void bindQuestions(List<QuestionSchema> questionSchemas) {
List<Question> questions = new ArrayList<>(questionSchemas.size());
for (QuestionSchema questionSchema : questionSchemas) {
questions.add(new Question(questionSchema.getId(), questionSchema.getTitle()));
}
questionsListViewMvc.bindQuestions(questions);
}
private void networkCallFailed() {
Toast.makeText(this, R.string.error_network_call_failed, Toast.LENGTH_SHORT).show();
}
#Override
public void onQuestionClicked(Question question) {
QuestionDetailsActivity.start(this, question.getId());
}
}
I would understand first why the cast has to be made which is what I was following in the tutorial buttheres little way I can keep plugging at this wiithout understanding the whole concept of MVC etc..and the implications of how to implement that in an android app.
Any help would be greatly welcome and elaborations as well also.
repo - github
Register the custom application class in manifest.
I checked the repo and found the custom class is not registered. So your custom class is not used as application class.
Related
Firebase -> PhoneAuthProvider -> VerifyPhoneNumber is leaking. I believe, it might be OnVerificationStateChangedCallbacks, which we are sending on call to verifyPhoneNumber.
Steps to reproduce:
Launch the app
Select "PhoneAuthActivity" for phone based authentication
Send Phone Number.
Click back.
When clicking back, the leaked memory appear
Does someone have the same problem? any solution?
public void FirebasePhoneUser(String phoneNumber) {
mCallback = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
Log.d("Completed","");
}
#Override
public void onVerificationFailed(FirebaseException e) {
Log.d("Error","");
}
#Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken forceResendingToken) {
Log.d("onCodeSent", "");
}
};
phoneAuthProvider = PhoneAuthProvider.getInstance();
phoneAuthProvider.verifyPhoneNumber(
phoneNumber,
30,
TimeUnit.SECONDS,
TaskExecutors.MAIN_THREAD,
mCallback
);
}
Given that API is terrible and there's no option to unsubscribe, you have several options to work this around.
Proxy or Decorator. You create another OnVerificationStateChangedCallbacks which delegates method calls to another instance:
// this class must be either top-level or 'static'!
public /*static*/ final class DelegatingVerificationStateCallbacks
extends PhoneAuthProvider.OnVerificationStateChangedCallbacks
implements Closeable {
#Nullable private PhoneAuthProvider.OnVerificationStateChangedCallbacks delegate;
public DelegatingVerificationStateCallbacks(
#NonNull PhoneAuthProvider.OnVerificationStateChangedCallbacks delegate
) {
this.delegate = delegate;
}
#Override public void onCodeSent(
#NonNull String verificationId,
#NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken
) {
if (delegate != null) delegate.onCodeSent(verificationId, forceResendingToken);
}
#Override public void onCodeAutoRetrievalTimeOut(#NonNull String s) {
if (delegate != null) delegate.onCodeAutoRetrievalTimeOut(s);
}
#Override public void onVerificationCompleted(#NonNull PhoneAuthCredential phoneAuthCredential) {
if (delegate != null) delegate.onVerificationCompleted(phoneAuthCredential);
}
#Override public void onVerificationFailed(#NonNull FirebaseException e) {
if (delegate != null) delegate.onVerificationFailed(e);
}
#Override public void close() {
delegate = null;
}
}
I've implemented Closeable for cleanup but you could implement RxJava's Disposable or whatever instead.
The usage pattern here is obvious and well-known:
public final class SomeScreen extends ActivityOrFragmentOrControllerOrWhatever {
private final ArrayList<Closeable> disposeBag = new ArrayList<>();
private void performAuth() {
DelegatingVerificationStateCallbacks callbacks =
new DelegatingVerificationStateCallbacks(
new OnVerificationStateChangedCallbacks() { … }
);
disposeBag.add(callbacks);
phoneAuthProvider.verifyPhoneNumber(…, callbacks);
}
#Override protected void onDestroy() {
for (Closeable c : disposeBag) {
try { c.close(); }
catch (IOException ignored) { }
}
disposeBag.clear();
}
}
Result: Firebase leaks a reference to empty and cheap DelegatingVerificationStateCallbacks, not to Activity.
Nulling references out yourself. You can take approach presented above to clear your own references to Activity. This implies these reference must be explicit, i. e. class must not be anonymous or inner to your activity. You must take full control of class constructor and fields, top-level class or nested static class is a good fit.
Weak reference. This is less explicit and involves some indirection but still works: you instantiate top-level or nested static class, pass Activity to constructor, wrap it in a WeakReference, and assign to a field. That's all, after some time WeakReference#get will start returning null.
Reflection. Very bad and unstable option which could help in some other situations. Sometimes your Activity could be leaked by Android SDK or vendor-specific code, and options from above don't apply. Then you can null out some private fields yourself. Don't do this for Firebase.
I know there are similar questions but it still doesn't answer my question in the manner I need for my current situation.
I have three activity presenters that each need to call a certain data remotely which will therefore call the activity presenter back when data arrives. To create this data listener I created an interface listener and since all three Presenters ask for the same data and retrieve it, all three presenters implement this interface listener.
Interface listener:
interface ListenerInterface {
onGotData();
}
Presenter one:
class PresenterOne implements ListenerInterface{
public void getData() {
DataManager dataManager = new DataManager();
dataManager.getData(this);
}
#Override
public void onGotData(Data data) {
//Do something with data
}
}
Presenter two very similar to presenter one:
class PresenterTwo implements ListenerInterface{
public void getData() {
DataManager dataManager = new DataManager();
dataManager.getData(this);
}
#Override
public void onGotData(Data data) {
//Do something with data
}
}
Assume Presenter three is exactly the same as the previous. The data manager class:
class DataManager {
public void getData(final ListenerInterface listener) {
//Gets data
addOnCompleteListener(new OnCompleteListener<Data data > () {
#Override
public void onComplete (#NonNull DataCall < Data > dataCall) {
listener.onGotData(dataCall.getResults());
}
});
}
}
Would doing so someone call all three presenters since the interface is the one doing the calling or only call the presenter that is passed? Is there anything I should worry about if I followed way? If anyone who knows the Android framework well could provide a detailed answer so I could learn from it more that would be great.
The reason I want to do this is I want to communicate through interfaces between classes.
Sorry if this question is simple for some people but I am still learning.
Thank you very much in advance.
you can use RxBus implementation to make global event (e.g. your onGotData).
First you have to create RxBus class.
public class RxBus {
private static RxBus instance;
private PublishSubject<Event> subject = PublishSubject.create();
public static synchronized RxBus getInstance() {
if (instance == null) {
instance = new RxBus();
}
return instance;
}
private RxBus(){}
public void postEvent(Event event){
subject.onNext(event);
}
public Observable<Event> getEvents(){
return subject;
}
}
And now, you should subscribe to it in BaseActivity or something like this (depends or your project structure).
private RxBus rxbus;
private Subscription rxBusSubscription;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rxBus = RxBus.getInstance();
}
#Override
protected void onResume() {
super.onResume();
if (shouldSubscribeRxBus()) {
rxBusSubscription = rxBus.getEvents()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(event -> {
if (event.getEventType() == Event.EventType.DATA_RECEIVED) {
onGotData(data);
}
});
}
}
Now implement you onGotData as you want.
When you catch data received call:
class DataManager {
public void getData(final ListenerInterface listener) {
//Gets data
addOnCompleteListener(new OnCompleteListener<Data data > () {
#Override
public void onComplete (#NonNull DataCall < Data > dataCall) {
RxBus.getInstance().postEvent(new GotDataEvent(dataCall.getResults()));
}
});
}
}
You can create your Event classes structure as you want.
I am developing an app where I am using clean architecture. In presenter, when something comes to method onCompleted then I must call function from Main activity.
this is my Presenter:
public class CheckInPresenter implements Presenter {
UseCase postCheckInUseCase;
Context context;
#Inject
CheckInPresenter(#Named("putCheckIn") UseCase postCheckInUseCase){
this.postCheckInUseCase = postCheckInUseCase;
}
public void initialize(){this.initializeCheckIn();}
public void initializeCheckIn(){this.putCheckIn();}
public void putCheckIn(){
this.postCheckInUseCase.execute(new CheckInSubscriber());
}
#Override
public void resume() {
}
#Override
public void pause() {
}
#Override
public void destroy() {
}
private final class CheckInSubscriber extends DefaultSubscriber<EventEntity>{
#Override
public void onCompleted() {
Log.d("onCompleted", "OnCompleted");
}
#Override
public void onError(Throwable e) {
Log.d("onError", "OnError: " + e.getMessage());
}
#Override
public void onNext(EventEntity eventEntity) {
Log.d("onNext", "OnNext");
}
}
}
And this is my function from MainActivity that I have to call:
public void getDataForToolbar() {
SharedPreferences sharedPreferences = getSharedPreferences(getResources().getString(R.string.Account_json), Context.MODE_PRIVATE);
final String account = sharedPreferences.getString(getResources().getString(R.string.account_json), null);
if (account != null) {
Gson gson = new Gson();
mAccount = gson.fromJson(account, AccountModel.class);
for (CompanyModel com : mAccount.getCompanies()) {
String name = com.getName();
company_name.setText(name);
logo_url = com.getLogo_url();
}
if (logo_url == null || logo_url.isEmpty()) {
Picasso
.with(this)
.load(R.drawable.default_company)
.resize(70, 58)
.transform(new RoundedTransformation(8, 0))
.into(toolbarImage);
} else {
picassoLoader(this, toolbarImage, logo_url);
}
String username = mAccount.getUsername();
if(mAccount.getStatus()){
aUsername.setText(username + "/" + getResources().getString(R.string.on_duty));
aUsername.setBackgroundColor(ContextCompat.getColor(mContext, R.color.colorGreen));
}else{
aUsername.setText(username + "/" + getResources().getString(R.string.off_duty));
aUsername.setBackgroundColor(ContextCompat.getColor(mContext, R.color.colorWhite));
}
}
}
Could someone helps me how to call this function into my onCompleted method in Presenter? Thanks in advance.
If you want to call some Activity's function from another object, you'll have to pass Activity's reference to that object. This means that you need to add Activity parameter to presenter's constructor.
Side note
I know that what you're implementing is called a "clean architecture" in many places (including the official MVP tutorials by Google), but you might want to read my posts on the subject in order to get an alternative view on what "clean" on Android should look like.
Why activities in Android are not UI elements
MVC and MVP architectural patterns in Android
Create interface IView and make your Activity to implement it.
In IView create method void getDataForToolbar();
I see #Inject annotation in your CheckInPresenter, so if you are using Dagger 2, update you Dagger module's constructor with IView, create a provider method for it and provide it for CheckInPresenter in this module.
Place IView in constructor of CheckInPresenter and update provider method for CheckInPresenter in Dagger module and Dagger component initialization in your Activity.
For example, it might look like this:
public class YourActivity implements IView {
...
}
#Module
public class YourModule {
private IView view;
public YourModule(IView view) {
this.view = view;
}
#Provides
public IView provideView() {
return view;
}
#Provides
#YourScope
public Presenter providePresenter() {
return new YourPresenter(view);
}
}
Just complete your existing Presenter and Module with IView.
After that call in your onCompleted method view.getDataForToolbar().
I have a Service class that I am using to make web service calls using Volley:
public class AccountService {
public static void forgotPassword(Context c, String emailAddress) {
String url = "myUrl";
JsonArrayRequest request = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
// done
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
Volley.newRequestQueue(c).add(request);
}
}
And I'm calling it from an Activity like this:
public class ForgotPasswordActivity extends AppCompatActivity implements View.OnClickListener{
private void submit() {
accountService.forgotPassword();
}
}
When the Volley request is finished, I want to update the UI in my activity. How can I do this considering it is an asynchronous request? Am I able to call a method from the AccountService class in my activity? Thanks for the help
Pass a listener object to the AccountService and then send communication success or error to the activity.
Try as per below (you should not pass the layout to the AccountService which will create some unnecessary issues)
public class ForgotPasswordActivity extends AppCompatActivity
implements View.OnClickListener,
AccountServiceCallback{
private void submit() {
AccountService.forgotPassword("email#123.com", this);
}
#Override
public void onClick(View v) {
}
#Override
public void onResponse(JSONArray response) {
// UPDATE UI as per on response requirement
}
#Override
public void onErrorResponse(VollyError error) {
// UPDATE UI as per response flow
}
}
public class AccountService {
public static void forgotPassword(Context c, String email, final
AccountServiceCallback callback) {
String url = "myUrl";
JsonArrayRequest request = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
// done
callback.onResponse(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
callback.onErrorResponse(error);
}
});
Volley.newRequestQueue(c).add(request);
}
interface AccountServiceCallback {
public void onResponse(JSONArray response);
public void onErrorResponse(VollyError error);
}
}
You will have to find a way to get the result of your background work back onto the main thread so it can make changes to the view hierarchy. There are a LOT of ways to do this, and most of them are not really good.
But before you even do that, there are problems with your code. First, if you are thinking you made an Android Service component, you didn't actually do that. You made a class with the name AccountService, which does nothing special in the Android world.
Second, your call of forgotPassword() passes no arguments, but your definition of forgotPassword() in AccountService has a completely different signature. This wouldn't compile.
You should probably start learning about Android-specific asynchronous programming patterns and develop a strategy for solving your problem before writing code, because you'll almost certainly do it wrong without understanding what you're doing first.
I was wondering if I could change the way my method function, similar to Blocks iOS.
So I have this interface create in class API.java
public interface APIListener {
void apiResponseSuccess(String output);
void apiResponseFailed(String output);
}
public APIListener listener = null;
public void myMethod{
listener.apiResponseSuccess("output");
}
In order to call my interface created, i have to implements
API.APIListener. and override the functions
#Override
public void apiResponseSuccess(Object output) {
Log.i("output from api",(String) output);
}
#Override
public void apiResponseFailed(String output) {
}
And to call it, I have to use :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
API api = new API();
api.listener = this;
api.myMethod();
}
But drawbacks using this, It's hard to maintain if I call many methods inside the API, because all the results will go to apiResponseSuccess in my class, and have to tag which one coming from. Where the iOS comes with Blocks, it becomes easier. so basically, Is there a way to return the interface methods direct when we call it. similar to this
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
API api = new API();
api.listener = this;
api.myMethod(
public void apiResponseSuccess(Object output) {
Log.i("output from api",(String) output);
}
public void apiResponseFailed(String output) {
}); //so the result will go in separately inside the where the function is called.
}
You can achieve it easily.
Your api method should get APIListener as a parameter - so when you'll call it you'll have something like this:
api.myMethod(new APIListener() {
#Override
public void apiResponseSuccess(Object output) {
Log.i("output from api",(String) output);
}
#Override
public void apiResponseFailed(String output) {
}
});
You can also pass more params of course:
api.myMethod(new APIListener() {
#Override
public void apiResponseSuccess(Object output) {
Log.i("output from api",(String) output);
}
#Override
public void apiResponseFailed(String output) {
}
}, "my String", true);
BUT... notice that with your current implementation that the activity is the listener of your API call you'll have a memory leak!
You can solve it in several ways:
Don't make the listener anonymous ("ios block") but an inner static class that takes the activity as a WeakReference
Encapsulate the WeakReference inside your API and manage your listeners there.