Xamarin android - Attempt to invoke virtual method sendBroadcast() on a null object reference - xamarin

I'm building a crossplatform application using Xamarin,my application will download videos from internet, I've done the download and save functions, but after saved videos to DCIM(in android) the videos do not appear in gallery.After hafl of a day searching for solutions on internet I comeup with two solutions:
1.after download finished: send broadcast with action "Intent.ActionMediaMounted".
2.after download finished Call "MediaScannerConnection.ScanFile".
With solution 1 I got:
"{Java.Lang.NullPointerException: Attempt to invoke virtual method 'void android.content.Context.sendBroadcast(android.content.Intent)' on a null object reference}
With solution 2, I got:
"{Java.Lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Context.bindService(android.content.Intent, android.content.ServiceConnection, int)' on a null object reference}
This is my Interface which I used to handle downloadfinished placed in PLC project:
namespace VideoDownloader
{
public interface IDownloadState
{
void OnDownloadStarted();
void OnDownloadError();
void OnDownloadFinished(string path);
}
}
This is my MainPage.xaml.cs in PLC project:
namespace VideoDownloader
{
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
}
public void downloadVideo(VideoInfor video, bool isRetried)
{
//download code here...
DependencyService.Get<IDownloadState()
.OnDownloadFinished(video.path);
}
}
}
And This is my MainActivity in Android project which implement IDownloadState and send broadcast when OnDownloadFinished fired:
[assembly: Xamarin.Forms.Dependency(typeof(MainActivity))]
namespace VideoDownloader.Droid
{
[Activity(Label = "VideoDownloader", Icon = "#mipmap/icon", Theme =
"#style/MainTheme", MainLauncher = true, ConfigurationChanges =
ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity :
global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,
IDownloadState
{
readonly string[] StoragePermissions =
{
Manifest.Permission.WriteExternalStorage,
Manifest.Permission.ReadExternalStorage
};
const int RequestStorageId = 0;
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
int sdkBuildVersion = (int)Build.VERSION.SdkInt;
Console.WriteLine("SDK build version = " + sdkBuildVersion);
if (sdkBuildVersion >= 23)
{
RequestStoragePermission();
}
}
public override void OnRequestPermissionsResult(int requestCode,
string[] permissions, Permission[] grantResults)
{
switch (requestCode)
{
case RequestStorageId:
{
if (grantResults[0] == Permission.Granted)
{
}
else
{
}
}
break;
default:
break;
}
}
public void OnDownloadStarted()
{
throw new NotImplementedException();
}
public void OnDownloadError()
{
throw new NotImplementedException();
}
public void OnDownloadFinished(string path)
{
//Intent intent = new Intent(Intent.ActionMediaMounted);
//SendBroadcast(intent);
//throw new NotImplementedException();
MediaScannerConnection.ScanFile(this, new String[] {
Android.OS.Environment
.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim)
.AbsolutePath }, null, null);
}
}
}
I know there are many many similar questions for android on stackoverflow that have ansered but they seem to not like my situation at all. So is there anyone know what am I doing wrong? Why this is happening?

With solution 2, I got:
"{Java.Lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Context.bindService(android.content.Intent, android.content.ServiceConnection, int)' on a null object reference}
Please try to use Forms.Context instead of this in OnDownloadFinished().
For example:
public void OnDownloadFinished(string path)
{
//Intent intent = new Intent(Intent.ActionMediaMounted);
//SendBroadcast(intent);
//throw new NotImplementedException();
MediaScannerConnection.ScanFile(Forms.Context, new String[] {
Android.OS.Environment
.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim)
.AbsolutePath }, null, null);
}

Related

ShouldDelayBannerRenderingListenerImplementor Error after Xamarin AdMob SDK 118.1.1 update

After a long wait for Admob SDK Update on Xamarin to implement Adaptive Banners and new Native Ads ,after upgrade to new Nuget package Sdk 118.1.1preview ,Visual Studio open a .Java File and mention the following error :
error: ShouldDelayBannerRenderingListenerImplementor is not abstract and does not override abstract method zzb(Runnable) in ShouldDelayBannerRenderingListener.
To take advantage of the new xamarin admob sdk (118.1.1 preview) , and overcome the JAVA error :
error: ShouldDelayBannerRenderingListenerImplementor is not abstract and does not override abstract method zzb(Runnable) in ShouldDelayBannerRenderingListener.
just put the following code on the java file poped-up and build solution :
#Override
public boolean zzb(Runnable runnable) {
return false;
}
or let this c# code (FileWatcher)keep running :
static void Main(string[] args)
{
var Javacode = File.ReadAllText(#"MyJavaFile.java");
while (true)
{
try
{
var JavaFilePah = #"C:\Project\Android\apps\AppName\obj\Debug\100\android\src\mono\com\google\android\gms\ads\formats\ShouldDelayBannerRenderingListenerImplementor.java";
DateTime LastFileChang = File.GetLastWriteTime(JavaFilePah);
if (LastFileChang != LastFileChangesave)
{
if (File.Exists(JavaFilePah) && File.ReadAllText(JavaFilePah).Contains("zzb") == false)
{
File.WriteAllText(JavaFilePah, Javacode);
Console.WriteLine("ok");
}
LastFileChangesave = LastFileChang;
}
Thread.Sleep(10);
}
catch (Exception e)
{
}
}
}
change JavaFilePah with path of ur android app.
MyJavaFile content is :
package mono.com.google.android.gms.ads.formats;
public class ShouldDelayBannerRenderingListenerImplementor
extends java.lang.Object
implements
mono.android.IGCUserPeer,
com.google.android.gms.ads.formats.ShouldDelayBannerRenderingListener
{
/** #hide */
public static final String __md_methods;
static {
__md_methods =
"";
mono.android.Runtime.register ("Android.Gms.Ads.Formats.IShouldDelayBannerRenderingListenerImplementor, Xamarin.GooglePlayServices.Ads.Lite", ShouldDelayBannerRenderingListenerImplementor.class, __md_methods);
}
public ShouldDelayBannerRenderingListenerImplementor ()
{
super ();
if (getClass () == ShouldDelayBannerRenderingListenerImplementor.class)
mono.android.TypeManager.Activate ("Android.Gms.Ads.Formats.IShouldDelayBannerRenderingListenerImplementor, Xamarin.GooglePlayServices.Ads.Lite", "", this, new java.lang.Object[] { });
}
private java.util.ArrayList refList;
public void monodroidAddReference (java.lang.Object obj)
{
if (refList == null)
refList = new java.util.ArrayList ();
refList.add (obj);
}
public void monodroidClearReferences ()
{
if (refList != null)
refList.clear ();
}
#Override
public boolean zzb(Runnable runnable) {
return false;
}
}

create xamarin process never end

I have a plan and want to periodically check a URL every 5 minutes(NOTIFY CENTER SERVER(Listener)).
My problem: Once the program closes, the process closes
Is it possible that the project will not be shut down if the original program is closed ?
My Code After Changed Worked with : Matcha.BackgroundService
using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Matcha.BackgroundService.Droid;
using Matcha.BackgroundService;
using System.Threading.Tasks;
using Android.Util;
using System.Threading;
using AndroidApp = Android.App.Application;
using Android.Content;
using Android.Support.V4.App;
using Android.Graphics;
namespace Solution.Droid
{
[Activity(Label = "Solution", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
private NotificationManager _manager;
private bool _channelInitialized = false;
public const int _pendingIntentId = 0;
public int _channelID = 10001;
private long _mssageID=0;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
BackgroundAggregator.Init(this);
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
protected override void OnStart()
{
base.OnStart();
//Register Periodic Tasks
var _notifyTASK = new DevinuxTaskPeriodic(10);
_notifyTASK.DoTask += () =>
{
SendNotify("salam", DateTime.Now.ToString());
};
BackgroundAggregatorService.Add(() => _notifyTASK);
BackgroundAggregatorService.StartBackgroundService();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
public int SendNotify(string title, string message)
{
_mssageID++;
if (!_channelInitialized)
{
CreateNotificationChannel();
}
Intent intent = new Intent(AndroidApp.Context, typeof(MainActivity));
PendingIntent pendingIntent = PendingIntent.GetActivity(AndroidApp.Context, _pendingIntentId, intent, PendingIntentFlags.OneShot);
NotificationCompat.Builder builder = new NotificationCompat.Builder(AndroidApp.Context, _channelID.ToString())
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetLargeIcon(BitmapFactory.DecodeResource(AndroidApp.Context.Resources, Resource.Drawable.notification_template_icon_bg))
.SetSmallIcon(Resource.Drawable.notification_template_icon_bg)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate);
Notification notification = builder.Build();
_manager.Notify((int)_mssageID, notification);
return (int)_mssageID;
}
void CreateNotificationChannel()
{
_manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String("Solution");
var channel = new NotificationChannel(_channelID.ToString(), channelNameJava, NotificationImportance.Default)
{
Description = "My Company Notify Camp."
};
_manager.CreateNotificationChannel(channel);
}
_channelInitialized = true;
}
public class DevinuxTaskPeriodic : IPeriodicTask
{
public bool use { set; get; } = false;
public delegate void DoArgs();
public event DoArgs DoTask;
public DevinuxTaskPeriodic(int seconds)
{
Interval = TimeSpan.FromSeconds(seconds);
}
public TimeSpan Interval { get; set; }
public Task<bool> StartJob()
{
if (!use)
{
Timer tmr = new Timer((o) => {
if (DoTask != null)
{
DoTask();
}
}, null, 0, (int)Interval.TotalSeconds*1000);
}
use = true;
return new Task<bool>(() => true);
}
}
}
}
Yes, it is possible to run processes even when the original program/app is not in the foreground.
You are entering the territory of "backgrounding" which is less simple to do. There isn't an inbuilt/official way of performing backgrounding using Xamarin.Forms, so you will have to either create a dependency service (shown here), or try using Shiny.
If you follow the dependency services route, you just need to follow the official iOS & Android tutorials and implement them in your Native project. Note that if you only need a periodic alarm, Android provides a simpler Alarm/PowerManager that you can use.

Backgrounded jobs not working with Shiny library in a simple Xamarin Forms project [duplicate]

This question already has answers here:
How to extend application class in xamarin android
(2 answers)
Closed 3 years ago.
I am trying to implement the very promising Shiny library (for background jobs) from Allan Ritchie. I have only tried this in a simple File/New Project for Android thus far (haven't implemented the code for iOS or UWP), but I am not able to get it to run.
I am following the article https://allancritchie.net/posts/shinyjobs. However, when I run I get the following exception...
And I never hit this breakpoint...
My code can be cloned from https://github.com/JohnLivermore/SampleXamarinApp.git
But here it is inline as well...
App.xaml.cs
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override async void OnStart()
{
var job = new JobInfo
{
Identifier = "YourFirstJob",
Type = typeof(YourFirstJob),
// these are criteria that must be met in order for your job to run
BatteryNotLow = false,
DeviceCharging = false,
RequiredInternetAccess = InternetAccess.Any,
Repeat = true //defaults to true, set to false to run once OR set it inside a job to cancel further execution
};
// lastly, schedule it to go - don't worry about scheduling something more than once, we just update if your job name matches an existing one
await ShinyHost.Resolve<Shiny.Jobs.IJobManager>().Schedule(job);
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
Startup.cs
public class Startup : ShinyStartup
{
public override void ConfigureServices(IServiceCollection services)
{
}
}
YourFirstJob.cs
public class YourFirstJob : IJob
{
public YourFirstJob()
{
}
public async Task<bool> Run(JobInfo jobInfo, CancellationToken cancelToken)
{
//await this.dependency.SomeAsyncMethod(id);
return true; // this is for iOS - try not to lie about this - return true when you actually do receive new data from the remote method
}
}
MainActivity.cs
[Activity(Label = "SampleApp", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
Shiny.AndroidShinyHost.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
MainApplication.cs
[Application]
public class MainApplication : Application
{
public override void OnCreate()
{
base.OnCreate();
Shiny.AndroidShinyHost.Init(this, new SampleApp.Startup());
}
}
Any help would be greatly appreciated!
You might want to add following constructor to your MainApplication class.
public MainApplication(IntPtr handle, JniHandleOwnership ownerShip) : base(handle, ownerShip)
{
}

How can we make app in kiosk mode using xamarin?

I'm creating new app using xamarin. I have already completed some part using some sample codes. I'm able to disable back buttons, volume buttons and power button.
But when trying to disable home button I'm getting error on debugging.
I'm following this link,Kiosk mode in Andriod.
But when trying to disable home button I'm getting error on debugging.
Since you didn't post your code and your error message, we don't know what happened, I just tried to create such a sample followed the blog your posted and it works fine by my side.
Here is the service:
namespace KioskModeAndroid
{
[Service]
[IntentFilter(new[] { "KioskModeAndroid.KioskService" })]
public class KioskService : Service
{
private static long INTERVAL = Java.Util.Concurrent.TimeUnit.Seconds.ToMillis(2);
private static string TAG = typeof(KioskService).Name;
private static string PREF_KIOSK_MODE = "pref_kiosk_mode";
private Thread t = null;
private Context ctx = null;
private bool running = false;
public override void OnDestroy()
{
Log.Info(TAG, "Stopping service 'KioskService'");
running = false;
base.OnDestroy();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Log.Info(TAG, "Starting service 'KioskService'");
running = true;
ctx = this;
t = new Thread(() =>
{
while (running)
{
handleKioskMode();
Thread.Sleep(INTERVAL);
}
StopSelf();
});
t.Start();
return StartCommandResult.NotSticky;
}
private void handleKioskMode()
{
if (isKioskModeActive(ctx))
{
}
if (isInBackground())
{
restoreApp();
}
}
private bool isKioskModeActive(Context context)
{
var sp = PreferenceManager.GetDefaultSharedPreferences(context);
return sp.GetBoolean(PREF_KIOSK_MODE, false);
}
private bool isInBackground()
{
var am = ctx.GetSystemService(Context.ActivityService) as ActivityManager;
var processes = am.RunningAppProcesses;
foreach (var process in processes)
{
if (process.Importance == ActivityManager.RunningAppProcessInfo.ImportanceForeground)
{
foreach (var activeprocess in process.PkgList)
{
if (activeprocess == ctx.PackageName)
return false;
}
}
}
return true;
}
private void restoreApp()
{
Intent i = new Intent(ctx, typeof(MainActivity));
i.AddFlags(ActivityFlags.NewTask);
ctx.StartActivity(i);
}
public override IBinder OnBind(Intent intent)
{
return null;
}
}
}
I started this service in the OnCreate of MainActivity:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
StartService(new Intent(this, typeof(KioskService)));
}

DisplayAlert With changing Text xamarin forms

I have a requirement where i have to show the status of the download on a DisplayAlert. But with changing text on it asynchronously.
How to achieve this?
DisplayAlert("Download Info", "Downloading.....", "Ok");
I want to show status like...
Connected to server
Downloading
Download Complete
Here is a simple "Dynamic Alert" for Forms and iOS using UIAlertController and Android using a DialogFragment and a Xamarin.Forms dependency service:
Dependency Interface:
public interface IDynamicAlert
{
void Show(string title, string message);
void Update(string message);
void Dismiss();
}
iOS IDynamicAlert Dependency Implementation:
public class DynamicAlert : IDynamicAlert
{
UIAlertController alert;
public void Show(string title, string message)
{
if (alert != null) throw new Exception("DynamicAlert already showing");
alert = UIAlertController.Create(title, message, UIAlertControllerStyle.Alert);
var rootVC = UIApplication.SharedApplication.Windows[0].RootViewController;
rootVC.PresentViewController(alert, true, () =>
{
});
}
public void Update(string message)
{
if (alert == null) throw new Exception("DynamicAlert is not showing, call Show first");
alert.Message = message;
}
public void Dismiss()
{
if (alert == null) throw new Exception("DynamicAlert is not showing, call Show first");
alert.DismissViewController(true, () =>
{
alert.Dispose();
alert = null;
});
}
}
Example Usage:
var alert = DependencyService.Get<IDynamicAlert>();
if (alert != null)
{
alert.Show("StackOverflow", "Starting your request...");
await Task.Delay(2000); // Do some work...
alert.Update("Your request is processing...");
await Task.Delay(2000); // Do some work...
alert.Update("Your request is complete...");
await Task.Delay(750);
alert.Dismiss();
}
else
{
throw new Exception("IDynamicAlert Dependency not found");
}
Output:
Android Version:
The android version consists of a couple of parts, a DialogFragment subclass and the IDynamicAlert implementation that uses the custom DialogFragment.
Android DialogFragment Subclass:
public class DynamicAlertDialogFragment : DialogFragment
{
AlertDialog alertDialog;
readonly Context context;
public static DynamicAlertDialogFragment Instance(Context context, string title, string message)
{
var fragment = new DynamicAlertDialogFragment(context);
Bundle bundle = new Bundle();
bundle.PutString("title", title);
bundle.PutString("message", message);
fragment.Arguments = bundle;
return fragment;
}
public DynamicAlertDialogFragment(Context context)
{
this.context = context;
}
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
var title = Arguments.GetString("title");
var message = Arguments.GetString("message");
alertDialog = new AlertDialog.Builder(context)
.SetIcon(Android.Resource.Drawable.IcDialogInfo)
.SetTitle(title)
.SetMessage(message)
.Create();
return alertDialog;
}
public void SetMessage(string message)
{
(context as Activity).RunOnUiThread(() => { alertDialog.SetMessage(message);});
}
}
Android IDynamicAlert Dependency Implementation:
public class DynamicAlert : IDynamicAlert
{
const string FRAGMENT_TAG = "DynamicAlert_Fragment";
DynamicAlertDialogFragment fragment;
static FormsAppCompatActivity currentActivity;
public static FormsAppCompatActivity CurrentActivity { set { currentActivity = value; } }
public void Show(string title, string message)
{
if (currentActivity == null) throw new Exception("DynamicAlert.CurrentActivity needs assigned");
var fragMgr = currentActivity.FragmentManager;
var fragTransaction = fragMgr.BeginTransaction();
var previous = fragMgr.FindFragmentByTag(FRAGMENT_TAG);
if (previous != null)
{
fragTransaction.Remove(previous);
}
fragTransaction.DisallowAddToBackStack();
fragment = DynamicAlertDialogFragment.Instance(currentActivity, title, message);
fragment.Show(fragMgr, FRAGMENT_TAG);
}
public void Update(string message)
{
if (fragment == null) throw new Exception("DynamicAlert is not showing, call Show first");
fragment.SetMessage(message);
}
public void Dismiss()
{
if (fragment == null) throw new Exception("DynamicAlert is not showing, call Show first");
fragment.Dismiss();
fragment.Dispose();
fragment = null;
}
}
Android Init / Usage:
When creating the AlertDialog in the DialogFragment we need access to the current Activity and when using Xamarin.Forms, that is normally the MainActivity that is a FormsAppCompatActivity subclass. Thus you will need to initialize the DynamicAlert.CurrentActivity static property with this Activity in your MainActivity.OnCreate subclass:
Example:
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
////////////
DynamicAlert.CurrentActivity = this;
////////////
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
Android Output:

Resources