在这篇文章中,我们将为您详细介绍Android中的本地通知?的内容,并且讨论关于安卓本地推送通知的相关问题。此外,我们还会涉及一些关于AndroidStudio4.1中的本地内存分析、android–
在这篇文章中,我们将为您详细介绍Android中的本地通知?的内容,并且讨论关于安卓本地推送通知的相关问题。此外,我们还会涉及一些关于Android Studio 4.1 中的本地内存分析、android – 如何在信号上向用户发送通知?、android – 如何连续停止和播放通知?、android – 当应用程序在后台时,Cordova本地通知不起作用的知识,以帮助您更全面地了解这个主题。
本文目录一览:- Android中的本地通知?(安卓本地推送通知)
- Android Studio 4.1 中的本地内存分析
- android – 如何在信号上向用户发送通知?
- android – 如何连续停止和播放通知?
- android – 当应用程序在后台时,Cordova本地通知不起作用
Android中的本地通知?(安卓本地推送通知)
在iOS中,应用程序在后台使用“本地通知”时,通知用户发生了某些事情,他们可能需要注意:
Local notifications … to inform users when new data becomes available for your app, even when your app is not running in the foreground. For example, a messaging app might let the user kNow when a new message has arrived, and a calendar app might inform the user of an upcoming appointment.
Apple dev – Local and Remote Notifications Overview
[如果应用程序本身提供新数据,则为“本地”;如果远程服务器正在发送更新,则为“remote”.
在Android上有同等的地方吗?
解决方法:
如果您也定位旧API,请使用NotificationCompat.Builder.
Intent intent = new Intent(ctx, HomeActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder b = new NotificationCompat.Builder(ctx);
b.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_launcher)
.setTicker("Hearty365")
.setContentTitle("Default notification")
.setContentText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
.setDefaults(Notification.DEFAULT_LIGHTS| Notification.DEFAULT_SOUND)
.setContentIntent(contentIntent)
.setContentInfo("Info");
notificationmanager notificationmanager = (notificationmanager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
notificationmanager.notify(1, b.build());
Android Studio 4.1 中的本地内存分析
本文是 Android Studio 4.1 中 Profiler 有哪些新增特性 的第二部分。之前的文章侧重于介绍 Android Studio 中 System Trace 的新增功能。
我们从大家的反馈了解到使用 C++ 调试本地内存非常困难,尤其在开发游戏的时候。在 Android Studio 4.1 中,Memory Profiler (内存分析器) 可以记录本地内存分配的调用栈。本地内存记录基于 Perfetto 后端实现,它是 Android 的新一代性能工具和问题追溯解决方案。
在调试内存问题的时候,通常的做法是搞清楚什么在占用内存,什么在释放内存。本文接下来会带着大家一起使用 Native Memory Profiler 来发现内存泄漏,并且使用 GPU 模拟压力测试 (Gpu Emulation Stress Test) 作为示例工程。
准备工作
首先,我们从 https://github.com/google/gpu-emulation-stress-test 克隆或者下载源码。
当我们发现可疑的内存泄漏时,最好的做法是从更高的层次开始并且观察系统内存的图形。您只需要在 Android Studio 中点击 profile 按钮,然后打开内存分析器,里面会显示更加详细的内存追踪信息。
内存分析器的顶层视图,从显示中可以看到每次运行 "GPU emulation stress test" 的时候内存占用都会逐步升高
运行了几次模拟器后,我们可以发现一些有趣的现象:
- 对于 GPU 模拟应用来说,GPU 内存增加是理所应当的,然而 Activity 被 finish 之后,该内存似乎被清空了。
- 每当我们打开
GPUEmulationStressTestActivity
的时候,本地内存都会有所增加,但是每次运行后该内存似乎并没有被重置,这就表明可能存在内存泄漏。
Native Memory Table (本地内存表格) 视图
从 Android Studio 4.1 Canary 6 开始,我们可以通过获取本地内存分配记录来分析为何内存未被释放。为了能够在 GPU 模拟应用上进行该项操作,我先停止正在运行的应用,然后启动分析一个新的实例。从一个初始的状态开始,会有助于我们缩小需要关注的范围,尤其是在研究一套不熟悉的代码的时候更是如此。通过内存分析器,我可以获得整个 GPU 模拟示例运行期间的本地内存分配记录。我们需要点击 Run->Profile-> ‘app’
来重启应用。应用启动后 profile
窗口会打开,点击内存分析器,然后选择 record native allocation
。
本地内存记录在 Android Studio 中加载时的初始状态
有些游戏或者应用所依赖的库会在 new 关键字之外调用 malloc 来申请内存。这个表格视图突出显示了这种情况,因而在应对这类游戏或应用时非常有用。
当记录加载后,数据会以表格的形式呈现。表格中会显示调用 malloc 的叶子函数。除了显示函数名,表格里还会包含模块、调用计数、空间大小、和 delta 值。这些信息会被进行采样,因此不是所有的 malloc 或 free 的调用都会被捕捉到。这很大程度上取决于采样率,后面我们会讨论它。
另外很有必要了解这些占用内存的函数是被哪些函数调用的。有两种方法可图形化该信息。第一种方法是将 "Arrange by allocation method" 选项改为 "Arrange by call stack"。表格会显示调用栈的树结构,和 CPU 记录里的类似。如果当前项目包含符号 (通常适用于可调试构建,如果您正在分析一个外部的 APK,可以参考一下 文档),他们会自动被选取并启用。这样您就可以通过右键点击函数并 "Jump to source" 来直接转向源码。
在表格里右键点击一个元素会显示 "Jump to Source" 菜单
内存可视化 (本地和非本地)
我们还在内存分析器中增加了用于可视化数据的火焰图,您可以非常快速地找到分配内存最多的调用栈。该方法对于很深的调用栈非常有用。
有四种方式可以在 X 轴上对数据进行排序:
- "分配容量" (Allocation Size) 属于默认值,表示被追踪的内存总量;
- "分配计数" (Allocation Count) 表示分配内存的对象总数;
- "全部剩余容量" (Total Remaining Size) 表示在数据采集结束之前,整个数据采集过程中未被释放的内存容量;
- "全部剩余计数" (Total Remaining Count) 和剩余容量类似,表示在采集结束之前,整个采集过程中未被释放的对象总数。
采集数据加载之后,在 "全部剩余容量" 视图里,很容易发现 "lodepng" 所分配的内存容量比较大
从这里我们可以直接右键点击调用栈,然后选择 "转向源码" (Jump to Source),然后会直接转向内存分配相关的源码。不过,我们稍微花些时间看一下这里的可视化图形,会发现这里共享的父节点 WorldState 造成了多个泄漏问题。要验证这点,可以通过图形来过滤结果。
过滤/导航
和表格视图类似,图表可以通过过滤栏 (filter bar) 进行数据过滤。当启用过滤的时候,图表的数据会自动进行更新,仅显示函数符合关键词或者正则表达式的调用栈。
有的时候调用栈会比较长,或者仅仅因为屏幕的空间不足而无法完整显示全部函数的名称。您可以使用 ctrl 加鼠标滚轮进行缩放,或者可以点击图表,使用 W、A、S、D 进行导航。
验证结果
增加断点,并且快速运行两次模拟器,然后发现第二次运行的时候,由于我们覆盖了第一次运行时的一个指针造成了内存泄漏。
调试器的 Quick 视图显示第二次运行的时候 "sWorld" 已经有值了
作为快速解决方案,我们可以在处理结束后释放掉 sWorld 变量,然后再次分析应用来验证问题是否解决。
我们还是观察高层次的内存统计。验证了在模拟运行结束的时候删除 sWorld 释放了最初运行时占用的 70 MB。
应用启动分析和采样率设置
上面的例子展示了如何通过本地内存追踪来定位和解决内存泄漏问题。另一个本地内存追踪的常见用法是理解应用启动时内存的占用情况。在 Android Studio 4.1 中,我们还增加了在应用启动时采集本地内存使用记录的功能。您可以在 "Run/Debug Configuration" 里的 "Profiling" 标签页进行设置。
Profiling 标签页位于 Run Configuration 对话框中
您可以在 Run 配置对话框中自定义采集间隔或者设置应用启动时记录内存使用情况。
这里您还可以为新的采集修改采样率。更小的采样率会对整个性能产生很大的影响,而更大的采样率则会遗漏一些内存分配记录。不同的采样率针对不同类型的内存问题。
总结一下
通过全新的本地内存分析器可以定位内存泄漏并且轻松洞悉内存使用情况。快去 Android Studio 4.1 试试本地内存分析器吧。如果有任何问题和反馈可以 给我们留言。更多小窍门可以查阅我们今年早些时候在 Google 游戏峰会分享的内容:
https://www.bilibili.com/vide...
android – 如何在信号上向用户发送通知?
在我的应用中,用户可以向对方发送通知.
发送标签有可能吗?如果是这样我怎么能这样做?
我不想使用用户ID. (如何从其他用户中找到每个用户ID?)
我想像parse.com那样做.一个用户setchannel和其他用户向该频道发送通知.
提前致谢
解决方法
然后,您可以对Onesignal的create notification REST API进行POST调用.根据文档页面设置标签字段以定位您的“频道”.此调用需要从您的服务器进行,因为定位标记需要您的Onesignal App REST API密钥.
android – 如何连续停止和播放通知?
>当闹钟开始响铃时,通知声音应持续播放,直到用户拖动通知栏.
>当我向下拖动通知栏时,声音应该停止播放.
解决方法
> Notification.DEFAULT_SOUND:用于播放声音.
2.Notification.FLAG_INSISTENT:此标志会使您的声音持续响铃,直到您对通知进行了少量操作,即拖动栏或单击栏.
3.Notification.FLAG_AUTO_CANCEL:此标志用于在您看到通知后自动取消通知
android – 当应用程序在后台时,Cordova本地通知不起作用
我正在使用Cordova开发一个Android应用程序,它使用PushPlugin从我的服务器接收推送通知.
特别是,我正在使用PushPlugin Example进行一些测试.
我也在使用Cordova Local Notification plugin,因为我希望应用程序在收到推送通知后立即显示本地通知.
以下代码有效,并且仅在应用程序位于前台时显示本地通知.
即使应用程序在后台,我也希望显示本地通知.
可能吗?我怎样才能使它工作?
提前致谢
<!DOCTYPE HTML>
<html>
<head>
<title>com.PhoneGap.c2dm</title>
</head>
<body>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" charset="utf-8" src="jquery_1.5.2.min.js"></script>
<script type="text/javascript" src="PushNotification.js"></script>
<script type="text/javascript">
var pushNotification;
function onDeviceReady() {
$("#app-status-ul").append('<li>deviceready event received</li>');
document.addEventListener("backbutton", function(e){
$("#app-status-ul").append('<li>backbutton event received</li>');
if( $("#home").length > 0){
// call this to get a new token each time. don't call it to reuse existing token.
//pushNotification.unregister(successHandler, errorHandler);
e.preventDefault();
navigator.app.exitApp();
}
else{
navigator.app.backHistory();
}
}, false);
try{
pushNotification = window.plugins.pushNotification;
$("#app-status-ul").append('<li>registering ' + device.platform + '</li>');
if (device.platform == 'android' || device.platform == 'Android' || device.platform == 'amazon-fireos' ){
pushNotification.register(successHandler, errorHandler, {"senderID":"527085141383","ecb":"onNotification"});
} else {
pushNotification.register(tokenHandler, errorHandler, {"badge":"true","sound":"true","alert":"true","ecb":"onNotificationAPN"}); // obbligatorio!
}
}
catch(err) {
txt="There was an error on this page.\n\n";
txt+="Error description: " + err.message + "\n\n";
alert(txt);
}
} // fine onDeviceReady
function onNotificationAPN(e) {
if (e.alert) {
$("#app-status-ul").append('<li>push-notification: ' + e.alert + '</li>');
// showing an alert also requires the org.apache.cordova.dialogs plugin
navigator.notification.alert(e.alert);
}
if (e.sound) {
// playing a sound also requires the org.apache.cordova.media plugin
var snd = new Media(e.sound);
snd.play();
}
if (e.badge) {
pushNotification.setApplicationIconBadgeNumber(successHandler, e.badge);
}
}
function onNotification(e) {
$("#app-status-ul").append('<li>EVENT -> RECEIVED:' + e.event + '</li>');
switch( e.event ){
case 'registered':
if ( e.regid.length > 0 )
{
$("#app-status-ul").append('<li>REGISTERED -> REGID:' + e.regid + "</li>");
// Your GCM push server needs to kNow the regID before it can push to this device
// here is where you might want to send it the regID for later use.
console.log("regID = " + e.regid);
}
break;
case 'message':
// if this flag is set, this notification happened while we were in the foreground.
// you might want to play a sound to get the user's attention, throw up a dialog, etc.
var notificaOk = function(){
console.log("OK");
}
var notificaKo = function(){
console.log("KO");
}
window.plugin.notification.local.add({id: 1, title: "Product available", message: "Nexus 6 in stock", smallIcon: 'ic_dialog_email', icon: 'ic_launcher'}, notificaOk, notificaKo);
if (e.foreground){
$("#app-status-ul").append('<li>--INLINE NOTIFICATION--' + '</li>');
// on Android soundname is outside the payload.
// On Amazon fireos all custom attributes are contained within payload
var soundfile = e.soundname || e.payload.sound;
// if the notification contains a soundname, play it.
// playing a sound also requires the org.apache.cordova.media plugin
var my_media = new Media("/android_asset/www/"+ soundfile);
my_media.play();
}
else{ // otherwise we were launched because the user touched a notification in the notification tray.
if (e.coldstart)
$("#app-status-ul").append('<li>--COLDSTART NOTIFICATION--' + '</li>');
else
$("#app-status-ul").append('<li>--BACKGROUND NOTIFICATION--' + '</li>');
}
$("#app-status-ul").append('<li>MESSAGE -> MSG: ' + e.payload.message + '</li>');
//android only
$("#app-status-ul").append('<li>MESSAGE -> MSGCNT: ' + e.payload.msgcnt + '</li>');
//amazon-fireos only
$("#app-status-ul").append('<li>MESSAGE -> TIMESTAMP: ' + e.payload.timeStamp + '</li>');
break;
case 'error':
$("#app-status-ul").append('<li>ERROR -> MSG:' + e.msg + '</li>');
break;
default:
$("#app-status-ul").append('<li>EVENT -> UnkNown, an event was received and we do not kNow what it is</li>');
break;
}
}
function tokenHandler (result) {
$("#app-status-ul").append('<li>token: '+ result +'</li>');
// Your iOS push server needs to kNow the token before it can push to this device
// here is where you might want to send it the token for later use.
}
function successHandler (result) {
$("#app-status-ul").append('<li>success:'+ result +'</li>');
}
function errorHandler (error) {
$("#app-status-ul").append('<li>error:'+ error +'</li>');
}
document.addEventListener('deviceready', onDeviceReady, true);
</script>
<div id="home">
<div id="app-status-div">
<ul id="app-status-ul">
<li>Cordova PushNotification Plugin Demo</li>
</ul>
</div>
</div>
</body>
</html>
然后我使用以下nodeJS脚本向我的设备发送推送通知:
var GCM = require('gcm').GCM;
var apiKey = "***";
var gcm = new GCM(apiKey);
var devRegIdTarget = "APA9....";
var message = {
message: "Text msg",
registration_id : devRegIdTarget,
title : 'Title',
msgcnt : '1',
collapseKey : "msg1",
soundname : 'beep.wav'
};
message.timetoLive = 3000;
message.delayWhileIdle = true;
gcm.send(message, function(err, messageId){
if (err) {
console.log("Something has gone wrong!");
} else {
console.log("Sent with message ID: ", messageId);
}
});
解决方法:
我在使用PushPlugin和localnotification方面有类似的经验.
对于我的情况,通知在后台工作但是android的白色空白.
我整晚都在检查localnotification插件的源代码,但事实证明这是PushPlugin本身的问题. (我会说,确切的问题是两个插件之间断开连接)在PushPlugin的源代码中,它检查应用程序是在前台还是后台.
如果应用程序在后台,则不会向cordova应用程序触发通知事件,但PushPlugin会创建自己的本地通知.
@Override
protected void onMessage(Context context, Intent intent) {
Log.d(TAG, "onMessage - context: " + context);
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null)
{
// if we are in the foreground, just surface the payload, else post it to the statusbar
if (PushPlugin.isInForeground()) {
extras.putBoolean("foreground", true);
PushPlugin.sendExtras(extras);
}
else {
extras.putBoolean("foreground", false);
// Send a notification if there is a message
if (extras.getString("message") != null && extras.getString("message").length() != 0) {
createNotification(context, extras);
}
}
}
}
因此,如果您想在后面运行应用程序时使用自定义的smallicon.
我通过覆盖初始代码来快速破解
public void createNotification(Context context, Bundle extras)
{
notificationmanager mnotificationmanager = (notificationmanager) getSystemService(Context.NOTIFICATION_SERVICE);
String appName = getAppName(this);
Intent notificationIntent = new Intent(this, PushHandlerActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationIntent.putExtra("pushBundle", extras);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
int defaults = Notification.DEFAULT_ALL;
if (extras.getString("defaults") != null) {
try {
defaults = Integer.parseInt(extras.getString("defaults"));
} catch (NumberFormatException e) {}
}
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setDefaults(defaults)
.setSmallIcon(getResourceId(context, "pushicon", "drawable", context.getPackageName()))
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), getResourceId(context, "icon", "drawable", context.getPackageName())))
.setWhen(System.currentTimeMillis())
.setContentTitle(extras.getString("title"))
.setTicker(extras.getString("title"))
.setContentIntent(contentIntent)
.setAutoCancel(true);
String message = extras.getString("message");
if (message != null) {
mBuilder.setContentText(message);
} else {
mBuilder.setContentText("<missing message content>");
}
String msgcnt = extras.getString("msgcnt");
if (msgcnt != null) {
mBuilder.setNumber(Integer.parseInt(msgcnt));
}
int notId = 0;
try {
notId = Integer.parseInt(extras.getString("notId"));
}
catch(NumberFormatException e) {
Log.e(TAG, "Number format exception - Error parsing Notification ID: " + e.getMessage());
}
catch(Exception e) {
Log.e(TAG, "Number format exception - Error parsing Notification ID" + e.getMessage());
}
mnotificationmanager.notify((String) appName, notId, mBuilder.build());
}
现在,您需要做的就是将名为“pushicon”的图像放在可绘制的文件夹平台/ android / res / drawable / pushicon.png中
(我为大图标使用图像“图标”)
如果这很麻烦,我为此做了一个git repo
https://github.com/zxshinxz/PushPlugin.git
cordova插件添加https://github.com/zxshinxz/PushPlugin.git
希望其他程序员不要经历我经历的痛苦.
关于Android中的本地通知?和安卓本地推送通知的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Android Studio 4.1 中的本地内存分析、android – 如何在信号上向用户发送通知?、android – 如何连续停止和播放通知?、android – 当应用程序在后台时,Cordova本地通知不起作用等相关知识的信息别忘了在本站进行查找喔。
本文标签: