安卓开机自启动服务没有ACTION如何启动一个服务

Android实现点击通知栏后,先启动应用再打开目标Activity - 简书
下载简书移动应用
写了3804字,被51人关注,获得了32个喜欢
Android实现点击通知栏后,先启动应用再打开目标Activity
在开发Android app的过程中,遇到这样一个需求:app中启动一个Service,该Service在独立进程中运行,与服务器保持长连接,将服务器推送过来的消息在通知栏中显示,并设置点击动作,点击后跳转到app中对应的Activity。目前遇到的问题是Service以独立进程运行,在收到消息并弹出通知后,app本身的进程有两种情况:
app正在运行
对于第一种情况,处理就非常简单了,直接将参数传入Intent并打开对应的Activity即可。
但第二种情况比较复杂,因为app已经退出,而要打开的Activity中的某些操作是需要依赖app的初始化的,这些初始化操作是在app启动过程中进行的。举个例子,一个购物应用推送了某个新商品的消息,用户点击通知后进入商品详情的Activity,而该Activity中有个订购Button,点击该Button后就会从本地中获取用户的Id等信息并发一条消息给服务器,告诉服务器某用户订购了该商品。这些用户信息是在app启动时与服务器进行一系列交互后取得的。如果app退出后直接进入详情Activity并点击购买,就会因为获取不到用户信息而出错。
所以目前要解决的问题时,在Notification中设置点击动作,如果app本身正在运行,直接跳转到目标Activity;如果app已经退出,先启动app完成初始化,再跳转到目标Activity。
方案和思路
我们假设目前有三个Activity:
SplashActivity 用于显示app大图,同时进行用户登录等操作,服务器返回数据后跳转到MainActivity。
MainActivity app的主Activity。
DetailActivity MainActivity中点击Button进入的Activity,用于显示某件商品详情。
而弹出通知的Service在另外一个进程中。
我们要达到的目的是:
点击通知栏通知,假如app正在运行,则直接跳转到DetailActivity显示具体内容,在DetailActivity中按Back键返回MainActivity
点击通知栏通知,假如app已经退出,先从SplashActivity进入,显示app启动界面,初始化操作完成后进入MainActivity再跳转到DetailActivity显示具体内容,在DetailActivity中按Back键返回MainActivity。
初步的思路是先判断app进程是否存在,如果存在的话,就利用startActivities启动MainActivity和DetailActivity。为什么还要启动MainActivity而不直接只启动DetailActivity?因为有如下情况,进程中的所有Activity都已经退出了,但进程还没有被系统回收,这时判断进程是否存在返回true,然后只启动DetailActivity的话,按Back键任务栈就直接到底,返回桌面了。而我们要的效果是按Back键返回上一级Activity,也就是MainActivity。
如果app进程已经退出,不存在了,此时就用一个Intent启动应用,该Intent中包含一个Bundle, Bundle中存有启动DetailActivity所需的参数,这个Intent传入SplashActivity后,再由SplashActivity传给MainActivity,在MainActivity中加入判断,如果有该参数,则表示应用是从通知栏启动的,要进行跳转到DetailActivity的操作,否则就是常规启动。
有了大概的实现思路后,大家来个demo实际操作一下。首先,我们的demo有简单的组件:
PushService,在新进程中启动的Service,负责监听服务器,收到服务器的信息后将消息广播出去,在本demo中,为了简化,只是简单的广播一个消息
ShowNotificationReceiver,在新进程中注册的BroadcastReceiver,收到PushService发的消息后,会在通知栏弹出通知
NotificationReceiver, 在新进程中注册的BroadcastReceiver,用来设置点击通知栏通知的动作,打开app中的某个Activity
SplashActivity, app启动页面,先是启动图片,3s后进入MainActivity
MainActivity,app的主Activity
DetailActivity,app中显示详情的Activity
PushService.java
首先是PushService,要在新进程中启动,要在AndroidManifest.xml中加入以下注册Service的代码
&service android:name=".PushService"
android:process=":push"/&
PushService的工作很简单,启动后发一个广播在通知栏显示通知,然后常驻在后台
public class PushService extends Service{
public IBinder onBind(Intent intent) {
public void onCreate() {
super.onCreate();
Log.i("PushService", "PushService onCreate");
//用AlarmManager定时发送广播
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, ShowNotificationReceiver.class);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.currentThreadTimeMillis(), pendingIntent);
ShowNotificationReceiver.java
这个广播类用来在通知栏弹出通知
public class ShowNotificationReceiver extends BroadcastReceiver{
private static final String TAG = "RepeatReceiver";
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "ShowNotificationReceiver onReceive");
//设置点击通知栏的动作为启动另外一个广播
Intent broadcastIntent = new Intent(context, NotificationReceiver.class);
PendingIntent pendingIntent = PendingIntent.
getBroadcast(context, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("这就是通知的头")
.setTicker("这是通知的ticker")
.setContentIntent(pendingIntent)
.setSmallIcon(android.R.drawable.ic_lock_idle_charging);
Log.i("repeat", "showNotification");
NotificationManager manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(2, builder.build());
NotificationReceiver.java
点击通知栏后,会发送一个广播,NotificationReceiver收到该广播后,就会判断,app进程是否仍然存活,根据app进程的不同状态,定义不同的app启动方式
public class NotificationReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
//判断app进程是否存活
if(SystemUtils.isAppAlive(context, "com.liangzili.notificationlaunch")){
//如果存活的话,就直接启动DetailActivity,但要考虑一种情况,就是app的进程虽然仍然在
//但Task栈已经空了,比如用户点击Back键退出应用,但进程还没有被系统回收,如果直接启动
//DetailActivity,再按Back键就不会返回MainActivity了。所以在启动
//DetailActivity前,要先启动MainActivity。
Log.i("NotificationReceiver", "the app process is alive");
Intent mainIntent = new Intent(context, MainActivity.class);
//将MainAtivity的launchMode设置成SingleTask, 或者在下面flag中加上Intent.FLAG_CLEAR_TOP,
//如果Task栈中有MainActivity的实例,就会把它移到栈顶,把在它之上的Activity都清理出栈,
//如果Task栈不存在MainActivity实例,则在栈顶创建
mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent detailIntent = new Intent(context, DetailActivity.class);
detailIntent.putExtra("name", "电饭锅");
detailIntent.putExtra("price", "58元");
detailIntent.putExtra("detail", "这是一个好锅, 这是app进程存在,直接启动Activity的");
Intent[] intents = {mainIntent, detailIntent};
context.startActivities(intents);
//如果app进程已经被杀死,先重新启动app,将DetailActivity的启动参数传入Intent中,参数经过
//SplashActivity传入MainActivity,此时app的初始化已经完成,在MainActivity中就可以根据传入
//参数跳转到DetailActivity中去了
Log.i("NotificationReceiver", "the app process is dead");
Intent launchIntent = context.getPackageManager().
getLaunchIntentForPackage("com.liangzili.notificationlaunch");
launchIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
Bundle args = new Bundle();
args.putString("name", "电饭锅");
args.putString("price", "58元");
args.putString("detail", "这是一个好锅, 这是app进程不存在,先启动应用再启动Activity的");
launchIntent.putExtra(Constants.EXTRA_BUNDLE, args);
context.startActivity(launchIntent);
SplashActivity.java
SplashActivity.java先是app启动的图片,3s后进入MainActivity, 如果启动SplashActivity的Intent中带有参数,就将参数取出,放入启动MainActivity的Intent中
public class SplashActivity extends AppCompatActivity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
//隐藏ActionBar
getSupportActionBar().hide();
//使用handler倒数3秒后进入MainActivity
new Handler().postDelayed(new Runnable() {
public void run() {
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
//如果启动app的Intent中带有额外的参数,表明app是从点击通知栏的动作中启动的
//将参数取出,传递到MainActivity中
if(getIntent().getBundleExtra(Constants.EXTRA_BUNDLE) != null){
intent.putExtra(Constants.EXTRA_BUNDLE,
getIntent().getBundleExtra(Constants.EXTRA_BUNDLE));
startActivity(intent);
MainActivity.java
MainActivity中,如果有参数传入,就在初始化结束后,根据参数启动DetailActivity,如果没有参数传入,就此结束自己的任务
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, PushService.class);
startService(intent);
setTitle("MainActivity");
Bundle bundle = getIntent().getBundleExtra(Constants.EXTRA_BUNDLE);
if(bundle != null){
//如果bundle存在,取出其中的参数,启动DetailActivity
String name = bundle.getString("name");
String price = bundle.getString("price");
String detail = bundle.getString("detail");
SystemUtils.startDetailActivity(this, name, price, detail);
Log.i(TAG, "launchParam exists, redirect to DetailActivity");
protected void onResume() {
super.onResume();
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return super.onOptionsItemSelected(item);
DetailActivity.java
比较简单,显示传入的参数即可:-D
public class DetailActivity extends AppCompatActivity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
getSupportActionBar().setTitle("DetailActivity");
String name = getIntent().getStringExtra("name");
String price = getIntent().getStringExtra("price");
String detail = getIntent().getStringExtra("detail");
((TextView)findViewById(R.id.name)).setText(name);
((TextView)findViewById(R.id.price)).setText(price);
((TextView)findViewById(R.id.detail)).setText(detail);
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
Android各种资源收集
· 442人关注
技术资料相关,主要以Android为主,自己收藏的专题!请勿投稿,不一定会收~但欢迎订阅!
· 413人关注
来自移动开发狂热者对移动开发的经验总结、分享
· 76人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:看腻了安卓自带手机界面?15款最佳启动器推荐
[摘要]说到灵活性与可定制性,三大系统(iOS、安卓和WP)中要数安卓最强。
腾讯数码讯(编译:闻尚雨)说到灵活性与可定制性,三大系统(iOS、安卓和WP)中要数安卓最强。也正是因为安卓这方面的基础构架,几乎任何制造商都可以在设备上采用自开发的用户界面,例如大家熟悉的来自的Sense界面还有来自的TouchWiz界面,它们都是基于安卓系统的定制界面。当然,不是所有的人都爱这些类型的UI,好在用户可以方便地将其修改与替换,直到找到自己中意的款式。想要替换UI,最简单的方法便是安装一个第三方的启动器,如此一来,不仅仅可以让用户看到焕然一新的“外表”,还可以带来许多有趣的自定义功能和选项,而这些在系统自带的UI里几乎找不到。更好的是大部分第三方启动器资源占用量小,且运行更顺畅,这很棒不是吗?在给大家介绍这15款启动器之前,我们先告诉大家如何改变设备的启动器,实际上过程非常简单。首先安装启动器不必多说,然后要将其设置成为默认启动器。在用户安装完成点击Home键后,安卓系统会自动询问是否将新安装的启动器设为默认。大部分启动器还会指导用户完成设置过程,另外,如果用户的设备是安卓4.4 KitKat或者更高版本,还可以通过设置菜单选择默认启动器,只需找到默认应用程序子菜单即可。在这里,phonearena为我们挑选了15款非常不错且较流行的安卓启动器,大家可以参考一下。GO Launcher EXGO Launcher有大量的自定义选项,它支持定制图标包、各式各样的主题、炫酷的图片过渡效果等,用户还可以通过手势打开应用。然而,Go Launcher并不是系统负荷最轻的启动器,所以配置低端的手机不建议使用,且免费版的GO Launcher是带广告的,如果想去广告,需要购买GO Launcher Prime。Nova启动器Nova启动器应该算是系统负载最轻、功能最全的类AOSP启动器之一,它被许多人评价为综合能力最强的安卓启动器。最近,Nova升级至3.0版本,和先前相比增加了更多的功能,也让其在众多启动器的竞争中独树一帜。它支持谷歌的语音搜索热词“OK, ”,允许用户大范围改变主屏幕的布局,包括图像过渡动画、图标快捷方式等。Nova启动器的付费版本Nova Launcher Prime拥有更多的定制功能。Apex启动器虽然不如Nova功能丰富,Apex启动器和Nova在定制性上很相似。它允许用户拥有高达9块主屏幕、多主选单标签,可为任何应用或者文件夹定制图标和命名,还可以定义主屏幕手势等。总的来说,Apex是一款各项功能比较均衡的启动器,如果你像找到一款运行顺畅、功能稳定的启动器,Apex不会让你失望。其付费版本名为Apex Launcher Pro,会给用户带来更多的福利。Smart启动器 2这款启动器非常独特,它最标志性的功能叫做“气泡”,大家可以从上面的界面图看出,Smart主界面上的图标就像一个拨号盘,每个app像气泡一样围绕排在一起。右滑后可以看到应用主选单,里面的应用按照不同的标签进行分类,类别在最左边一栏,有媒体、网络、应用、游戏等。该启动器唯一的缺点就是不支持插件。Mi启动器众所周知,小米的手机有一套自己的ROM和米UI,它标志性的功能就是没有应用程序主选单,这使得它看起来像是安卓和iOS的混合体。故Mi启动器的原理也是如此,它抛弃了主选单,将用户的应用“抛洒”在各个主屏幕。Mi启动器易于使用,不过定制性功能很有限,对于一些安卓粉丝来说可能不能接受。dodol启动器dodol启动器最强大的地方在于它含有大量的主题,除此之外,它还颇具可定制性。当然,dodol启动器的可定制范围不及Nova,不过运行流畅、性能很好,大部分安卓用户都可以接受。最好的一点是,该应用完全免费。Action启动器Action启动器运行非常流畅,几乎没有卡顿现象。不过和Smart启动器类似,它没有常规的应用程序主选单,所以滑动屏幕可以翻看所有的应用。向左滑动可以进入所谓的“快速页”,可以进入谷歌搜索和一些你最近使用过的应用列表。可惜的是,大部分的定制功能只在付费版Action启动器中才有。Solo启动器可以说,Solo启动器是功能最丰富的安卓启动器之一,它拥有未读信息框、手势组合以及各种可用主题。且Solo也算是性能之王,运行极其流畅。另外,它也是完全免费的,喜欢的朋友不要错过。Buzz启动器该启动器最优秀的功能莫过于可以允许用户下载完整的主屏幕设置,在这里不要和主题搞混淆,因为Buzz不仅可以有自己的图标包、壁纸,还有自己的界面布局,因此,每个主屏幕设置都有完全不同的外观和感觉,用户可以创造自己的个性化设置并分享它们。所以对于那些想轻松换掉整个界面的安卓用户来说,Buzz启动器是完美选择。EverythingMe启动器EverythingMe是一款能为用户“考虑”的启动器,它可以“预测”用户在任何特定环境下需要使用的应用。根据每天的时间,EverythingMe会呈现用户此刻最可能用到的app。例如,在早晨,它会弹出与新闻有关的应用;随后在开始工作时弹出与效率相关的应用;晚上在检测到用户在外面闲逛时甚至会推荐餐厅。可以说,用户使用得越多,EverythingMe也会变得越亲密。虽然它的定制化选项有限,但是足以替代设备自带的UI。Launcher 8喜欢Window Phone 8的风格吗?如果你是安卓手机用户,又想感受WP 8,Launcher 8会是不错的选择。老实说,它有一些生硬,不过也算是直观地让用户体验了WP。拥有WP特有的Live Tile,往左滑动即可显示所有的应用,还有一个类WP的状态栏,总之整个感觉和WP很像。Launcher 8运行顺畅,安卓用户可以体验一下。Themer Beta正如这个启动器的名字一般,Themer就是一个以主题为中心的应用。它拥有极其丰富的主题库,不仅可以改变界面的外观,还可以有自己的布局,这意味着没有主题是完全一样的。目前,该启动器还是测试版本,所以使用时可能会遇到一些问题,不过未来应该会有升级的版本。KK启动器KK启动时基于安卓KitKat自带的启动器,所以毋庸置疑它拥有最快最顺畅的性能。其界面几乎和自带的启动器一模一样,不过KK的定制性更加丰富。它支持“Ok,Google”热词、主题、图标等,还有一个边栏,可以放一些用户常用的应用,很是方便。另外,KK包极小,不会占据过多的空间,安卓4.0及以上版本用户可使用。Next Launcher 3D Shell该启动器给用户提供一个酷炫的3D界面,无论是主选单或是主屏幕都是3D的,可以自定义图案过渡方式和动画。它还支持许多3D主题,有趣的是,Next启动器还允许用户融合来自不同主题的元素,最后做成一个大杂烩。但是,需要注意的是,这种酷炫的效果很容易“吃掉”你的电量,还是小心为好。且该启动器的价格可能会吓跑一堆的用户,需要16.99美元(约合人民币106元)。Atom启动器Atom也是一款能提供超多定制化功能的启动器,更有趣的是它包含了主题制作器,如此一来,用户可以轻松制作并分享主题,还有自定义的Atom Bar。除此之外,Atom真正的强大之处在于超强的性能,运行极其流畅。来源:查报价,看新品,尽在腾讯数码官方微信 扫描左侧二维码即可添加腾讯数码官方微信您也可以在微信上搜索“腾讯数码”或“qqdigi”,获取更多数码资讯。
[责任编辑:ziwenzhao]
还能输入140字
Copyright & 1998 - 2016 Tencent. All Rights Reserved<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&

我要回帖

更多关于 安卓服务自启动 的文章

 

随机推荐