startup.ActivityLogin has leaked window DecorView#3a9e526[ActivityLogin] that was originally added here - android-activity

Here is my code, I am trying to allow the user to sign in via his Gmail id. But I am getting this error:
Error Image
Not sure what I am missing, I think I have called dismiss() at the right place. Is it the timing issue?
The app is launching fine in my phone though. I am not sure if it will crash in other devices so I want to get rid of this error.
//Google Sign In
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GOOGLE_SIGN_IN_KEY) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
firebaseAuthWithGoogle(account);
} catch (ApiException e) {
if (e.getStatusCode() == 12500) {
Snackbar.make(findViewById(android.R.id.content), "Sign In Error! Update Google Play Service.", Snackbar.LENGTH_LONG).show();
}
}
}
}
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = firebaseAuth.getCurrentUser();
showGoogleSignUpDialog();
storeUserInfo(user.getPhotoUrl().toString(), user.getUid(), user.getDisplayName(), user.getEmail());
} else {
Snackbar.make(findViewById(android.R.id.content), "Sign In Failed!", Snackbar.LENGTH_LONG).show();
}
}
});
}
private void storeUserInfo(final String stringUserImage, final String stringUserID, final String stringName, final String stringEmail) {
FirebaseUser user = firebaseAuth.getCurrentUser();
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(stringName)
.setPhotoUri(Uri.parse(stringUserImage))
.build();
user.updateProfile(profileUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
firebaseFirestore.collection("UserData").document(stringUserID).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.getData() != null && documentSnapshot.getData().size() > 0) {
Snackbar.make(findViewById(android.R.id.content), "Welcome back!", Snackbar.LENGTH_LONG).show();
startActivity(new Intent(ActivityLogin.this, ActivityHome.class));
finish();
} else {
createUserData(stringUserID, stringUserImage, stringName, stringEmail);
}
}
});
}
}
});
}
private void createUserData(String stringUserID, String stringUserImage, String stringName, String stringEmail) {
final Map<String, Object> userDataMap = new HashMap<>();
userDataMap.put("userName", stringName);
userDataMap.put("userImage", stringUserImage);
userDataMap.put("userID", stringUserID);
userDataMap.put("userPoints", 100);
userDataMap.put("userVerified", true);
userDataMap.put("userEmail", stringEmail);
userDataMap.put("timestamp", FieldValue.serverTimestamp());
firebaseFirestore.collection("UserData").document(stringUserID).set(userDataMap)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
alertGoogleSignIn.dismiss();
Snackbar.make(findViewById(android.R.id.content), "Welcome!", Snackbar.LENGTH_LONG).show();
startActivity(new Intent(ActivityLogin.this, ActivityHome.class).putExtra("canShowCoinCredit", true));
finish();
}
}, 3000);
}
});
}
private void showGoogleSignUpDialog() {
final AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Signing in");
alert.setMessage("Please hold on while we process...");
alert.setCancelable(false);
alertGoogleSignIn = alert.create();
alertGoogleSignIn.show();
}

Try the following:
Generate the onStop() override method and transfer your startactivity as shown below. The finish() method you have already specified will invoke the onStop() override method then your activity should be started.
#Override
protected void onStop() {
super.onStop();
startActivity(new Intent(ActivityLogin.this, ActivityHome.class).putExtra ("canShowCoinCredit", true));
}

This error occurred because alertGoogleSignIn dialog is not dismissed before intent to next screen
Need to dismiss alertGoogleSignIn before startIntent
Please add alertGoogleSignIn.dismiss() in following function
private void storeUserInfo(final String stringUserImage, final String stringUserID, final String stringName, final String stringEmail) {
FirebaseUser user = firebaseAuth.getCurrentUser();
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(stringName)
.setPhotoUri(Uri.parse(stringUserImage))
.build();
user.updateProfile(profileUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
firebaseFirestore.collection("UserData").document(stringUserID).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
alertGoogleSignIn.dismiss(); // dismiss dialog here
if (documentSnapshot.getData() != null && documentSnapshot.getData().size() > 0) {
Snackbar.make(findViewById(android.R.id.content), "Welcome back!", Snackbar.LENGTH_LONG).show();
startActivity(new Intent(ActivityLogin.this, ActivityHome.class));
finish();
} else {
createUserData(stringUserID, stringUserImage, stringName, stringEmail);
}
}
});
}
}
});
}
I hope this helps you

Related

How to listen a startActivityForResult call when using FlutterPlugin?

I'm developing a Flutter Plugin for Android using Java. When i call the MethodChannel, I need to call another Android Intent. If I was using an native activity, it would be simple since I can call startActivityForResult and implement the method onActivityResult on the same class.
But, when I develop a Flutter Plugin, I can implement FlutterPlugin, MethodCallHandler and ActivityAware interfaces but how can I start a new activity and listen for async result?
Java code:
public class GetnetPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
private MethodChannel channel;
private Context context;
private Activity activity;
#Override
public void onAttachedToEngine(#NonNull FlutterPluginBinding flutterPluginBinding) {
context = flutterPluginBinding.getApplicationContext();
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "com.example/method");
channel.setMethodCallHandler(this);
}
#Override
public void onDetachedFromEngine(#NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
#Override
public void onMethodCall(#NonNull MethodCall call, #NonNull Result result) {
switch (call.method){
case "makePayment":
makePayment();
result.success(true);
return;
default:
result.notImplemented();
return;
}
}
#Override
public void onAttachedToActivity(#NonNull ActivityPluginBinding binding) {
this.activity = binding.getActivity();
}
#Override
public void onDetachedFromActivityForConfigChanges() {
this.activity = null;
}
#Override
public void onReattachedToActivityForConfigChanges(#NonNull ActivityPluginBinding binding) {
this.activity = binding.getActivity();
}
#Override
public void onDetachedFromActivity() {
this.activity = null;
}
//This is the method that is called with main action. It starts a new activity by a new intent, then it should listen for a async result
public void makePayment(){
Bundle bundle = new Bundle();
DecimalFormat df = new DecimalFormat("000000000000");
bundle.putString("amount", df.format(10));
bundle.putString("paymentType", "credit");
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("getnet://pagamento/v3/payment"));
intent.putExtras(bundle);
if(intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivityForResult(intent, REQUEST_CODE);
}
}
//This is the method that I need to be called after new activity returns a result
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
channel.invokeMethod("success", data);
}
});
}
}
Flutter side:
class Getnet {
final MethodChannel _channel =
const MethodChannel('com.example/method');
final StreamController _streamController = StreamController.broadcast();
Getnet() {
_channel.setMethodCallHandler((call) async {
final method = call.method;
switch (method) {
case 'success':
_streamController.sink.add({
"status": 1,
"msg": call.arguments,
});
break;
case 'error':
_streamController.sink.add({
'status': 0,
'msg': call.arguments['errorMessage'],
});
break;
}
});
}
void dispose() {
_streamController.close();
}
Stream get stream => _streamController.stream;
Future makePayment() async {
await _channel.invokeMethod('makePayment');
}
}
I just found the answer on Enrico Ori's post at Medium: https://medium.com/theotherdev-s/mastering-flutter-create-a-plugin-e81242b6065
The solution is to make Plugin implements ActivityAware and PluginRegistry.ActivityResultListener, which demands onActivityResult implementation.

Can't initialized GraphQl Client in flutter using Get_it

I want to implement GraphQL client in my flutter app. For Dependency injection, I use GetIt library. But when I run the app, it says
'Invalid argument (Object of type HomeGraphQLService is not
registered inside GetIt. Did you forget to pass an instance name?
(Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt
sl=GetIt.instance;)): HomeGraphQLService'
.
It means GraphQL client did not instantiate somehow, although I registered it in my service locator
Session.dart
abstract class Session {
String getAccessToken();
}
SessionImpl.dart
class SessionImpl extends Session {
SharedPreferences sharedPref;
SessionImpl(SharedPreferences sharedPref) {
this.sharedPref = sharedPref;
}
#override
String getAccessToken() {
return sharedPref.getString('access_token') ?? "";
}
}
GraphQLClientGenerator.dart
class GraphQLClientGenerator {
Session session;
GraphQLClientGenerator(Session session) {
this.session = session;
}
GraphQLClient getClient() {
final HttpLink httpLink = HttpLink('https://xxx/graphql');
final AuthLink authLink = AuthLink(getToken: () async => 'Bearer ${_getAccessToken()}');
final Link link = authLink.concat(httpLink);
return GraphQLClient(link: link, cache: GraphQLCache(store: InMemoryStore()));
}
String _getAccessToken() {
return session.getAccessToken();
}
}
HomeRepository.dart
abstract class HomeRepository {
Future<List<Course>> getAllCourseOf(String className, String groupName);
}
HomeRepositoryImpl.dart
class HomeRepositoryImpl extends HomeRepository {
HomeGraphQLService homeGraphQLService;
HomeMapper homeMapper;
HomeRepositoryImpl(HomeGraphQLService homeGraphQLService, HomeMapper homeMapper) {
this.homeGraphQLService = homeGraphQLService;
this.homeMapper = homeMapper;
}
#override
Future<List<Course>> getAllCourseOf(String className, String groupName) async {
final response = await homeGraphQLService.getAllCourseOf(className, groupName);
return homeMapper.toCourses(response).where((course) => course.isAvailable);
}
}
HomeGraphQLService.dart
class HomeGraphQLService {
GraphQLClient graphQLClient;
HomeGraphQLService(GraphQLClient graphQLClient) {
this.graphQLClient = graphQLClient;
}
Future<SubjectResponse> getAllCourseOf(String className, String groupName) async {
try {
final response = await graphQLClient.query(getAllCourseQuery(className, groupName));
return SubjectResponse.fromJson((response.data));
} catch (e) {
return Future.error(e);
}
}
}
GraphQuery.dart
QueryOptions getAllCourseQuery(String className, String groupName) {
String query = """
query GetSubject($className: String, $groupName: String) {
subjects(class: $className, group: $groupName) {
code
display
insights {
coming_soon
purchased
}
}
}
""";
return QueryOptions(
document: gql(query),
variables: <String, dynamic>{
'className': className,
'groupName': groupName,
},
);
}
ServiceLocator.dart
final serviceLocator = GetIt.instance;
Future<void> initDependencies() async {
await _initSharedPref();
_initSession();
_initGraphQLClient();
_initGraphQLService();
_initMapper();
_initRepository();
}
Future<void> _initSharedPref() async {
SharedPreferences sharedPref = await SharedPreferences.getInstance();
serviceLocator.registerSingleton<SharedPreferences>(sharedPref);
}
void _initSession() {
serviceLocator.registerLazySingleton<Session>(()=>SessionImpl(serviceLocator()));
}
void _initGraphQLClient() {
serviceLocator.registerLazySingleton<GraphQLClient>(() => GraphQLClientGenerator(serviceLocator()).getClient());
}
void _initGraphQLService() {
serviceLocator.registerLazySingleton<HomeGraphQLService>(() => HomeGraphQLService(serviceLocator()));
}
void _initMapper() {
serviceLocator.registerLazySingleton<HomeMapper>(() => HomeMapper());
}
void _initRepository() {
serviceLocator.registerLazySingleton<HomeRepository>(() => HomeRepositoryImpl(serviceLocator(), serviceLocator()));
}
main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown],
);
await initDependencies();
runApp(MyApp());
}
I cannot say where exactly it is happening because it is elsewhere in your code where you are accessing the GraphQLService, but the problem is definitely due to the lazy loading. The object has not been created and loaded by the locator before it is being accessed. Try updating ServiceLocator.dart to instantiate the classes during registration, like so:
void _initSession() {
serviceLocator.registerSingleton<Session>.(SessionImpl(serviceLocator()));
}
void _initGraphQLClient() {
serviceLocator.registerSingleton<GraphQLClient>(
GraphQLClientGenerator(serviceLocator()).getClient());
}
void _initGraphQLService() {
serviceLocator.registerSingleton<HomeGraphQLService>(
HomeGraphQLService(serviceLocator()));
}
void _initMapper() {
serviceLocator.registerSingleton<HomeMapper>(HomeMapper());
}
void _initRepository() {
serviceLocator.registerSingleton<HomeRepository>(
HomeRepositoryImpl(serviceLocator(), serviceLocator()));
}

How to listen the method channel result

On firebase service, there are two method onNewToken and onMessageReceived, the code I tried to implement to get the new token and remote message from them on android side, then feedback to flutter side. But I have no idea how to listen the method channel when it has a result.
// Service
public class FluttersService extends FirebaseMessagingService {
#Override
public void onNewToken(String token) {
...
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
#Override
public void onMessageReceived(RemoteMessage message) {
...
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
}
// Plugin
public class FlutterPushPlugin extends BroadcastReceiver
implements MethodCallHandler, NewIntentListener, FlutterPlugin, ActivityAware {
// BroadcastReceiver implement
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
return;
}
if (action.equals(ACTION_TOKEN)) {
String token = intent.getStringExtra(EXTRA_TOKEN);
methodChannel.invokeMethod("onToken", token);
} else if (action.equals(ACTION_REMOTE_MESSAGE)) {
RemoteMessage message =
intent.getParcelableExtra(EXTRA_REMOTE_MESSAGE);
if (message == null) return;
Map<String, Object> content = remoteMessageToMap(message);
methodChannel.invokeMethod("onMessage", content);
}
}
#Override
public void onMethodCall(final MethodCall call, #NonNull final Result result) {
switch (call.method) {
case "onToken":
// How to response the result to flutter side?
break;
case "onMessage":
// How to response the result to flutter side?
break;
default:
result.notImplemented();
return;
}
}
}
Use Event channel for sending an event to flutter from native.
A complete description is provided in the below article.
https://rvsevtag62.medium.com/event-channel-to-listen-to-broadcast-events-from-android-43a813672896

Platform specific code error: MissingPluginException

I want to send an Notification in Flutter, so I set up my platform specific code (only Android) but I get the following error back:
Unhandled Exception: MissingPluginException(No implementation found for method send_notification on channel reminderChannel)
I already cleaned the project but still not working.
Future to invoke method:
const platform = const MethodChannel("reminderChannel");
Future<void> invokeMethod() async {
try {
//FIXME Missing plugin
int testValue = await platform.invokeMethod("send_notification");
} on PlatformException catch (e) {}
}
invokeMethod();
mainActivity:
private static final String notificationChannel = "reminderChannel";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), notificationChannel).setMethodCallHandler(
new MethodCallHandler() {
#Override
public void onMethodCall(MethodCall methodCall, Result result) {
if (methodCall.method.equals("send_notification")) {
System.out.print("Android Method called");
result.success(5);
} else {
result.notImplemented();
}
}
}
);
}
I want that the testValue variable in invokeMethod equals 5.
Thanks for helping.
I suspect your channel is deallocated at the end of the method.
So keep a reference to the MethodChannel in your acivity:
private static final String notificationChannel = "reminderChannel";
private MethodChannel mainChannel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
reminderChannel = new MethodChannel(getFlutterView(), notificationChannel)
reminderChannel.setMethodCallHandler(
new MethodCallHandler() {
#Override
public void onMethodCall(MethodCall methodCall, Result result) {
if (methodCall.method.equals("send_notification")) {
System.out.print("Android Method called");
result.success(5);
} else {
result.notImplemented();
}
}
}
);
}

No implementation found for method listen on channel for ConnectionStatus library

I'm trying to use FlutterCheckInternetConnectivity on our application, after run application i get this error:
plugins.flutter.io/connectivity_status:
MissingPluginException(No implementation found for method listen on channel
plugins.flutter.io/connectivity_status)
on this part of code:
void dispose() {
connectionChangeController.close();
}
ConnectionStatusSingleton class:
class ConnectionStatusSingleton {
static final ConnectionStatusSingleton _singleton = new ConnectionStatusSingleton._internal();
ConnectionStatusSingleton._internal();
static ConnectionStatusSingleton getInstance() => _singleton;
bool hasConnection = false;
StreamController connectionChangeController = new StreamController.broadcast();
final Connectivity _connectivity = Connectivity();
void initialize() {
_connectivity.onConnectivityChanged.listen(_connectionChange);
checkConnection();
}
Stream get connectionChange => connectionChangeController.stream;
void dispose() {
connectionChangeController.close();
}
void _connectionChange(ConnectivityResult result) {
checkConnection();
}
Future<bool> checkConnection() async {
bool previousConnection = hasConnection;
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
hasConnection = true;
} else {
hasConnection = false;
}
} on SocketException catch(_) {
hasConnection = false;
}
if (previousConnection != hasConnection) {
connectionChangeController.add(hasConnection);
}
return hasConnection;
}
}
my implemented this library:
main() {
ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
connectionStatus.initialize();
runApp(MaterialApp(
...
));
}
_FragmentPostsState widget class:
class _FragmentPostsState extends State<FragmentPosts> {
StreamSubscription _connectionChangeStream;
bool isOffline = false;
#override
void initState() {
super.initState();
ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
_connectionChangeStream = connectionStatus.connectionChange.listen(connectionChanged);
}
#override
Widget build(BuildContext context) {
return (isOffline)
? Center(...)
: PostPage();
}
void connectionChanged(dynamic hasConnection) {
setState(() {
print('connection changed ...');
isOffline = !hasConnection;
});
}
}
I had this same problem and eventually I restarted the app from command-line and this solved the problem.