I am writing an Android program in C# using Xamarin that will scan a barcode (by calling the Barcode Scanner app) and then check the code against a web service.
I can't get the result back from the Barcode Scanner though. That app seems to be starting and ending correctly but the OnActivityResult method isn't firing.
Here's my code:
namespace AndroidApplication1
{
[Activity(Label = "AndroidApplication1", MainLauncher = true, Icon = "#drawable/icon")]
public class Activity1 : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
//Start Barcode Scanner program
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
//intent.PutExtra("com.google.zxing.client.android.SCAN.SCAN_MODE", "ONE_D_MODE");
StartActivityForResult(intent, 0);
}
public void OnActivityResult(int requestCode, int resultCode, Intent data)
{
}
}
}
I have tried various things such as making the'O' in OnActivityResult lower case and uncommenting the intent.PutExtra etc
Does anyone know what is wrong?
James
Change your method, so that it's overriding the base Activity class:
protected override void OnActivityResult(int requestCode, int resultCode, Intent data)
{
}
The Activity class you're extending most likely contains a virtual method like this:
protected virtual void OnActivityResult(int requestCode, int resultCode, Intent data)
{
}
You're currently hiding the underlying virtual method, and your method will never get "hit" as-is.
Related
I'm developing an Android application with Xamarin Forms that is composed of an interface and also a background service.
I need that the service works also when the interface application is closed.
If I add "IsolatedProcess = true" into the service the graphical interface still works but the service crashes.
I read a lot of posts with possible solutions but they don't work. (I tried to compile in release mode and also to remove "Use Shared Runtime" flag).
I'm compiling with Android 8.1 (Oreo) as Target Framework.
The target environment is Android 4.2.
I start the service into OnCreate method of the MainActivity class:
Intent testIntent = new Intent(this.BaseContext, typeof(TestService));
StartService(testIntent);
The service class:
[Service(IsolatedProcess = true, Exported = true, Label = "TestService")]
public class TestService : Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnCreate()
{
base.OnCreate();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Device.StartTimer(new TimeSpan(0, 0, 40), () =>
{
//Code executed every 40 seconds
});
base.OnStartCommand(intent, flags, startId);
return StartCommandResult.Sticky;
}
public override bool StopService(Intent name)
{
return base.StopService(name);
}
}
If I remove "IsolatedProcess = true" the service works but it will be stopped when I will close the application interface process.
I solved the issue by changing the value of the attribute IsolatedProcess to true, removing the Device.StartTimer instruction and by introducing a BroadcastReceiver.
MainActivity class:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static Intent testServiceIntent;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
testServiceIntent = new Intent(this.BaseContext, typeof(TestService));
LoadApplication(new App());
}
}
The service class:
[Service(IsolatedProcess = false, Exported = true, Label = "TestService")]
public class TestService : Service
{
System.Threading.Timer _timer;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnCreate()
{
base.OnCreate();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
businessLogicMethod();
base.OnStartCommand(intent, flags, startId);
return StartCommandResult.Sticky;
}
public void businessLogicMethod()
{
//My business logic in a System.Threading.Timer
}
}
The Broadcast Receiver class:
[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class TestApplicationBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Log.Info("TestApp", "******* Loading Application *******");
try
{
if (intent.Action.Equals(Intent.ActionBootCompleted))
{
Intent service = new Intent(context, typeof(TestService));
service.AddFlags(ActivityFlags.NewTask);
context.StartService(service);
}
}
catch (Exception ex)
{
Log.Error("TestApp", "******* Error message *******: " + ex.Message);
}
}
}
I hope that can be useful for someone.
I'm Creating a Call Diverting app using Xamarin. What i am doing is with the press of a button a command is triggerd and using DependencyService i call the Android specific implementaion of the Call Diverter Method.
Now I'm having a problam where the instance of the MainActivity Context for the StartActivity Method is null. I'm suspecting that this is the cause of the error i get when i running the app: 'Target of StartActivity is null (NullReferenceException)'
but i dont know how to fix this. i thought i'm doing everything right but i'm getting an exception.
this is my code so far: Android Project Call diverting method implementation
[assembly: Dependency(typeof(CallDiverter_Android))]
namespace CallDiverter2.Droid
{
public class CallDiverter_Android : ICallDiverter
{
public void DivertCall(string callForwardString)
{
var context = MainActivity.Instance;
//Divert call code
try
{
//String callForwardString = "**21*1234567890#";
Intent callIntent = new Intent(Intent.ActionCall); // ACTION_CALL
Android.Net.Uri uri = Android.Net.Uri.Parse(callForwardString);
callIntent.SetData(uri);
context.StartActivity(callIntent);
//Forms.Context.StartActivity(callIntent);
}
catch (Exception)
{
throw;
}
}
public void StopCallDiverting()
{
//Stop the call diverting action
}
}
}
The instance in the MainActivity class:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle bundle)
{
Instance = this;
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
}
My BroadcastReceiver does not receive anything. Most likely its my setup that is wrong, because I was not able to find any good examples on this. I need my receiver to receive something in my MainActivity, and change a View. I have almost the same code in an Android project, and here it is working, however BroadcastReceivers seems to be implemented a tiny bit differently in Xamarin (in Android, I can make a new BroadcastReceiver almost like an object, but in Xamarin, or C#, it seems I must make my own class and thus do not have the same possibilities to directly reference the views). If I get this to work, I will post a full working example for everyone too.
Here is how I have tried to set it up:
[Activity(Label = "GetLocation.Droid", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
Button button;
protected override void OnCreate(Bundle bundle)
{
// ... various OnCreate() code
LocationBroadcastReciever lbr = new LocationBroadcastReciever();
RegisterReceiver(lbr, new IntentFilter("test"));
}
public void SetButtonText(string text)
{
button.Text = text;
}
}
[BroadcastReceiver]
public class LocationBroadcastReciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
/* My program never get this far, so I have not been able
to confirm if the bellow code works or not (its from
another example I saw). */
//EDIT: It does NOT work. See my answer for a working example
string text = intent.GetStringExtra("title");
((MainActivity)context).SetButtonText(text);
InvokeAbortBroadcast();
}
}
And in my IntentService I have this method that actually runs, but never arrives at my receiver.
private void SendBroadcast(double lat, double lng, string activity)
{
Intent intent = new Intent("test");
intent.PutExtra("title", "Updated");
LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
}
This is pretty much the same code as I have in my working Android (only tweaked the BroadcastReceiver and minor adjustments to make it compile).
Can anyone see whats wrong??
EDIT
Finally got this whole thing to work. You can see my answer for a full, clean example.
Local
You register receiver as global, but send intents via LocalBroadcastManager. If you want to use this manager you should register your receiver like this:
LocalBroadcastManager.GetInstance(this).RegisterReceiver(lbr, filter);
You can find more about LocalBroadcastManager here.
Global
Or if you want to use global broadcasts, you should create intent by type:
var intent = new Intent(this, typeof(LocationBroadcastReciever));
and send it via android Context (in your service):
this.SendBroadcast(intent);
Also you can use intent with action, but it requires IntentFilter attribute on your receiver:
[IntentFilter(new []{ "test" })]
[BroadcastReceiver]
public class LocationBroadcastReciever : BroadcastReceiver { ... }
For the sake of future search results, here is a clean example of my code with a working BroadcastReceiver
// ** MainActivity
namespace GetLocation.Droid
{
[Activity(Label = "GetLocation.Droid", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
//I initialize my view(s) here to access them from outside of OnCreate().
Button button;
//I found this in an Android BroadcastReceiver example of how to access the MainActivity from the BroadcastReceiver.
private static MainActivity ins;
public static MainActivity getInstace()
{
return ins;
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
button = FindViewById<Button>(Resource.Id.myButton);
ins = this;
button.Click += delegate
{
Intent intent = new Intent(this, typeof(MyIntentService));
StartService(intent);
};
LocationBroadcastReciever lbr = new LocationBroadcastReciever();
LocalBroadcastManager.GetInstance(this).RegisterReceiver(lbr, new IntentFilter("test"));
}
public void SetButtonText(string text)
{
button.Text = text;
}
}
[BroadcastReceiver]
[IntentFilter(new[] { "test" })]
public class LocationBroadcastReciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
string text = intent.GetStringExtra("title");
MainActivity.getInstace().SetButtonText(text);
}
}
}
And in my IntentService
namespace GetLocation.Droid
{
[Service]
[IntentFilter(new String[] { "com.mytos.MyIntentService" })]
public class MyIntentService : IntentService
{
protected override void OnHandleIntent(Intent intent)
{
SendBroadcast("My message");
}
private void SendBroadcast(string message)
{
//Here you can of course send whatever variable you want. Mine is a string
Intent intent = new Intent("test");
intent.PutExtra("title", message);
LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
}
}
}
A couple of things:
First, you need the [IntentFilter] on the receiver. So it should look like....
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new [] { "test" })]
public class LocationBroadcastReciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
/* My program never get this far, so I have not been able
to confirm if the bellow code works or not (its from
another example I saw). */
string text = intent.GetStringExtra("title");
((MainActivity)context).SetButtonText(text);
InvokeAbortBroadcast();
}
}
That should get you past your issue.
Second, you should register and unregister the reciever. So you should register in the OnResume and unregister in OnPause.
[Activity(Label = "GetLocation.Droid", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
LocationBroadcastReciever _lbr;
Button button;
protected override void OnCreate(Bundle bundle)
{
// ... various OnCreate() code
}
protected override void OnResume()
{
base.OnResume();
_lbr = new LocationBroadcastReciever();
RegisterReceiver(lbr, new IntentFilter("test"));
}
protected override void OnPause()
{
UnregisterReceiver(_lbr);
base.OnPause();
}
public void SetButtonText(string text)
{
button.Text = text;
}
}
Note: these changes are what I saw different between your code and my code for a working broadcast receiver. Whether my changes are necessary or not, I'm not entirely sure.
I am having quite an interesting issue. Let me emphasize that I haven't been programming much for android and it seems I might have gone off track somewhere.
My problem is the triggering of the event onActivityResult(). I have read the Xamarin receipies but somehow it does not work. The routine does not get called in the MainActivity.
I even tried to do a similar example on java, and there it worked like a charm.
So, now to business. I have a MainActivity, which can start the Configuration Activity. This activity is supposed to collect the IP from the server (user manually puts it in), and return the String back to MainActivity. Fair and simple.
MainActivity code snippet:
[Activity(Label = "Test", MainLauncher = true, Icon = "#drawable/ax")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
setBindigs();
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
switch (resultCode)
{
case Result.Ok:
//do something
break;
}
}
private void setBindigs()
{
ImageView ax = FindViewById<ImageView>(Resource.Id.ax);
ax.Click += HandleImageClick;
}
private void HandleImageClick(object sender, EventArgs e)
{
var conf = new Intent(this, typeof(Configuration));
StartActivityForResult(conf, Convert.ToInt32(Result.Ok));
}
And the Configuration snippet:
[Activity(Label = "Configuration")]
public class Configuration : Activity
{
private Button[] Connects;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Configuration);
setBindigs();
}
private void setBindigs()
{
const int KeyboardLength = 2;
Connects = new Button[KeyboardLength];
for (int I = 0; I < KeyboardLength; ++I)
{
Connects[I] = FindViewById<Button>(Resource.Id.ConnectButton + I);
Connects[I].Click += HandleKeyboardClick;
}
}
private void HandleKeyboardClick(object sender, EventArgs e)
{
Button Clicked = sender as Button;
Result ActivityResult = Result.Ok;
String IpText = String.Empty;
switch(Clicked.Id)
{
case Resource.Id.ConnectButton:
EditText IP = FindViewById<EditText>(Resource.Id.ServerIP);
IpText = IP.Text;
break;
case Resource.Id.DisconnectButton:
ActivityResult = Result.Canceled;
break;
}
Intent myIntent = new Intent (this, typeof(MainActivity));
myIntent.PutExtra ("IP", IpText);
SetResult (Result.Ok, myIntent);
Finish();
}
Would you have any ideas? In java I used the option getIntent(); instead of Intent myIntent = new Intent (this, typeof(MainActivity));
I have just found the problem in my code. For future reference, here is what seems to be the problem:
When calling StartActivityForResult() I used the arguments StartActivityForResult(conf, Convert.ToInt32(Result.Ok));. It seems that the expected result should not be passed as Convert.ToInt32(Result.Ok) but rather as a 0.
This solved my problem
As in title broadcast from IntentService is not received.
Here's how I have it set up:
[Service]
[IntentFilter(new[] { MyService.ToUploadCountNotification })]
public class MyService : IntentService
{
public const string ToUploadCountNotification = "MyService.ToUploadCountNotification";
public const string ToUploadCount = "MyService.ToUploadCount";
protected override void OnHandleIntent(Intent intent)
{
while (Count > 0)
{
var uploadCount = new Intent();
uploadCount.SetAction(ToUploadCountNotification);
uploadCount.PutExtra(ToUploadCount, localHarryys.Count);
Log.Debug("Sync service", "sending broadcast");
SendBroadcast(intent, null);
}
}
}
public class MyServiceBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
//throw new NotImplementedException();
Toast.MakeText(context,
string.Format("Uploading...({0})", intent.Extras.GetInt(MyService.ToUploadCount)),
ToastLength.Short).Show();
}
}
In activity I register receiver:
protected override void OnResume()
{
base.OnResume();
RegisterReceiver(_receiver, new IntentFilter(MyHarryysSyncService.ToUploadCountNotification));
Log.Debug("Browse", "Receiver registered");
}
protected override void OnPause()
{
base.OnPause();
UnregisterReceiver(_receiver);
Log.Debug("Browse", "Receiver unregistered");
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == 0)
{
StartService(new Intent(this, typeof(MyService)));
}
base.OnActivityResult(requestCode, resultCode, data);
}
In my research all I could find was
make sure that you register it correctly in activity - I believe I do I've also put it in OnCreate/OnDestroy see below
activity might not be visible/active at the time service sends broadcast - From debug window I get correct order of messages Receiver registered / sending broadcast so I'm assuming that activity is active and receiver registered.
I've tested couple more things.
After line StartService(new Intent(this, typeof(MyService)))
I've put SendBroadcast(new Intent(MyService.ToUploadCountNotification), null);
that didn't work till I've move registration to OnCreate/OnDestroy. Unfortunatelly broadcast from service was still not received
I've registered receiver in androidmanifest.xml that works as well but I wanted to have it registered dynamically by activity as there might be different behaviour depending on active activity.
So my question is what else am I doing wrong there. What else can I check.