Periodically, the application begins to update itself. There is a constant call in the logs:
[ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4.MainActivity#a894c70
[ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4.MainActivity#a894c70
[ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4.MainActivity#a894c70
[ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4.MainActivity#a894c70
When this happens, if, for example, you open the menu , it closes itself, if something is filled in, it is cleared, the page is updated. There are no timers in the code. I'm testing the app on Xiaomi Redmi. I repeat sometimes it happens sometimes it doesn't. What is it?
I do not know what the problem is, but occasionally, it happens that the application throws the fingerprint to the page. It is intermittent. Sometimes everything works fine. That is, I go through the fingerprint, the next page opens, everything is normal and a second after 5 I am again thrown to the page where you need to enter the fingerprint.
Code for the authorization page:
public authentification()
{
try
{
InitializeComponent();
bool auth = CrossSettings.Current.GetValueOrDefault("authorized", false);
if (auth == false) { CheckAuth(); }
else
{
Application.Current.MainPage = new MasterLk();
}
}
catch { }
}
async void CheckAuth()
{
try
{
var avail = await CrossFingerprint.Current.IsAvailableAsync();
if (!avail)
{
CrossSettings.Current.GetValueOrDefault("authorized", true);
Application.Current.MainPage = new MasterLk();
}
else
{
var request = new AuthenticationRequestConfiguration("NeedAuth", "-");
var result = await CrossFingerprint.Current.AuthenticateAsync(request);
if (result.Authenticated)
{
CrossSettings.Current.GetValueOrDefault("authorized", true);
Application.Current.MainPage = new MasterLk();
}
else
{
CheckAuth();
}
}
}
catch { }
}
On the page where it throws it there is a ListView with a binding:
public class OrdersViewModel : BaseViewModel
{
private Table oldLoan;
private bool isRefreshing;
private readonly string clientId;
public bool IsRefreshing
{
get
{
return isRefreshing;
}
set
{
isRefreshing = value;
OnPropertyChanged("IsRefreshing");
}
}
public ICommand RefreshCommand { get; set; }
public ObservableCollection<Table> Loans { get; set; }
public void ShowOrHideLoan(Table loan)
{
if (oldLoan == loan)
{
loan.IsExpanded = !loan.IsExpanded;
Reload(loan);
}
else
{
if (oldLoan != null)
{
oldLoan.IsExpanded = false;
Reload(oldLoan);
}
loan.IsExpanded = true;
Reload(loan);
}
oldLoan = loan;
}
private void Reload(Table loan)
{
var index = Loans.IndexOf(loan);
Loans.Remove(loan);
Loans.Insert(index, loan);
}
public async Task LoadDataAsync()
{
IsRefreshing = true;
Loans.Clear();
try
{
var loans = await ConnectAPI.GetOrdersAsync(clientId);
await Task.Delay(1000);
foreach (var item in loans)
{
Loans.Add(item);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
finally
{
oldLoan = null;
IsRefreshing = false;
}
}
public OrdersViewModel(string clientId)
{
IsRefreshing = false;
this.clientId = clientId;
Loans = new ObservableCollection<Table>();
RefreshCommand = new Command(async () =>
{
await LoadDataAsync();
});
Task.Run(async () => await LoadDataAsync());
}
}
That is, whenever the [ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4 event appears.MainActivity#a894c70
Throws it to the print page...
and if you stay on this page, it is updated after a while.
MIUI 12 has made an intelligent dark theme. The system itself repaints the applications if they do not support the dark theme. Apparently this service is ForceDarkHelper. And ExcludeList is in the settings a list of applications that cannot be repainted
Related
I'm using Deeplinking on Xamarin.iOS.
I can't find a pattern to handle the link if the user has disconnected from my app.
In this case I need to redirect to the login page while waiting for the login to complete before leaving SceneDelegate.ContinueUserActivity, right?
What I've tried so far is to set a Nito.AsyncEx.AsyncAutoResetEvent in my login ViewController, then wait for it with the help of AsyncHelpers. But the login UI is frozen.
[Export("scene:continueUserActivity:")]
public void ContinueUserActivity(UIScene scene, NSUserActivity userActivity)
{
....
if (notAuthenticated)
{
// The user is not authenticated
// Redirect to the Login Page
LoginViewController lvc = new LoginViewController(true);
if (Window.RootViewController == null)
{
var navController = new UINavigationController(lvc);
Window.RootViewController = navController;
}
else
{
UINavigationController rootViewController = ((UINavigationController)Window.RootViewController);
rootViewController.PopToRootViewController(true);
rootViewController.PushViewController(lvc, true);
}
Window.MakeKeyAndVisible();
AsyncHelpers.RunSync(async() => await lvc.LoginFinishedOrCancelled.WaitAsync());
...
}
}
As far as I know there is no way to make ContinueUserActivity async aware.
You could invoke the line AsyncHelpers.RunSync(async() => await lvc.LoginFinishedOrCancelled.WaitAsync()); in your login page instead of in SceneDelegate .
public bool isNeedLoad {get;set;}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if(isNeedLoad)
{
// ...AsyncHelpers.RunSync(async() => await lvc.LoginFinishedOrCancelled.WaitAsync());
isNeedLoad = false ;
}
}
LoginViewController lvc = new LoginViewController(true){isNeedLoad = true};
if (Window.RootViewController == null)
{
var navController = new UINavigationController(lvc);
Window.RootViewController = navController;
Window.MakeKeyAndVisible();
}
else
{
UINavigationController rootViewController = ((UINavigationController)Window.RootViewController);
rootViewController.PopToRootViewController(true);
rootViewController.PushViewController(lvc, true);
}
I have a App that uses tabbed pages, In the xaml of the Parent tab page
I populate all my other tab pages, I have a viewmodel that binds to the Parent tab page and viewmodels for each of the other Tab pages. I have a badge on one of the tabs that has a counter which shows how many messages there are.
I am having trouble updating the counter.
So I have a call to retrieve the amount of unread messages from the database which is populating into the counter on app load. When i Navigate to view the message it updates the database of that the message has been read , I then navigate back to the tabbed page with a popasync , I then pull to refresh which executes the call to get amount of messages read but it not updating the the counter, if i put a break point on the GetCounter method i see it is updating the counter with the right amount but not changing in on the badge.
Hope that makes sense.
If anyone can help i will be very grateful.
Master Tab Page:
<NavigationPage Title="Message" Icon="email.png" plugin:TabBadge.BadgeText="{Binding counter}"
plugin:TabBadge.BadgeColor="Red"
plugin:TabBadge.BadgePosition="PositionTopRight"
plugin:TabBadge.BadgeTextColor="Green">
<x:Arguments>
<local:MessagePage BindingContext="{Binding messages}" />
</x:Arguments>
</NavigationPage>
public partial class MasterTabPage : TabbedPage
{
Master_PageViewModel vm;
public MasterTabPage ()
{
InitializeComponent ();
this.BindingContext = vm = new Master_PageViewModel(Navigation);
}
}
Master Tab Page ViewModel:
public class Master_PageViewModel : INotifyPropertyChanged
{
INavigation Navigation;
private int _counter;
public int counter
{
get => _counter;
set
{
_counter = value;
OnPropertyChanged(nameof(counter));
}
}
public MessagePageViewModel messages { get; set; }
public Master_PageViewModel(INavigation navigation)
{
Navigation = navigation;
messages = new MessagePageViewModel(Navigation);
Init();
counter = 0;
}
public async void Init()
{
await GetCounter();
}
public async Task GetCounter()
{
try
{
using (HttpClient client = new HttpClient())
{
List<MessageModel> msg = new List<MessageModel>();
using (HttpResponseMessage response = await client.GetAsync("http://localhost:53665/api/GetMessagesCount/Id=" + 2 + "/" ))
{
if (response.IsSuccessStatusCode)
{
using (HttpContent content = response.Content)
{
var textresponse = await content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<List<MessageModel>>(textresponse);
foreach (var i in json)
{
msg.Add(new MessageModel
{
msgCounter = i.msgCounter,
});
}
counter = msg[0].msgCounter;
}
}
else
{
}
}
}
}
catch (Exception)
{
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Message Tab ViewModel:
public class MessagePageViewModel : BaseViewModel
{
public ICommand MessageDetailsCommand { get; set; }
INavigation Navigation;
private ObservableCollection<MessageModel> _messagesList;
public ObservableCollection<MessageModel> MessagesList
{
get { return _messagesList; }
set
{
if (_messagesList != value)
{
_messagesList = value;
}
}
}
public ICommand ReloadCommand { get; set; }
public ICommand RefreshCommand
{
get
{
return new Command(async () =>
{
await GetMessages();
Master_PageViewModel vm = new Master_PageViewModel(Navigation,multiMediaPickerService);
await vm.GetCounter();
});
}
}
bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set
{
_isBusy = value;
}
}
public MessagePageViewModel(INavigation navigation)
{
ReloadCommand = new Command(async () => await ReloadPage());
Navigation = navigation;
MessageDetailsCommand = new Command(async (object obj) => await MessageDetails(obj));
Initialize();
}
private async void Initialize()
{
await GetMessages();
}
private async Task ReloadPage()
{
await GetMessages();
}
public async Task GetMessages()
{
List<MessageModel> msg = new List<MessageModel>
.........
MessagesList = new ObservableCollection<MessageModel>(msg);
}
private async Task MessageDetails(object obj)
{
var item = (obj as MessageModel);
await Navigation.PushAsync(new MessageDetailsPage(....));
}
}
}
}
This is because you created a new instance of Master_PageViewModel in your RefreshCommand. It is not the parent tabbed page's binding context so the tab's badge won't be updated even though the GetCounter has been triggered.
You have to pass the parent tabbed view model to your MessagePageViewModel like:
public Master_PageViewModel(INavigation navigation)
{
Navigation = navigation;
messages = new MessagePageViewModel(Navigation, this);
Init();
counter = 0;
}
And change your message page view model's constructor:
Master_PageViewModel parentViewModel
public MessagePageViewModel(INavigation navigation, Master_PageViewModel viewModel)
{
ReloadCommand = new Command(async () => await ReloadPage());
Navigation = navigation;
parentViewModel = viewModel;
// ...
}
At last, trigger the method in your refresh command:
public ICommand RefreshCommand
{
get
{
return new Command(async () =>
{
await GetMessages();
await parentViewModel.GetCounter();
});
}
}
Moreover, I noticed that your MessagePageViewModel used the parent tabbed view model's navigation. I don't think this is a good approach as it has its own NavigationPage so that it should utilize its own navigation instead of the parent's.
I have a list view with a search bar, i can search a item in the listview and click on the item and navigate to details of that item, but when i click the back arrow i get an System.NullReferenceException on my HttpResponseMessage.
Could someone please advise me as to what i could be doing wrong.
If the search bar is empty it works fine.
ViewModel
private async Task GetProjects(string email)
{
IsBusy = true;
ProjectList = new ObservableCollection<ProjectModel>();
using (HttpClient client = new HttpClient())
{
try
{
using (HttpResponseMessage response = await client.GetAsync("http://example/api/GetProject/email=" + email + "/"))
{
if (response.IsSuccessStatusCode)
{
using (HttpContent content = response.Content)
{
var textresponse = await content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<List<ProjectModel>>(textresponse);
foreach (var t in json)
{
if (t.pjtIsActive == 1)
{
ProjectList.Add(new ProjectModel
{
..............
});
}
}
IsBusy = false;
}
}
else
{
}
}
}
catch (Exception)
{
IsBusy = false;
}
}
}
private ICommand _searchCommand;
public ICommand SearchCommand
{
get
{
return _searchCommand ?? (_searchCommand = new Command<string>
(async (text) =>
{
if (text.Length >= 1)
{
ProjectList.Clear();
await GetProjects(EmailAddress);
var projectSearch = ProjectList.Where(c => c.pjtName.ToLower().StartsWith(text.ToLower()) || c.ClientName.ToLower().StartsWith(text.ToLower()) || c.ContractorName.ToLower().StartsWith(text.ToLower()) || c.pjtNumber.ToLower().StartsWith(text.ToLower())).ToList();
ProjectList.Clear();
foreach (var item in projectSearch)
ProjectList.Add(item);
}
else
{
GetProjects(EmailAddress);
}
}));
}
}
private ICommand _projectDetailsCommand;
public ICommand ProjectDetailsCommand=> _projectDetailsCommand?? (_projectDetailsCommand= new Command(async (object obj) => {
var item = (obj as ProjectModel);
ProjectModel project = new ProjectModel();
...........
Navigation.PushAsync(new Project_Details(project));
}));
Content Page
protected override void OnAppearing()
{
BindingContext = new Project_View_ViewModel(Navigation);
base.OnAppearing();
}
You should call the binding context in the constructor and refresh the required data in the OnAppearing,
private Project_View_ViewModel bindingv;
public Project_View()
{
try
{
InitializeComponent();
bindingv = new Project_View_ViewModel(Navigation);
BindingContext = bindingv;
}
catch (Exception ex)
{
Logger.Log(ex);
}
}
protected async override void OnAppearing()
{
base.OnAppearing();
try
{
if (bindingv != null)
{
await bindingv.GetProjects();
}
}
catch (Exception ex)
{
Logger.Log(ex);
}
}
I'm trying to run some code in a new thread because I'm noticing a slowness on my device. It is compiling ok but at the app starting, it freezes and terminates with the message (MyApp is presenting errors constantly).
What I'm doing wrong?
using System.Threading.Tasks;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace MyApp
{
public partial class App : Application
{
public App()
{
InitializeComponent();
}
protected override void OnStart()
{
new System.Threading.Thread(new System.Threading.ThreadStart(() => {
TestaLogin();
})).Start();
}
private void TestaLogin()
{
try
{
Context mContext = Android.App.Application.Context;
ISharedPreferences pref = PreferenceManager.GetDefaultSharedPreferences(mContext);
string uid = pref.GetString("uid", "0");
string token = pref.GetString("token", "0");
if (uid == "0" || token == "0")
{
Device.BeginInvokeOnMainThread(() => { MainPage = new Login(); });
}
else
{
if (Logar(uid, token))
Device.BeginInvokeOnMainThread(() => { MainPage = new MainPage(uid); });
else
Device.BeginInvokeOnMainThread(() => { MainPage = new Login(); });
}
}
catch (Exception e)
{
throw e;
}
}
private bool Logar(string user, string pass)
{
try
{
using (WebClient client = new WebClient())
{
return client.DownloadString("https://www.example.com/mobile/login.php?u=" + user + "&t=" + pass) == "0" ? false : true;
}
}
catch
{
return false;
}
}
}
}
I also wanted to know if lines like this has to be inside the MainThread, I thought that because it's handling changing the page:
Device.BeginInvokeOnMainThread(() => { MainPage = new MainPage(uid); });
I need some help to understand why this exception is thrown. The exception is:
Android.Util.AndroidRuntimeException: Only the original thread that created a view hierarchy can touch its views.
Link to hastebin with full exception
I use ZXing.Net.Mobile.Forms for barcode scanning and Rg.Plugins.Popup for showing a popup. I believe one of them causes the exception.
The exception seems to be thrown at random. The app works fine 99 % of the time.
ScannerPage.xaml
<zxing:ZXingScannerView x:Name="ScannerView"
Result="{Binding ScanResult, Mode=OneWayToSource}"
ScanResultCommand="{Binding ScanResultCommand}"
IsScanning="{Binding IsScanning}"
IsAnalyzing="{Binding IsAnalyzing}" />
<zxing:ZXingDefaultOverlay x:Name="ScannerOverlay"
BottomText="Scanning will happen automatically"
ShowFlashButton="False"/>
ScannerPageViewModel.cs (stripped of irrelevant parts)
[PropertyChanged.AddINotifyPropertyChangedInterface]
internal class ScannerPageViewModel : INavigatedAware
{
public ScannerPageViewModel(IScannerService scannerService, IUserDialogs dialogs, IPopupNavigation popups, IScreenService screen)
{
ScanResultCommand = new Command(ProcessBarcode);
}
public ICommand ScanResultCommand { get; }
/// <summary>
/// Show info dialog box with ticket info.
/// </summary>
private async Task ShowInfoScanResult(string message)
{
var popup = new PopupViews.InfoScanResult(Popups, message);
popup.Disappearing += (se, ev) => IsAnalyzing = true;
await Popups.PushAsync(popup);
}
private void ProcessBarcode()
{
Device.BeginInvokeOnMainThread(async () =>
{
if (ScanResult != null && !string.IsNullOrEmpty(ScanResult.Text))
{
// Disable the scanner after one barcode is found.
IsAnalyzing = false;
var source = new CancellationTokenSource();
// Show loading animation if scanning takes >1 second.
var t = Task.Run(async () =>
{
await Task.Delay(1000, source.Token);
Device.BeginInvokeOnMainThread(ShowLoading);
});
// Call the web service to process the barcode.
var scanResponse = await ScannerService.ScanBarcode(ScanResult.Text, ScanningSession, SelectedScanAction);
if (scanResponse.IsSuccessful)
{
var scanResult = scanResponse.Data;
if (scanResult.Success)
{
var json = scanResult.BarcodeInfo;
var message = ParseJsonBarcodeInfo(json);
if (SelectedScanAction == ScanAction.Information)
await ShowInfoScanResult(message);
else
await ShowOkScanResult(message);
}
else
{
await ShowErrorScanResult(scanResult.FaultDescription);
}
}
else
{
ShowScanRequestError(scanResponse.ErrorMessage);
}
source.Cancel(); // Cancel loading animation timer.
HideLoading();
Screen.SetFullscreen();
source.Dispose();
}
});
}
I have created the Dependency service for Android for me it's working perfect check a below code.
PCL Project
public interface IBarcodeScanner
{
Task<string> ScanAsync();
}
And then in Android project
[assembly: Dependency(typeof(BarcodeScanner))]
namespace CodeMashScanner.Droid.Helpers
{
public class BarcodeScanner : IBarcodeScanner
{
public async Task<string> ScanAsync()
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner(Forms.Context;
var scanResults = await scanner.Scan();
return scanResults.Text;
}
}
}