Android Xamarin-使用SQLite时打开计划的通知会停止重复并崩溃
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Xamarin-使用SQLite时打开计划的通知会停止重复并崩溃相关的知识,希望对你有一定的参考价值。
我已经使用SQLite创建了一个具有6个数据库表的Xamarin android应用程序。我实现了重复通知功能,每次调用通知时,该功能都会显示与SQLite表不同的元素。这是通过使应用程序在后台运行并遍历SQL数据以找到要在通知中显示的元素来完成的。如果点击通知,则会打开应用程序,并且通知中显示的信息会显示在应用程序的页面上。
所以我可以做的就是打开我的应用程序并将其设置为显示重复通知。每次触发通知时,通知都会根据通过SQL数据的后台函数显示不同的信息。我退出我的应用程序并清除我最近的应用程序以使其在后台运行。通知和更改信息效果很好。但是,一旦我重新打开该应用程序,通知就会停止触发,稍后当我关闭我的应用程序时,我会收到通知,通知该应用程序已停止响应。
我相信问题来自Android警报服务和SQLite数据连接。即使再次打开应用程序后,如何保持通知不断重复?如果我在最初设置要显示的通知后再也没有打开应用程序,则通知将继续显示而不会出现错误。
这是我的课程,用于设置警报管理器并创建通知
[assembly: Dependency(typeof(LawsForImpact.Droid.AndroidNotificationManager))]
namespace LawsForImpact.Droid
{
[BroadcastReceiver]
public class AndroidNotificationManager : BroadcastReceiver, INotificationManager
{
const string channelId = "default";
const string channelName = "Default";
const string channelDescription = "The default channel for notifications.";
const int pendingIntentId = 0;
public const string LocalNotificationKey = "LocalNotification";
public const string TableKey = "table";
public const string IndexKey = "index";
bool channelInitialized = false;
int messageId = -1;
NotificationManager manager;
public event EventHandler NotificationReceived;
string currentTitle;
int currentIndex;
SavedInformation savedInfo;
public void Initialize()
{
CreateNotificationChannel();
}
public int ScheduleNotification(string title, string message)
{
if (!channelInitialized)
{
CreateNotificationChannel();
}
messageId++;
// 1 MainActivity intent allows MainActivity to change once notification tapped
Intent intentMain = new Intent(AndroidApp.Context, typeof(MainActivity));
intentMain.PutExtra(TableKey, currentTitle);
intentMain.PutExtra(IndexKey, currentIndex);
PendingIntent pendingIntentMain = PendingIntent.GetActivity(AndroidApp.Context, pendingIntentId, intentMain, PendingIntentFlags.UpdateCurrent);
NotificationCompat.BigTextStyle textStyle = new NotificationCompat.BigTextStyle();
NotificationCompat.Builder builder = new NotificationCompat.Builder(AndroidApp.Context, channelId)
.SetContentIntent(pendingIntentMain)
.SetContentTitle(title)
.SetContentText(message)
.SetLargeIcon(BitmapFactory.DecodeResource(AndroidApp.Context.Resources, Resource.Drawable.ic_mtrl_chip_checked_circle))
.SetSmallIcon(Resource.Drawable.ic_mtrl_chip_checked_black)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate)
.SetStyle(textStyle);
Random random = new Random();
int randomNumber = random.Next(9999 - 1000) + 1000;
Notification notification = builder.Build();
manager.Notify(randomNumber, notification);
return messageId;
}
public void SavedInfo(SerializableDictionary<string, int> pickedQueue, int queueIndex, bool randomTog, int repeatInterval)
{
savedInfo = new SavedInformation();
currentTitle = pickedQueue.ElementAt(queueIndex).Key;
savedInfo.QueueOfSaved = pickedQueue;
savedInfo.QueueIndex = queueIndex;
savedInfo.RandomToggle = randomTog;
savedInfo.RepeatInterval = repeatInterval;
LoadData();
RepeatAlarmSet();
}
public override void OnReceive(Context context, Intent intent)
{
var extra = intent.GetStringExtra(LocalNotificationKey);
var notification = DeserializeNotification(extra);
SerializableDictionary<string, int> queue = notification.QueueOfSaved;
var queueIndex = notification.QueueIndex;
var randTog = notification.RandomToggle;
var repInterval = notification.RepeatInterval;
SavedInfo(queue, queueIndex, randTog, repInterval);
}
public void RepeatAlarmSet()
{
Intent intent = new Intent(Application.Context, typeof(AndroidNotificationManager));
var serializedNotification = SerializeNotification(savedInfo);
intent.PutExtra(LocalNotificationKey, serializedNotification);
var pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, intent, PendingIntentFlags.UpdateCurrent);
var alarmManager = GetAlarmManager();
alarmManager.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, 1000, pendingIntent);
}
public void Cancel()
{
var intent = new Intent(Application.Context, typeof(AndroidNotificationManager));
var pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, intent, PendingIntentFlags.UpdateCurrent);
var alarmManager = GetAlarmManager();
pendingIntent.Cancel();
alarmManager.Cancel(pendingIntent);
var notificationManager = NotificationManagerCompat.From(Application.Context);
notificationManager.CancelAll();
}
private async void LoadData()
{
SQLiteConnection _sqLiteConnection;
_sqLiteConnection = await Xamarin.Forms.DependencyService.Get<ISQLite>().GetConnection();
IEnumerable<IDataTable> tableToEnumerable = new List<IDataTable>();
List<IDataTable> listData;
switch (currentTitle)
{
case "Table1":
tableToEnumerable = _sqLiteConnection.Table<Table1>().ToList();
break;
case "Table2":
tableToEnumerable = _sqLiteConnection.Table<Table2>().ToList();
break;
case "Table3":
tableToEnumerable = _sqLiteConnection.Table<Table3>().ToList();
break;
case "Table4":
tableToEnumerable = _sqLiteConnection.Table<Table4>().ToList();
break;
case "Table5":
tableToEnumerable = _sqLiteConnection.Table<Table5>().ToList();
break;
case "Table6":
tableToEnumerable = _sqLiteConnection.Table<Table6>().ToList();
break;
}
listData = tableToEnumerable.ToList();
int index = listData.Count() - savedInfo.QueueOfSaved[currentTitle];
index = index - 1;
currentIndex = index;
// if random enabled
if (savedInfo.RandomToggle)
{
Random random = new Random();
index = random.Next(0, listData.Count());
}
//sets all the current notification information
string title = listData[index].Title;
string message = listData[index].Description;
//logic for next notification
// subtract the queue int of current notification subject to keep track of next index
savedInfo.QueueOfSaved[currentTitle] = savedInfo.QueueOfSaved[currentTitle] - 1;
// check for index overflow
if (savedInfo.QueueOfSaved[currentTitle] < 0)
{
savedInfo.QueueOfSaved[currentTitle] = listData.Count() - 1;
}
// index of next table
savedInfo.QueueIndex = savedInfo.QueueIndex + 1;
// if next table index overflows that means its time to restart the table index and move up the notification index
if (savedInfo.QueueIndex >= savedInfo.QueueOfSaved.Count)
{
savedInfo.QueueIndex = 0;
}
ScheduleNotification(title, message);
}
public void ReceiveNotification(string table, int index)
{
var args = new NotificationEventArgs()
{
Table = table,
Index = index,
};
NotificationReceived?.Invoke(null, args);
var notificationManager = NotificationManagerCompat.From(Application.Context);
notificationManager.CancelAll();
}
public static Intent GetLauncherActivity()
{
var packageName = Application.Context.PackageName;
return Application.Context.PackageManager.GetLaunchIntentForPackage(packageName);
}
void CreateNotificationChannel()
{
manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String(channelName);
var channel = new NotificationChannel(channelId, channelNameJava, NotificationImportance.Default)
{
Description = channelDescription
};
manager.CreateNotificationChannel(channel);
}
channelInitialized = true;
}
private string SerializeNotification(SavedInformation notification)
{
var xmlSerializer = new XmlSerializer(notification.GetType());
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, notification);
return stringWriter.ToString();
}
}
private SavedInformation DeserializeNotification(string notificationString)
{
var xmlSerializer = new XmlSerializer(typeof(SavedInformation));
using (var stringReader = new StringReader(notificationString))
{
var notification = (SavedInformation)xmlSerializer.Deserialize(stringReader);
return notification;
}
}
private AlarmManager GetAlarmManager()
{
var alarmManager = Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;
return alarmManager;
}
}
我相信MainActivity以某种方式参与其中,因为它负责重新启动应用程序的过程。
[Activity(
LaunchMode = LaunchMode.SingleTop,
Label = "LawsForImpact",
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);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
CreateNotificationFromIntent(Intent);
}
protected override void OnNewIntent(Intent intent)
{
CreateNotificationFromIntent(intent);
}
void CreateNotificationFromIntent(Intent intent)
{
if (intent?.Extras != null)
{
string tableKey = intent.Extras.GetString(AndroidNotificationManager.TableKey);
int indexKey = intent.Extras.GetInt(AndroidNotificationManager.IndexKey);
DependencyService.Get<INotificationManager>().ReceiveNotification(tableKey, indexKey);
}
}
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);
}
}
我在后台进程中加载SQL数据时遇到的问题。依赖服务引起了该问题。我通过使用Android设备监控器工具并在以下工具的帮助下找到了答案:Xamarin Service and Forms Init
以上是关于Android Xamarin-使用SQLite时打开计划的通知会停止重复并崩溃的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin android-应用关闭时推送通知单击删除 SQLite 数据
使用 SQL/SQLite 工具箱 Visual Studio 2019 在 SQLite 数据库和 Xamarin.Android 项目之间建立连接
Xamarin.Android 使用 SQLite 出现 Index -1 requested, with a size of 10 异常