最近很多小伙伴都在问Android实现Service下载文件,Notification显示下载进度的示例和android下载进度这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展An
最近很多小伙伴都在问Android实现Service下载文件,Notification显示下载进度的示例和android 下载进度这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展Android accessibility service detect notification、Android Notification 从 notify 到添加 view 的处理流程、android Notification 状态栏通知使用示例、android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转)等相关知识,下面开始了哦!
本文目录一览:- Android实现Service下载文件,Notification显示下载进度的示例(android 下载进度)
- Android accessibility service detect notification
- Android Notification 从 notify 到添加 view 的处理流程
- android Notification 状态栏通知使用示例
- android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转)
Android实现Service下载文件,Notification显示下载进度的示例(android 下载进度)
先放个gif。。最终效果如果:
主要演示了Android从服务器下载文件,调用Notification显示下载进度,并且在下载完毕以后点击通知会跳转到安装APK的界面,演示是在真实的网络环境中使用真实的URL进行演示,来看看代码:
MainActivity代码非常简单,就是启动一个Service:
public class MainActivity extends AppCompatActivity { String download_url="http://shouji.360tpcdn.com/160329/a9037075b8d3aa98fbf6115c54a5b895/com.alensw.PicFolder_4722404.apk"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void bt_start_service(View view){ Intent intent=new Intent(this,DownLoadService.class); intent.putExtra("download_url",download_url); startService(intent); } }
DownLoadService里面,在onStartCommand方法里面是关键代码,调用NotifyUtil这个工具类的“notify_progress”方法去显示一个通知,与此同时开始下载APK文件,DownLoadService代码如下:
public class DownLoadService extends Service { String download_url; String savePath= Environment.getExternalStorageDirectory()+"/liulan.apk"; private int requestCode = (int) SystemClock.uptimeMillis(); private NotifyUtil currentNotify; File mFile; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent,int flags,int startId) { mFile=new File(savePath); download_url=intent.getStringExtra("download_url"); Log.e("test","执行onStartCommand"); //设置想要展示的数据内容 Intent intent_noti = new Intent(); intent_noti.setAction(Intent.ACTION_VIEW); //文件的类型,从tomcat里面找 intent_noti.setDataAndType(Uri.fromFile(mFile),"application/vnd.android.package-archive"); PendingIntent rightPendIntent = PendingIntent.getActivity(this,requestCode,intent_noti,PendingIntent.FLAG_UPDATE_CURRENT); int smallIcon = R.drawable.xc_smaillicon; String ticker = "正在更新快图浏览"; //实例化工具类,并且调用接口 NotifyUtil notify7 = new NotifyUtil(this,7); notify7.notify_progress(rightPendIntent,smallIcon,ticker,"快图浏览升级程序","正在下载中",false,download_url,savePath,new NotifyUtil.DownLoadListener() { @Override public void OnSuccess(File file) { mFile=file; DownLoadService.this.stopSelf(); } @Override public void onFailure(Throwable t,int errorNo,String strMsg) { } }); currentNotify = notify7; return super.onStartCommand(intent,flags,startId); } }
在调用“notify_progress”方法的时候,已经开始下载文件了,那么下载的代码是什么呢?如下:
public void notify_progress(PendingIntent pendingIntent,int smallIcon,String ticker,String title,String content,boolean sound,boolean vibrate,boolean lights,String download_url,String savePath,final DownLoadListener listener) { setCompatBuilder(pendingIntent,title,content,sound,vibrate,lights); /* * 因为进度条要实时更新通知栏也就说要不断的发送新的提示,所以这里不建议开启通知声音。 * 这里是作为范例,给大家讲解下原理。所以发送通知后会听到多次的通知声音。 */ FinalHttp fh = new FinalHttp(); HttpHandler<File> httpHandler=fh.download(download_url,new AjaxCallBack<File>() { @Override public void onLoading(long count,long current) { super.onLoading(count,current); double a=count; double b=current; double currentPro=(double)((b/a)*100); cBuilder.setProgress(100,(int)currentPro,false); sent(); } @Override public void onSuccess(File file) { super.onSuccess(file); cBuilder.setContentText("下载完成").setProgress(0,false); sent(); listener.OnSuccess(file); } @Override public void onFailure(Throwable t,String strMsg) { super.onFailure(t,errorNo,strMsg); listener.onFailure(t,strMsg); } }); }
这里用到了afinal.jar
这个jar已经封装好下载的工具类,我们直接拿来用就行。下载成功之后会通过DownLoadListener这个接口回调到DownLoadService里面,最终运行效果就如最上面那个gif动态图运行效果一样。
项目下载地址:点击下载
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
Android accessibility service detect notification
0
down vote
favorite
|
I''m trying to make my app detect whenever a notification is displayed. I''ve enabled it in the settings app andonServiceConnecteddoes get called, however when I create a notification or receive an e-mail through the gmail app nothing happens,onAccessibilityEventdoes not get called. Android manifest:
NotificationService.java
Thanks for any help. ![]()
|
||||||||
|
|
2 Answers
up vote
2
down vote
accepted
|
Accessibility services in Android 4.0 and above can behave strangely if there is no accessibility-service meta-data tag defined in the manifest. Try defining the meta-data as in the examples below. You should continue to use setServiceInfo() to maintain backward compatibility with pre-4.0 devices. Also, I would recommend specifying a feedback type that is specific to your service, rather than using "all". AndroidManifest.xml
res/xml/accessibilityservice.xml
There was an error in your feedbackType. Corrected below. Still, consider using a more specific feedback type. NotificationService.java
|
||||||
|
|


up vote
1
down vote
|
The app using AccessibilityService needed to have a permission from settings>Accessibility in order to access the system events. Allow permission from settings . This may work check this link accessibility service is not started |
Android Notification 从 notify 到添加 view 的处理流程
创建 Notification 是很容易的,android8.0 以后开始加入通知渠道 NotificationChannel,然后在构造 NotificationCompat.Builder 的时候,指定要发送的渠道,最后调用 NotificationManager.notify (id,notification) 发送通知。
public void notify(int id, Notification notification)
{
notify(null, id, notification);
}
---------------
public void notify(String tag, int id, Notification notification)
{
notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
}
---------------
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
{
INotificationManager service = getService();
final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam);
...
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
copy, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
-------------------
static public INotificationManager getService()
{
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService("notification");
sService = INotificationManager.Stub.asInterface(b);
return sService;
}
获取了 INotificationManager 远程接口对象,把 Notification 给加入到队列中,
INotificationManager 的远程对象是 NotificationManagerService 里的 mservice,NotificationManagerService 是系统服务。在开机启动的时候,Systemserver 里和其他系统服务一起启动,最后注册到 ServiceManager 里。
publishBinderService (Context.NOTIFICATION_SERVICE, mService); // 把 service 注册到 Servicemanager 里
----
private final IBinder mService = new INotificationManager.Stub(){
...
}
接着前面的,找到了 enqueueNotificationWithTag
@Override
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Notification notification, int userId) throws RemoteException {
enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Binder.getCallingPid(), tag, id, notification, userId);
}
------------
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int incomingUserId) {
.... 处理 notification 包含的信息,通知渠道,优先级。。
mHandler.post(new EnqueueNotificationRunnable(userId, r));
}
把 notification 转换为 NotificationRecord,并 post 给 EnqueueNotificationRunnable,
EnqueueNotificationRunnable 的 run 方法里。
@Override
public void run() {
synchronized (mNotificationLock) {
mEnqueuedNotifications.add(r);
scheduleTimeoutLocked(r);
...
mHandler.post(new PostNotificationRunnable(r.getKey()));
}
------------
@Override
public void run() {
synchronized (mNotificationLock) {
try {
NotificationRecord r = null;
int N = mEnqueuedNotifications.size();
NotificationRecord old = mNotificationsByKey.get(key);
final StatusBarNotification n = r.sbn;
final Notification notification = n.getNotification();
...
if (notification.getSmallIcon() != null) {
StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
mListeners.notifyPostedLocked(n, oldSbn);
if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
mHandler.post(new Runnable() {
@Override
public void run() {
mGroupHelper.onNotificationPosted(
n, hasAutoGroupSummaryLocked(n));
}
});
}
}
...
buzzBeepBlinkLocked(r);
}
------------
void buzzBeepBlinkLocked(NotificationRecord record) {
处理 notification 的 声音 震动和灯光闪烁
}
------------
public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
发送给状态栏
mHandler.post(new Runnable() {
@Override
public void run() {
notifyPosted(info, sbnToPost, update);
}
});
}
↓
private void notifyPosted(final ManagedServiceInfo info,
final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
final INotificationListener listener = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
listener.onNotificationPosted(sbnHolder, rankingUpdate);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
}
}
INotificationListener 是另一个远程接口对象
protected class NotificationListenerWrapper extends INotificationListener.Stub
------------
@Override
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
NotificationRankingUpdate update) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = sbn;
args.arg2 = mRankingMap;
mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
args).sendToTarget();
}
case MSG_ON_NOTIFICATION_POSTED: {
SomeArgs args = (SomeArgs) msg.obj;
StatusBarNotification sbn = (StatusBarNotification) args.arg1;
RankingMap rankingMap = (RankingMap) args.arg2;
args.recycle();
onNotificationPosted(sbn, rankingMap);
------------
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
onNotificationPosted(sbn);
}
public void onNotificationPosted(StatusBarNotification sbn) {
// optional
}
很意外,发现方法是空的,那调这么多有什么用? 研究了一下发现,onNotificationPosted 的这个方法属于的是
public abstract class NotificationListenerService extends Service {
1
NotificationListenerService 是个抽象方法,那很自然调用的时候会调用它的子类,
然后
public class NotificationListenerWithPlugins extends NotificationListenerService
1
但是找了一圈 NotificationListenerWithPlugins ,没有 onNotificationPosted,那只有继续找它的子类了,
后来发现,在 Statusbar 里有个匿名内部类实现了 NotificationListenerService 的方法。
private final NotificationListenerWithPlugins mNotificationListener =
new NotificationListenerWithPlugins() {
...
@Override
public void onNotificationPosted(final StatusBarNotification sbn,
final RankingMap rankingMap) {
mHandler.post(new Runnable() {
@Override
public void run() {
...
if (isUpdate) {
updateNotification(sbn, rankingMap);
} else {
addNotification(sbn, rankingMap);
}
...
}
}
...
}
------------
public void addNotification(StatusBarNotification notification, RankingMap ranking)
throws InflationException {
Entry shadeEntry = createNotificationViews(notification);
boolean isHeadsUped = shouldPeek(shadeEntry);.
...
}
------------
protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
throws InflationException {
NotificationData.Entry entry = new NotificationData.Entry(sbn);
Dependency.get(LeakDetector.class).trackInstance(entry);
entry.createIcons(mContext, sbn);
// Construct the expanded view.
inflateViews(entry, mStackScroller);
}
------------
protected void inflateViews(Entry entry, ViewGroup parent) {
new RowInflaterTask().inflate(mContext, parent, entry,
row -> {
bindRow(entry, pmUser, sbn, row);
updateNotification(entry, pmUser, sbn, row);
});
}
最后 bindRow 就是去构造通知栏的通知 View,然后 updateNotification 就是去显示到状态栏。
private void updateNotification(Entry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row) {
...
row.updateNotification(entry);
}
------------
public void updateNotification(NotificationData.Entry entry) {
mEntry = entry;
mStatusBarNotification = entry.notification;
mNotificationInflater.inflateNotificationViews();
}
------------
public void inflateNotificationViews() {
inflateNotificationViews(FLAG_REINFLATE_ALL);
}
------------
void inflateNotificationViews(int reInflateFlags) {
...
StatusBarNotification sbn = mRow.getEntry().notification;
new AsyncInflationTask(sbn, reInflateFlags, mRow, mIsLowPriority,
mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
mCallback, mRemoteViewClickHandler).execute();
}
使用了异步任务 AsyncTask 去完成布局
AsyncInflationTask
@Override
protected InflationProgress doInBackground(Void... params) {
return createRemoteViews(mReInflateFlags,
recoveredBuilder, mIsLowPriority, mIsChildInGroup,
mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
packageContext);
}
------------
private static InflationProgress createRemoteViews(int reInflateFlags,
Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
Context packageContext) {
InflationProgress result = new InflationProgress();
isLowPriority = isLowPriority && !isChildInGroup;
if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
}
if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
result.newExpandedView = createExpandedView(builder, isLowPriority);
}
if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
}
if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
result.newPublicView = builder.makePublicContentView();
}
if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
: builder.makeAmbientNotification();
}
result.packageContext = packageContext;
return result;
}
到了这里,都是创建各种布局
比如 createContentView
public RemoteViews createContentView() {
return createContentView(false /* increasedheight */ );
}
------------
public RemoteViews createContentView(boolean increasedHeight) {
if (mN.contentView != null && useExistingRemoteView()) {
return mN.contentView;
} else if (mStyle != null) {
final RemoteViews styleView = mStyle.makeContentView(increasedHeight);
if (styleView != null) {
return styleView;
}
}
return applyStandardTemplate(getBaseLayoutResource());
}
这里会去判断我们是否有在 notification 里添加 style, 如果有不同的 style,比如音乐播放器那种 notification,就是自定义 style,如果没有,那就用默认的 layout。
private int getBaseLayoutResource() {
return R.layout.notification_template_material_base;
}
------------
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:tag="base" >
<include layout="@layout/notification_template_header" />
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_marginTop="@dimen/notification_content_margin_top"
android:layout_marginBottom="@dimen/notification_content_margin_bottom"
android:orientation="vertical" >
<include layout="@layout/notification_template_part_line1" />
<include layout="@layout/notification_template_text" />
<include
android:layout_width="match_parent"
android:layout_height="@dimen/notification_progress_bar_height"
android:layout_marginTop="@dimen/notification_progress_margin_top"
layout="@layout/notification_template_progress" />
</LinearLayout>
<include layout="@layout/notification_template_right_icon" />
</FrameLayout>
原来这就是我们用的 notification 的布局内容。
private RemoteViews applyStandardTemplate(int resId) {
return applyStandardTemplate(resId, mParams.reset().fillTextsFrom(this));
}
private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
return applyStandardTemplate(resId, mParams.reset().hasProgress(hasProgress)
.fillTextsFrom(this));
}
private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p) {
updateBackgroundColor(contentView);
bindNotificationHeader(contentView, p.ambient);
bindLargeIcon(contentView);
}
android Notification 状态栏通知使用示例
ch7_notification.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="这是一个Notification使用示例"/>
<Button android:id="@+id/bt_sendNotification"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="发送Notification"/>
</LinearLayout>
ch7_second.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="这是一个通过Notification启动的Activity"/>
</LinearLayout>
NotificationActivity.java:
package com.example.ch7;
import com.example.baseexample.R;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.location.GpsStatus.NmeaListener;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class NotificationActivity extends Activity {
private Button bt_sendNotification = null;
private Intent mIntent = null;
private PendingIntent mPendingIntent = null;
private Notification mNotification = null;
private NotificationManager mNotificationManager = null;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.ch7_notification);
bt_sendNotification = (Button)findViewById(R.id.bt_sendNotification);
bt_sendNotification.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
mIntent = new Intent(NotificationActivity.this,SecondActivity.class);
mPendingIntent = PendingIntent.getActivity(NotificationActivity.this, 0, mIntent, 0);
mNotification = new Notification();
mNotification.icon = R.drawable.ic_launcher;
mNotification.tickerText="实例";
mNotification.defaults = Notification.DEFAULT_ALL;
mNotification.flags = Notification.FLAG_INSISTENT;
mNotification.setLatestEventInfo(NotificationActivity.this, "点击查看", "这是一个Notification示例", mPendingIntent);
mNotificationManager.notify(1,mNotification);
}
});
}
}
SecondActivity.java :
package com.example.ch7;
import com.example.baseexample.R;
import android.app.Activity;
import android.os.Bundle;
public class SecondActivity extends Activity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.ch7_second);
}
}
<activity android:name="com.example.ch7.NotificationActivity" android:label="@string/app_name"></activity>
<activity android:name="com.example.ch7.SecondActivity" android:label="@string/app_name"></activity>
android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转)
网上很多的例子都是直接获取 Notification 对象来设置一个通知,其实 Notification 跟 Dialog 一样,也有自己的 Builder,可以用 builder 对象来设置一个 Notification
这个例子是在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转(跟 android 的 vcard 文件导入时弹出的 Notification 一样)
NotificationManager mNotificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Notification.Builder(context);
builder.setOngoing(true);
builder.setProgress (total, current, false);// 设置进度条,false 表示是进度条,true 表示是个走马灯
builder.setTicker (title);// 设置 title
builder.setWhen(System.currentTimeMillis());
builder.setContentTitle (content);// 设置内容
builder.setAutoCancel (true);// 点击消失
builder.setSmallIcon(R.drawable.upload);
builder.setContentIntent (PendingIntent.getActivity (context, 0, new Intent (), 0));// 这句和点击消失那句是 “Notification 点击消失但不会跳转” 的必须条件,如果只有点击消失那句,这个功能是不能实现的
Notification noti = builder.getNotification();
mNotificationManager.notify(id,noti);
希望这个例子对其他人有点用,因为我特曾为这个功能苦恼过,呵呵!
关于Android实现Service下载文件,Notification显示下载进度的示例和android 下载进度的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Android accessibility service detect notification、Android Notification 从 notify 到添加 view 的处理流程、android Notification 状态栏通知使用示例、android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转)等相关知识的信息别忘了在本站进行查找喔。
本文标签: