I am using FirebaseInAppMessaging and it's works. Then i register action call back using FirebaseInAppMessagingClickListener, it's not calling.
public class InAppMessageClick implements FirebaseInAppMessagingClickListener, FirebaseInAppMessagingImpressionListener, FirebaseInAppMessagingDisplay {
String TAG = "InAppMessageClick";
#Override
public void messageClicked(InAppMessage inAppMessage, Action action) {
// Determine which URL the user clicked
String url = action.getActionUrl();
LogUtils.i(TAG, "Action URL : "+url);
// Get general information about the campaign
CampaignMetadata metadata = inAppMessage.getCampaignMetadata();
Log.i(TAG," Metadata : "+metadata);
}
#Override
public void impressionDetected(InAppMessage inAppMessage) {
LogUtils.i(TAG, "impressionDetected Action URL : "+inAppMessage.getCampaignMetadata().getCampaignName());
}
#Override
public void displayMessage(InAppMessage inAppMessage, FirebaseInAppMessagingDisplayCallbacks firebaseInAppMessagingDisplayCallbacks) {
LogUtils.i(TAG, "displayMessage Action URL : "+inAppMessage.getCampaignMetadata().getCampaignName());
}
}
And i register this click listener in MainActivity's onCreate
InAppMessageClick inAppMessageClick = new InAppMessageClick();
FirebaseInAppMessaging.getInstance().setMessageDisplayComponent(inAppMessageClick);
FirebaseInAppMessaging.getInstance().addClickListener(inAppMessageClick);
i tried to register listener for two ways.
InAppMessageClick inAppMessageClick = new InAppMessageClick();
FirebaseInAppMessaging.getInstance().addClickListener(inAppMessageClick);`
Or
FirebaseInAppMessaging.getInstance().addClickListener(inAppMessageClick, new Executor() {
#Override
public void execute(Runnable command) {
LogUtils.i("MainActivity", "FIAM CLICKED EXECUTOR");
}
});
`
And using gradle
implementation 'com.google.firebase:firebase-inappmessaging-display:18.0.2'
implementation 'com.google.firebase:firebase-core:17.0.1'
Could it be related to this issue opened 7 days ago?
https://github.com/firebase/firebase-android-sdk/issues/681
For some reason, FirebaseInAppMessaging remove all listeners every time an activity goes to background. You can see this by putting a break point on removeAllListeners method of DeveloperListenerManager class.
Registering your listener in the onResume method of your main activity is a way to deal with this problem.
Dependencies:
implementation platform('com.google.firebase:firebase-bom:26.6.0')
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-inappmessaging-display-ktx'
implementation 'com.google.firebase:firebase-inappmessaging-ktx'
code on MainActivity onCreateMethod:
val firebaseIam = Firebase.inAppMessaging
firebaseIam.addClickListener { inAppMessage, action ->
//write your functionality
Log.d("here","successful)
}
Related
I've written a small Spring Boot/Vaadin application that displays a simple UI to take user input and make a call to another service that takes some time to run. When the task is submitted, I'm displaying a progress dialog that shows a progress bar, a message informing the user what is going on and a close button to allow them to close the dialog when the job completes. I'm using a ListenableFuture to be notified when the task is done.
I can get the dialog to appear with status of "executing" and the progress bar doing its thing, but when the task is done (I have debug statements going to the console to let me know), it's not triggering the logic to update the status message and enable the close button. I can't figure out what I'm doing wrong.
Here's the code:
MainView1.java
#Route("rescheduleWorkOrders1")
#CssImport("./styles/shared-styles.css")
public class MainView1 extends VerticalLayout {
...
private final BackendService service;
public MainView1(BackendService service) {
this.service = service;
configureView();
addSubmitButton();
bindFields();
}
private void addSubmitButton() {
Button submit = new Button("Submit", this::submit);
add(submit);
}
private void submit(ClickEvent<?> event) {
UserData data = binder.getBean();
ListenableFuture<ResponseEntity<String>> future = service.executeTask(data);
ProgressDialog dialog = new ProgressDialog(future);
dialog.open();
}
private void configureView() {
...
}
private void bindFields() {
...
}
}
ProgressDialog.java
public class ProgressDialog extends Dialog {
private final ListenableFuture<ResponseEntity<String>> future;
private ProgressBar bar;
private Paragraph message;
private Button close;
public ProgressDialog(ListenableFuture<ResponseEntity<String>> future) {
super();
this.future = future;
configureView();
this.future.addCallback(new ListenableFutureCallback<>() {
#Override
public void onSuccess(ResponseEntity<String> result) {
message.setText("Task complete. Status: " + result.getStatusCode());
bar.setVisible(false);
close.setEnabled(true);
}
#Override
public void onFailure(Throwable ex) {
message.setText(ex.getMessage());
bar.setVisible(false);
close.setEnabled(true);
}
});
}
private void configureView() {
bar = new ProgressBar();
bar.setIndeterminate(true);
bar.setVisible(true);
message = new Paragraph("Executing task ...");
close = new Button("Close", this::close);
close.setEnabled(false);
add(bar, message, close);
}
private void close(ClickEvent<?> event) {
this.close();
}
}
BackendService.java
#Service
public class BackendService {
#Async
public ListenableFuture<ResponseEntity<String>> executeTask(UserData data) {
...
RestTemplate template = new RestTemplate();
ResponseEntity<String> response = template.postForEntity(uri, entity, String.class);
System.out.println(response);
return AsyncResult.forValue(response);
}
}
Note: I do have #EnableAsync specified in a #Configuration annotated class.
When dealing with asynchronous code in Vaadin you need to:
Use UI#access when updating the UI outside an active request. This acquires a lock on the UI, to prevent it being updated by two threads simultaneously.
Enable server push by adding the #Push annotation to your main layout or view. This allows the server to push updates to the client even if no request is active.
Without the former, you can get ConcurrentModificationExceptions in the best case, and very subtle bugs in the worst.
Without the latter, the changes will be applied (i.e. dialog closed), but the changes will only be sent to the client the next time the client sends a request. I believe this is your main issue.
More information can be found in the documentation.
I am using mvvm architecture I would like to notify view when volley post request is successful, what i could do is to instantiate ViewModel in appRepository class and then post values to a liveData, but i guess that's not a good approach as I haven't seen a similar practice. Can anyone suggest me a good approach to return my response to ui, or at least notify that post request has been successful.
From fragment/View I trigger this method
// save data to api
checkInViewModel.updateEventPersonEntity(eventPersonsEntity);
ViewModel forwards it to apprespository
public void updateEventPersonEntity(EventPersonsEntity eventPersonsEntity) {
mRepository.updateEventPersonEntity(eventPersonsEntity);
}
AppRepository.Java class
public void updateEventPersonEntity(EventPersonsEntity eventPersonsEntity) {
executor.execute(() -> {
// mDb.eventPersonsDao().update(eventPersonsEntity);
if (isNetworkAvailable(context)) {
post_updateEventPersonEntity(eventPersonsEntity);
}
});
}
private void post_updateEventPersonEntity(EventPersonsEntity eventPersonsEntity) {
Map<String, Object> params = new HashMap<>();
params.put("EventPersonId", eventPersonsEntity.getEventPersonId());
params.put("EventId", eventPersonsEntity.getEventId());
params.put("PersonId", eventPersonsEntity.getPersonId());
params.put("CashStart", parseDoubleToGerman(eventPersonsEntity.getCashStart()));
params.put("CashEnd", parseDoubleToGerman(eventPersonsEntity.getCashEnd()));
params.put("StartingTime", String.valueOf(eventPersonsEntity.getStartingTime()));
params.put("EndingTime", String.valueOf(eventPersonsEntity.getEndingTime()));
params.put("isChekcedIn", eventPersonsEntity.getIsCheckedIn());
params.put("isChekcedOut", eventPersonsEntity.getIsCheckedOut());
JSONObject objRegData = new JSONObject(params);
String eventPersonApi = APP_URL.EVENT_PERSONS_API + eventPersonsEntity.getEventPersonId();
RequestQueueSingleton.getInstance(context).objectRequest(eventPersonApi, Request.Method.PUT, this::onSuccess_updateEventPersonEntity, this::onError, objRegData);
}
private void onError(VolleyError error) {
Log.d(APP_REPOSITORY_TAG, "requestError: " + error);
}
private void onSuccess_updateEventPersonEntity(JSONObject jsonObject) {
// notify ui
}
You can do this same as you did for your success response logic in repository. Simply create new callback interface:
interface OnEventUpdatedListener{
void eventUpdated();
}
Then, update your method to look like this, passing the listener to the actual method that does the work:
public void updateEventPersonEntity(EventPersonsEntity eventPersonsEntity, OnEventUpdatedListener listener) {
mRepository.updateEventPersonEntity(eventPersonsEntity, listener);
}
Pass this inside your:
if (isNetworkAvailable(context)) {
post_updateEventPersonEntity(eventPersonsEntity, listener);
}
After that, in your onSuccess() method simply call:
private void onSuccess_updateEventPersonEntity(JSONObject jsonObject) {
listener.eventUpdated();
}
Finally, you will have the info when the update happens, in the calling site, if you call your repository like this:
updateEventPersonEntity(null, new OnEventUpdatedListener() {
#Override
public void EventUpdated() {
// Do your logic here
}
});
Is there any way to implement an interface in dart/flutter without having to use a class?
Currently, how I implement it is with the code below
class _UserSignupInterface extends _SignupSelectUsernamePageState
implements UserSignupInterface {
#override
void onSuccess() {
_navigateToUserPage();
}
#override
void onError() {
setState(() {
_isSignupClickable = true;
});
}
}
_attemptSignup() {
UserSingleton userSingletonInstance = UserSingleton().getInstance();
UserSignupInterface _userSignupInterface = _UserSignupInterface();
UserSingleton().getInstance().user.username = _username;
UserLoginController.attemptSignup(_userSignupInterface,
userSingletonInstance.user, userSingletonInstance.userDetail, _groupID);
}
However, I would like to implement these interface methods without having to use a class, just as I would in java. Something that would look like the code below.
UserController.attemptSignup(context, new UserSignupRequest() {
#Override
public void onSuccess(User user, UserDetail userDetail, Group group) {
btnContinueWithFacebook.setEnabled(true);
Intent intent = new Intent(context, ScoopActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
progressBar.setVisibility(View.GONE);
startActivity(intent);
}
#Override
public void onFail() {
Log.d(APP.TAG, "Signup request has failed");
btnContinueWithFacebook.setEnabled(true);
progressBar.setVisibility(View.GONE);
/**
* TODO:: Notify user of signup attempt failure
*/
}
}, user, userDetail, group_id);
There is no such feature in Dart. In order to implement an interface, you have to declare a class.
The alternatives is to define the API to accept individual functions instead of a single object, or to declare a helper class which takes the behavior of the necessary methods as constructor arguments.
Example:
class _UserSignupInterface extends _SignupSelectUsernamePageState
implements UserSignupInterface {
void Function(_UserSingupInterface self) _onSuccess;
void Function(_UserSingupInterface self) _onError;
_UserSignupInterface(this._onSuccess, this._onError);
#override
void onSuccess() {
_onSuccess(this);
}
#override
void onError() {
_onError(this);
}
}
Then you can call it as:
... _UserSignupInterface((self) {
self._navigateToUserPage();
}, (self) {
self.setState(() {
self._isSignupClickable = true;
});
})
It's not as pretty as Java, admittedly.
I know this question already has an answer but I would like to add a more neater implementation close to Java inline interface which I normally use.
First, we have the class which acts as our interface:
class HttpRequestCallback {
/// Called when http request is completed
final void Function() onCompleted;
/// Called when http request is successful
/// * [message] is a dynamic object returned by the http server response
final void Function(dynamic message) onSuccess;
/// Called when http request fail
/// * [message] is a dynamic object returned by the http server response
final void Function(dynamic message) onError;
HttpRequestCallback(
{required this.onCompleted,
required this.onSuccess,
required this.onError});
}
Secondly, we have a function that expects the interface as parameter:
Future<void> login(LoginModel model, {HttpRequestCallback? callback}) async {
var response = await httpClient.doPost(app_constants.ApiEndpoints.Login,
body: model.toJson());
// Api request completed
callback?.onCompleted();
if (response.success) {
// Api request successful
callback?.onSuccess(LoginResponseModel.fromJson(
response.message as Map<String, dynamic>));
} else {
// Api request failed
callback?.onError(response.message);
}
}
Finally, we call the function passing our interface as an argument:
...
apiService.login(loginModel,
callback: HttpRequestCallback(
onCompleted: () {
//...
},
onSuccess: (message) {
//...
},
onError: (message) {
//...
}
));
...
I think you are looking for anonymous class in Dart, but it's not supported.
If i understood well what you are trying to do, you can achieve something similar by passing function as parameter in this way:
enum ResultLogin { OK, ERROR }
class Login {
Function _listener; // generic function
Login(listener) {
_listener = listener;
}
void run(){
ResultLogin result = *DO_YOUR_LOGIN_FUNCTION*;
_listener(result);
}
}
class Main {
void doLogin(){
Login myLogin = new Login((ResultLogin result){
switch(result){
case OK:
print("OK");
break;
case ERROR:
print("ERROR");
break;
default:
break;
}
}
);
}
}
In this way you can handle your result and refresh some widget state according to your needs.
Im trying to implement MVVM architecture using ViewModel and LiveData. These two methods are inside a Activity:
private void handleResult(BoardViewModel vm) {
vm.getLiveDataSingleObj("Result").observe(this, new Observer<Object>() {
#Override
public void onChanged(#Nullable Object resultObj) {
Result result = (Result) resultObj;
if (!result.isCompleted()) return;
gotoResult();
}
});
}
And
private void gotoResult() {
Log.w(LOG_TAG, "Result: Moving to next activity");
Intent intent = new Intent(boardActivity, ResultActivity.class);
intent.putExtra("LEVEL", levelIndex);
intent.putExtra("MAP", mapIndex);
startActivity(intent);
}
The handleResult method is setup to listen for result objects that indicate that the game has ended and it is time to move on to the next activity ("gotoResult"). However, this completely breaks the navigation of the app, when i go back and then say attempt to start a new game session i instead instantly go to the next activity telling me I've already won.
Any ideas as to why it fires multiple times and eventually stops, letting me start a new session. To clarify, if I remove the gotoResult the logic works every single time no errors with indexes out of bounds or what have you, it's only when I add the goto that everything breaks.
ViewModel:
private void setupHashTypes() {
hashLiveData.put(KEY_BOARD, liveDataBoardQuery);
hashLiveData.put(KEY_STEPS_COUNTER, game.getStepsTakenLiveData());
hashLiveData.put(KEY_PATH_CHANGE, game.getPathChangedLiveData());
hashLiveData.put(KEY_VALUE_CHANGE, game.getValueChangeLiveData());
hashLiveData.put(KEY_TIMER, game.getTimerLiveData());
hashLiveData.put(KEY_SELECTED, game.getSelectedLiveData());
hashLiveData.put(KEY_DESELECTED, game.getDeselectedLiveData());
hashLiveData.put(KEY_HOLD, game.getHoldLiveData());
hashLiveData.put(KEY_UNHOLD, game.getUnholdLiveData());
hashLiveData.put(KEY_RESULT, game.getResultLiveData());
}
public LiveData<Object> getLiveDataSingleObj(String type) {
if (hashLiveData.containsKey(type)) {
return (LiveData<Object>) hashLiveData.get(type);
}
throw new IllegalArgumentException("Invalid: key was not found: " + type);
}
And the Model has getters, example:
private final SingleLiveEvent<Result> resultLiveData = new SingleLiveEvent<>();
public LiveData<Result> getResultLiveData() {
return resultLiveData;
}
you should remove the observer in onDestroy() method
Changing from MutableLiveData which always resends the previous set values to new subscribers, to SingleLiveEvent which doesn't have this behaviour, solved the problem.
The class can be found here: https://github.com/googlesamples/android-architecture/tree/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp
So Azure spit the following code for me to insert into an activity (Android Studio is what I'm using)
Add the following line to the top of the .java file containing your launcher activity:
import com.microsoft.windowsazure.mobileservices.*;
Inside your activity, add a private variable
private MobileServiceClient mClient;
Add the following code the onCreate method of the activity:
mClient = new MobileServiceClient("https://pbbingo.azurewebsites.net", this);
Add a sample item class to your project::
public class ToDoItem{ public String id; public String Text;}
In the same activity where you defined mClient, add the following code:
ToDoItem item = new ToDoItem();
item.Text = "Don't text and drive";
mClient.getTable(ToDoItem.class).insert(item, new TableOperationCallback<item>(){
public void onCompleted(ToDoItem entity, Exception exception, ServiceFilter response)
{
if(exception == null){
//Insert Succeeded
} else {
//Insert Failed
}
}});
My goal is to create a login page. I understand that the above was probably offered up more with a ToList in mind. I just want to get the syntax correct today. The problem I think, is my basic class structure. I have created an OnClick Listener within my on create that gets the ID from a button in my layout. I don't need it checking for anything in the database until the button has been actually clicked to either login or register.
public class LoginClass extends AppCompatActivity{
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.MyLoginLayout);
MobileServiceClient mClient = null;
try {
mClient = new MobileServiceClient ("myAzureWebsite", "AzureKey", this);
} catch (MalformedURLException e) {
e.printStackTrace();
}
Button Attempt = (Button) findViewById (R.id.mySubmitButton);
final MobileServiceClient finalMClient = mClient; // finalized so I can use it later.
Attempt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick (View v) {
final View thisView = v;
final MyToDoItemClass item = new MyToDoItemClass();
In MyToDoItemClass I have two variables (Both String) Just left over from
the example of a ToDoList (they are String ID and String Text)
item.Text = "Filler";
item.ID = "Fill";
finalMClient.getTable(MyToDoItemClass.class).insert(new Table OperationCallback<item>() { //<--- I'm getting an error that the variable, item
is from an unknown class...
public void onCompleted (Item entity, Exception exception, ServiceFilterResponse response){
if(exception == null) {
Intent i = new Intent (LoginClass.this, MainActivity.class);
startActivity(i);
}else{
Toast.makeText(thisView.getContext(), "Failed", Toast.LENGTH_LONG).show();
}}
});
}
});
}}
The problem is with that the TableOperationCallback is saying that the item from MyToDoItemClass class is from an unknown class.
There are many issues in your code, as below.
According to the javadoc for class MobileServiceClient, there is not a method insert(TableOperationCallback<E> callback), so the code finalMClient.getTable(MyToDoItemClass.class).insert(new Table OperationCallback<item>() {...} is invalid.
The generics E in Table OperationCallback<E> means that you need to write a POJO class name instead of E, not an object variable name like item, so the correct code should be new Table OperationCallback<MyToDoItemClass>, please see the Oracle tutorial for Generics to know more details.
The figure below shows all methods insert of class MobileServiceClient. The bold word Deprecated under the method name means that you should not use it for developing on new project, it‘s only compatible for old project on the new version of Java SDK.
Please follow the offical tutorial to develop your app. Any concern, please feel free to let me know.