【Android】揭秘如何利用Service与线程制造安卓后台通知栏推送_ ...
2023年7月7日发(作者:)
【Android】揭秘如何利⽤Service与线程制造安卓后台通知栏推送安卓设备的后台通知栏推送很烦,主要是可以通过利⽤安卓的Service功能,在app被点击Home键或者返回键之后,依旧可以在挂载后台运⾏。反正Home键或者返回键只能杀死Activity⽽不能终结Service的,不像Windows点关闭键默认是关闭程序界⾯+程序线程。本⽂的意义相当于在Windows中制造⼀条线程,或者是对Windows应⽤程序的关闭键进⾏重写,让其应⽤程序的关闭仅仅是隐藏界⾯,不杀死进程。理论上,只要这个Service不被安卓系统因内存不⾜所回收,会⼀直持续到设备重启,或者,app良⼼点,提供⼀个关闭Service的功能。Service⼀般配合Android的线程处理机制所实现,下⾯举⼀个⼩例⼦说明这个问题:如图,此app⼀启动,则开启两条进程,⼀条是每2秒系统搞⼀个Toast显⽰当前时间,⼀条是每10秒在通知栏推送⼀条消息。这app真是够流氓的,你完全可以把显⽰时间改改,改成⼀段Java从远程获取数据的代码,详情看见《【Java】读取⽹页中的内容》(),来下些垃圾应⽤,⽤⽂件流放到⼿机内存,等待这条线程结束再⽤通知栏推送给⽤户,真的是呵呵了。据说,⽤户的流量就这样跑光的。但是,本app同样提供⼀个停⽌服务的按钮,终⽌这两条线程。制作过程如下:1、字符⽂件,主要是两个按钮的字体,不是关键: 利⽤Service与线程实现推送 Settings 开始服务 终⽌服务2、之后在reslayoutactivity_把这两个按钮摆好,⾃上⽽下的垂直线性布局,摆横向两个匹配⽗布局,纵向包裹内容的按钮赋予相应的id。 3、之后,正式开始我们推送线程的制作,在src⽂件夹⼯程包下这⾥是eDemo新建⼀个继承e类的,如下图:之后,在空⽩位置按Alt+Shift+S之后再按V,表⽰重写Service下的onStartCommand()⽅法与onDestroy()⽅法,这两个⽅法分别可以被任何App中的,利⽤Intent指定为本服务的startService()⽅法与stopService()所触发。这也就是所谓的“安卓Service⽣命周期”:ervice()->onCreate()->onStart()->Service running->rvice()->onDestroy()->Service stop。其中:如果Service还没有运⾏,则android先调⽤onCreate()然后调⽤onStart();如果Service已经运⾏,则只调⽤onStart(),所以⼀个Service的onStart⽅法可能会重复调⽤多次。 从⽗⽅法拿到onStartCommand()⽅法与onDestroy()⽅法之后先别急着实现,与《【Android】多个Activity之间利⽤bundle传递数值》(),新建的界⾯Activity之后,要先去注册⼀样,这⾥新建服务Service之后,同样要去注册这个TimeService。的代码修改如下,也就是加上⼀⾏: 4、接着,我们要实现TimeService中的onStartCommand()⽅法与onDestroy()⽅法。这⾥⽤到了《【Android】进度条与线程之间的消息处理》()的知识。先令线程的运⾏标识flag——isRun为真。开两条线程。⼀条不停利⽤Toast显⽰当前时间,这⾥,由于Toast是处于线程的消息处理器当中,所以即使在服务中,也可以直接⽤到getApplicationContext()获取整个安卓设备的上下⽂。⽆须搞⼀个Looper辅助,此线程每隔2秒运⾏⼀次直到isRun为false终⽌,对Java线程不熟悉的朋友,可以参考《【Java】定时器、线程与匿名内部类》()与《【Java】线程并发、互斥与同步》(),这⾥不能⽤定时器去搞,不然Toast会出错。另⼀条线程,是利⽤到《【Android】利⽤Notification操作设备的通知栏》()的知识,每隔10秒向通知栏推送消息。在onStartCommand()中定义线程并开始,在onDestroy()只要把类全局变量isRun搞为false,让这两条线程⾃然死亡就可以了。最终的代码如下:package edemo;import cation;import cationManager;import gIntent;import e;import ;import r;import r;import e;import ;import ;public class TimeService extends Service { private boolean isRun;// 线程是否继续的标志 private Handler handler1; // 显⽰当前时间线程消息处理器。 private Handler handler2;// 推送通知栏消息的线程消息处理器。 private int notificationCounter;// ⼀个⽤于计算通知多少的计数器。 @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onDestroy() { roy(); isRun = false; } @Override public int onStartCommand(Intent intent, int flags, int startId) { isRun = true; final NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);// 注册通知管理器 new Thread(new Runnable() { @Override // 在Runnable中,如果要让线程⾃⼰⼀直跑下去,必须⾃⼰定义while结构 // 如果这个run()⽅法读完了,则整个线程⾃然死亡 public void run() { // 定义⼀个线程中⽌标志 while (isRun) { try { (2000);// Java中线程的休眠,必须在try-catch结构中,每2s秒运⾏⼀次的意思 } catch (InterruptedException e) { tackTrace(); } if (!isRun) { break; } Message msg = new Message(); // 在安卓中,不要在线程中直接现实⽅法,这样app容易崩溃,有什么要搞,扔到消息处理器中实现。 ssage(msg); } } } }).start();// 默认线程不启动,必须⾃⼰start() // 不停在接受线程的消息,根据消息的参数,进⾏处理 ,这⾥没有传递过来的参数 handler1 = new Handler(new ck() {// 这样写,就不弹出什么泄漏的警告了 @Override public boolean handleMessage(Message msg) { // 安卓显⽰当前时间的⽅法 Time time = new Time(); ow(); String currentTime = ("%Y-%m-%d %H:%M:%S"); xt(getApplicationContext(), "当前时间为:" + currentTime, _SHORT) .show(); return false; } }); new Thread(new Runnable() { @Override // 在Runnable中,如果要让线程⾃⼰⼀直跑下去,必须⾃⼰定义while结构 // 如果这个run()⽅法读完了,则整个线程⾃然死亡 public void run() { // 定义⼀个线程中⽌标志 while (isRun) { try { (10000);// Java中线程的休眠,必须在try-catch结构中 } catch (InterruptedException e) { tackTrace(); } if (!isRun) { break; } Message msg = new Message(); ssage(msg); } } }).start();// 默认线程不启动,必须⾃⼰start() handler2 = new Handler(new ck() {// 这样写,就不弹出什么泄漏的警告了 @SuppressWarnings("deprecation") @Override // 这⾥estEventInfo, // 设置通知标题与内容会被eclipse标志过时, // 但新的⽅法,使⽤builder去设置通知的⽅法只能应⽤于android3.0以上的设备,对于android2.2的设备是⽆法使⽤的。 // 在现时国内有部分设备还是在android2.2的情况下,还是⽤这条⼏乎兼容所有版本安卓的“过时”⽅法吧! public boolean handleMessage(Message msg) { notificationCounter++;// 计数器+1 Notification notification = new Notification(); = _launcher;// 设置通知图标为app的图标 = _AUTO_CANCEL;// 点击通知打开引⽤程序之后通知⾃动消失 Text = "显⽰通知";// 在⽤户没有拉开标题栏之前,在标题栏中显⽰的⽂字 = tTimeMillis();// 设置发送时间 ts = T_ALL;// 设置使⽤默认声⾳、震动、闪光灯 // 以下三⾏:在安卓设备任意环境中中,如果点击信息则打开MainActivity Intent intent = new Intent(getApplicationContext(), ); PendingIntent pendingIntent = PendingIntent .getActivity(getApplicationContext(), 0, intent, 0); estEventInfo( getApplicationContext(), "消息标题", "消息内容,第" + notificationCounter + "条通知", pendingIntent); (notificationCounter, notification);// 要求通知管理器发送这条通知,其中第⼀个参数是通知在系统的id return false; } }); }); return START_STICKY;// 这个返回值其实并没有什么卵⽤,除此以外还有START_NOT_STICKY与START_REDELIVER_INTENT }}5、之后的MainActivity⾮常简单,两个按钮的点击事件,⼀个开始服务,另⼀个结束服务,为了防⽌启动多条服务,点击完⼀个按钮禁⽤,开启另⼀个按钮。package edemo;import ;import ;import kListener;import ;import ty;import ;public class MainActivity extends Activity {private Button button1;private Button button2; @Override protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_main); //注册组件 button1=(Button)findViewById(1); button2=(Button)findViewById(2); //程序开始开启Service,禁⽤开始按钮 startService(new Intent(,)); bled(false); //两个按钮的点击事件 lickListener(new OnClickListener() {
@Override public void onClick(View arg0) { startService(new Intent(,)); bled(false); bled(true); } }); lickListener(new OnClickListener() {
@Override public void onClick(View arg0) { stopService(new Intent(,)); bled(true); bled(false); } });
}}
发布者:admin,转转请注明出处:http://www.yc00.com/news/1688678391a161811.html
评论列表(0条)