Zxing cannot be started while StartForeground is running - xamarin.forms

If you are running Start Foreground from an Android.App service
I get an error when I start Zxing (barcode reading).
Error details: Compatible code is not running.
Selective debug execution may or may not be the executable code running in the current thread.
Unhandled Exception:
Java.Lang.NullPointerException: <Timeout exceeded getting exception details>
Is there anyone who can solve this problem?
-- 2020/12/22 add --
Thank you for your reply.
I thought I'd ask a simple question,
It seems that it was not concise but vague Excuse me.
Execute background service to acquire location information continuously (every 15 minutes)
I want to read barcodes as another function,
An error will occur if the barcode is read while the background service is running.
It would be ideal if there was a way to avoid an error in this situation, but I don't know how to deal with it.
Exit background service, read barcode, then
I was wondering if I could handle it by restarting the background service.
I can't solve the problem.
1. Refer to the url below to get the location information in the background.
https://teratail.com/questions/167858
Package installation
ZXing.Net.Mobile (2.4.1)
ZXing.Net.Mobile.Forms (2.4.1)
Run the Clicked event on the Xamarin.Forms Button
The code below calls the Zxing form.
await Navigation.PushAsync (new QRScanPage ()); ← * An error occurs here
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
public partial class QRScanPage: ContentPage
{
public Page00_QRScanPage ()
{
InitializeComponent ();
}
void Handle_OnScanResult (ZXing.Result result)
{
Device.BeginInvokeOnMainThread (async () =>
{
zxing.IsAnalyzing = false;
await Navigation.PopAsync ();
await DisplayAlert ("notification", "Read the following value:" + result.Text, "OK");
zxing.IsAnalyzing = true;
});
}
protected override void OnAppearing ()
{
try
{
base.OnAppearing ();
zxing.IsScanning = true;
}
catch (Exception ex)
{
DisplayAlert ("ExErr",
$ "{ex.Message}", Msg.Button.Ok);
}
}
protected override void OnDisappearing ()
{
zxing.IsScanning = false;
base.OnDisappearing ();
}
}
Service outage
Intent serviceIntent = new Intent (this, typeof (BackgroundService)); * "BackgroundService" is the running Service class
Base.StopService (serviceIntent);
Stop with StopSelf () method
As a result, nothing could be solved.

Related

Blazor WebAssembly SignalR HubConnection causing javascript error on reload

I have a SignalR HubConnection within my Blazor WebAssembly application and whilst it works most of the time, if I reload the page (via the browser reload) then I often am getting the following error in the console and the connection is not made:
Uncaught Error: The delegate target that is being invoked is no longer available. Please check if it has been prematurely GC'd.
at Object.invoke_delegate (dotnet.5.0.4.js:1)
at WebSocket. (dotnet.5.0.4.js:1)
Here's a rough, simplified view of the code where I create the HubConnection (and dispose it).
#inherits LayoutBase
#attribute [Authorize]
<AuthorizeView>
<Authorized>
//...
</Authorized>
<NotAuthorized>
//...
</NotAuthorized>
</AuthorizeView>
public class LayoutBase : LayoutComponentBase, IAsyncDisposable
{
[Inject] public IAccessTokenProvider AccessTokenProvider { get; set; }
private readonly HubConnection _hubConnection;
protected override async Task OnInitializedAsync()
{
_hubConnection = new HubConnectionBuilder()
.AddNewtonsoftJsonProtocol(c =>
{
//...
})
.WithUrl(notificationHubUrl, option => option.AccessTokenProvider = GetAccessToken)
.WithAutomaticReconnect()
.Build();
_hubConnection.Closed += HubConnectionOnClosed;
_hubConnection.Reconnected += HubConnectionOnReconnected;
_hubConnection.Reconnecting += HubConnectionOnReconnecting;
await _hubConnection.StartAsync()
await base.OnInitializedAsync();
}
private async Task<string> GetAccessToken()
{
var tokenResult = await AccessTokenProvider.RequestAccessToken(...)
// etc...
}
// .. Event Handlers
public ValueTask DisposeAsync()
{
_logger.LogInformation($"Disposing Hub: {_hubConnection.ConnectionId}");
_hubConnection.Closed -= HubConnectionOnClosed;
_hubConnection.Reconnected -= HubConnectionOnReconnected;
_hubConnection.Reconnecting -= HubConnectionOnReconnecting;
return _hubConnection.DisposeAsync();
}
}
Previously I had it as an injected service but I eventually simplified it to this structure but it continues to get this error on reload. It's not every time I reload but most times.
I have tried changing the dispose pattern without success. I can't find any information on the error anywhere else.
Any ideas?
I don't have a definitive answer as to the underlying reason but I suspect that this is a bug somewhere in the SignalR/dotnet framework resulting in the GCing of a delegate because something drops a reference to it.
One way I've managed to provoke this error reasonably consistently is to have a handler returning just a Task, e.g.
_hubConnection.On<TEvent>(eventType.Name, OnEvent);
where OnEvent looks like this:
// THIS IS THE BROKEN SIGNATURE - DO NOT USE
private async Task OnEvent<TEvent>(TEvent e)
{
}
A workaround which appears to have fixed it for me is to make the handler actually return something. This seems to make something deeper in the framework hold a reference for longer so that it doesn't get GC'ed. E.g.
// WORKS ON MY MACHINE - Note the return type of Task<object>
private async Task<object> OnEvent<TEvent>(TEvent e)
{
// ... Do stuff
return null;
}

Hosted service not terminating after Environment.Exit

I've got a .NET core 3.1 app with a hosted service that runs as a console application on Windows.
In case of an error I'm trying to terminate the worker with Environment.Exit(1).
Now the problem is that, if Enviroment.Exit() is called before any await in ExecuteAsync, the application does not terminate. It logs Waiting for the host to be disposed. Ensure all 'IHost' instances are wrapped in 'using' blocks. and then hangs indefinitely.
When I await anything before the call to Enviroment.Exit() it also logs that, but it terminates as expected.
Here is the simplest code that I could come up with to reproduce the problem.
The NotTerminatingWorker hangs forever, the TerminatingWorker terminates. The only difference is a tiny Task.Delay:
public class Program {
public static async Task Main(string[] args) {
using var host = CreateHostBuilder(args).Build();
await host.RunAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) {
return Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => { services.AddHostedService<NotTerminatingWorker>(); });
}
}
public class NotTerminatingWorker : BackgroundService {
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
Environment.Exit(1);
}
}
public class TerminatingWorker : BackgroundService {
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
await Task.Delay(1);
Environment.Exit(1);
}
}
I would expect that both behave the same way, but that's obviously not the case.
Any explanation for this would be greatly appreciated!
UPDATE: The application should be able to run both as a console application and as a Windows service. The non-zero return code is required to get it restarted if it crashes.
And apparently Windows does not restart services that exited with code 0.
I believe the behavior you're seeing is a side-effect of how the .NET Core runtime does its startup: it calls ExecuteAsync for each background worker and then waits for it to complete. So a synchronous ExecuteAsync can cause problems. I've used Task.Run to work around this.
In case of an error I'm trying to terminate the worker with Environment.Exit(1).
I recommend not using Environment.Exit at all. Instead, do a controlled shutdown by injecting IHostApplicationLifetime and calling StopApplication. This will trigger the stoppingToken for each of your background services, and if they ignore it, they will be forcibly terminated after a timeout.
Handling the hostLifetime events in the Main method did for me the job. This is working for me on .NET6
public static int Main(string[] args)
{
ExitCode = 0;
ILogger? logger = null;
try
{
var builder = CreateHostBuilder(args)
.Build();
var hostLifetime = builder.Services.GetRequiredService<IHostApplicationLifetime>();
logger = builder.Services.GetService<ILogger<Program>>();
// register on hostLifetime events for handling stopping and finalize
using var hostLtAppStopping = hostLifetime.ApplicationStopping.Register(() =>
{
// service is about to stop... do some cleanup stuff here
});
using var hostLtAppStopped = hostLifetime.ApplicationStopped.Register(() =>
{
logger?.LogDebug("Service graceful shout down, exit with code {exitCode}!", ExitCode);
Environment.Exit(ExitCode); // ExitCode is set by the caller of hostApplicationLifetime.StopApplication
});
// start the service
logger?.LogDebug("builder.Run()");
builder.Run();
}
catch (Exception e)
{
logger?.LogError(e, "Unhandled Exception occurred => exit with exit code 1!");
ExitCode = 1;
return ExitCode;
}
return ExitCode;
}

Why does _session.Use method not work properly?

I have a job like this:
[UnitOfWork]
public override void Execute(CompleteIRHJobArgs args)
{
var robotUserId = _userRepo.GetAll().Where(p => p.UserName == TestaLIMSWPConsts.LIMSRobot).Select(p => p.Id).First();
using (_session.Use(args.TenantId, robotUserId))
{
_instanceReciptHeaderDomainService.SetIRHToCompleteState(args.IRHIds);
}
}
I find robotUserId and set it as the current user. But after I step into method SetIRHToCompleteState, _session.UserId.Value is null. I think it is wrong behavior. My ABP version is 4.0.0.
public async Task SetIRHToCompleteState(List<int> irhIds)
{
var irhs = await _instanceHeaderRepo.GetAll().Where(p => irhIds.Contains(p.Id)).ToListAsync();
foreach (var t in irhs)
{
t.FlowState = FlowState.Completed;
t.CompleteDate = Clock.Now;
t.CompleteUserId = _session.UserId.Value;
}
}
And sometimes,
var irhs = await _instanceHeaderRepo.GetAll()...
throws exception:
System.Transactions.TransactionInDoubtException: The transaction is in doubt. ---> System.Data.SqlClient.SqlException: There is already an open DataReader associated with this Command which must be closed first. ---> System.ComponentModel.Win32Exception: The wait operation timed out
But after step into method SetIRHToCompleteState, _session.UserId.Value is null.
SetIRHToCompleteState is async and continued running after the using scope was disposed.
Since Execute is not async, you cannot await but you can call AsyncHelper.RunSync instead.
// using Abp.Threading;
using (_session.Use(args.TenantId, robotUserId))
{
AsyncHelper.RunSync(() => _instanceReciptHeaderDomainService.SetIRHToCompleteState(args.IRHIds));
}
This would also avoid the "open DataReader" error.
From aspnetboilerplate/aspnetboilerplate#1646:
it's called in a background thread which is not inside an async context. But it's not a problem since background job manager is already single threaded and does not cause to block many threads.
Hangfire implementation is also like that.

Flutter and external JAR Library: android.os.NetworkOnMainThreadException

Im trying to use olingo with Flutter on Android. I set up my channel and I can call the library but I keep getting this message:
E/AndroidRuntime(28391): FATAL EXCEPTION: main
E/AndroidRuntime(28391): Process: com.example.odata, PID: 28391
E/AndroidRuntime(28391): org.apache.olingo.client.api.http.HttpClientException: android.os.NetworkOnMainThreadException
E/AndroidRuntime(28391): at org.apache.olingo.client.core.communication.request.AbstractODataRequest.doExecute(AbstractODataRequest.java:312)
So it looks like it is running on the main thread - which is a no go as this would block. I tried the looper to ask Java to run on the UI Thread:
public void onMethodCall(MethodCall call, Result result) {
// Note: this method is invoked on the main thread.
Log.i("test", "using " + call.method);
String serviceUrl = "http://services.odata.org/OData/OData.svc/";
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
if (call.method.equals("getMetaData")) {
String metadata;
final Edm edm = ODataClientFactory.getClient().getRetrieveRequestFactory().getMetadataRequest(serviceUrl).execute().getBody();
metadata = edm.toString();
if (metadata != "") {
result.success(metadata);
} else {
result.error("UNAVAILABLE", "Metadata cannot read.", null);
}
} else {
result.notImplemented();
}
}
});
But Im still getting the same error.
So how exactly can I deal with external JAR Library which are doing blocking operations ? To my understanding an external call is a Future anyway so it will not block my Flutter thread anyway - but Android Java does not think so ...
This is my method call in flutter
Future<void> _getMetaData() async {
String metadata;
try {
final String result = await platform.invokeMethod('getMetaData');
metadata = result;
} on PlatformException catch (e) {
metadata = e.message;
}
setState(() {
_metadata = metadata;
});
}
Thanks for the answer, this is the solution for anyone that may be interested:
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getMetaData")) {
class MetadataLoader extends AsyncTask<String , Integer, String> {
#Override
protected String doInBackground(String... urls) {
// call your Java library method here, including blocking methods
return your_return_value;
}
protected void onPostExecute(String _result) {
// your_return_value is now passed in _result
result.success(_result);
}
}
new MetadataLoader().execute(); // Start the Async
}
On the flutter side,
Future<void> _getMetaData() async {
String metadata;
try {
final String result = await platform.invokeMethod('getMetaData');
// do something with the result
// the Flutter thread will stop at the await and resume when the Java
// will call result.success
}
}
You will need to create a new Java thread or Worker. (Note that the "main" thread and the "UI" thread are the same thing - so by posting to the main looper you've ended up in the same place - trying to do network i/o on the main thread.)
Yes, the Flutter engine is running in different threads, but you still need to leave the main native thread unblocked as it is responsible for detecting user input, etc.
Also note that when your blocking activity completes - on its non-main thread - it will likely want to deliver the response to Dart. To do this it will need to use part of your code above - to post the results back to the main thread, which can then invoke method channel operations.
You'll probably want to use your method channel bi-directionally. From flutter to native to request an operation (returning, say, a sequence number), and from native to flutter to deliver the results (quoting the sequence number so that the result can be tied back to the request).

Multithreading using Callable while having a responsive graphical interface

I'm trying to get a responsive JavaFX graphical interface while executing a cmd command.
The command I'm executing is the following.
youtube-dl.exe --audio-format mp3 --extract-audio https://www.youtube.com/watch?v=l2vy6pJSo9c
As you see this is a youtube-downloader that converts a youtube link to an mp3-file.
I want this to be executed in a second thread and not in the main FX thread.
I've solved this by implementing interface Callable in the class StartDownloadingThread.
#Override
public Process call() throws Exception {
Process p = null;
p = ExecuteCommand(localCPara1, localCPara2, localDirectory).start();
try {
Thread.sleep(30);
}catch (InterruptedException e){}
return p;
}
The method ExecuteCommand just returns a ProcessBuilder object.
I try to use Thread.sleep to make the program return to the main thread and thus making the application responsive. Unfortunately the program still freezes.
This is how the method call is called.
ExecutorService pool = Executors.newFixedThreadPool(2);
StartDownloadingThread callable = new StartDownloadingThread(parameter1, parameter2, directory);
Future future = pool.submit(callable);
Process p = (Process) future.get();
p.waitFor();
How do I make my GUI responsive using the interface Callable?
Using a executor to run a task just for you to use the get method of the Future that is returned when submitting the task does not actually free the original thread to continue with other tasks. Later you even use the waitFor method on the original thread, which is likely to take even more time than anything you do in your Callable.
For this purpose the Task class may be better suited, since it allows you to handle success/failure on the application thread using event handlers.
Also please make sure an ExecutorService is shut down after you're done submitting tasks.
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
Process p = null;
p = ExecuteCommand(localCPara1, localCPara2, localDirectory).start();
// why are you even doing this?
try {
Thread.sleep(30);
}catch (InterruptedException e){}
// do the rest of the long running things
p.waitFor();
return null;
}
};
task.setOnSucceeded(event -> {
// modify ui to show success
});
task.setOnFailed(event -> {
// modify ui to show failure
});
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(task);
// add more tasks...
// shutdown the pool not keep the jvm alive because of the pool
pool.shutdown();

Resources