android中启动service的activity销毁了,这时怎么关闭service?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android中启动service的activity销毁了,这时怎么关闭service?相关的知识,希望对你有一定的参考价值。

droid中怎么启动关闭Service及功能解释 .
7.16,杭州。阿里百川无线开放大会。阿里与开发者一起见证移动的力量
什么是Service?
解惑:
1、 Service不是分离开的进程,除非其他特殊情况,它不会运行在自己的进程,而是作为启动运行它的进程的一部分。
2、 Service不是线程,这意味着它将在主线程里劳作。
启动service有两种方法:
1、 Context.startService()
调用者与服务之间没有关联,即使调用者退出,服务仍可运行
2、 Context.bindService()
调用者与服务绑定在一起,调用者一旦退出,服务也就终止
Service的生命周期
如果使用startService()启动service,系统将通过传入的Intent在底层搜索相关符合Intent里面信息的service。如果服务没有启动则先运行onCreate,然后运行onStartCommand (可在里面处理启动时传过来的Intent和其他参数),直到明显调用stopService或者stopSelf才将停止Service。无论运行startService多少次,只要调用一次stopService或者stopSelf,Service都会停止。使用stopSelf(int)方法可以保证在处理好intent后再停止。
控制service运行的主要方式有两种,主要是根据onStartCommand方法返回的数值。方法:
1、START_STICKY
2、START_NOT_STICKY or START_REDELIVER_INTENT
这里主要解释这三个变量的意义:
1、 START_STICKY
在运行onStartCommand后service进程被kill后,那将保留在开始状态,但是不保留那些传入的intent。不久后service就会再次尝试重新创建,因为保留在开始状态,在创建 service后将保证调用onstartCommand。如果没有传递任何开始命令给service,那将获取到null的intent
2、 START_NOT_STICKY
在运行onStartCommand后service进程被kill后,并且没有新的intent传递给它。Service将移出开始状态,并且直到新的明显的方法(startService)调用才重新创建。因为如果没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。
3、 START_REDELIVER_INTENT
在运行onStartCommand后service进程被kill后,系统将会再次启动service,并传入最后一个intent给onstartCommand。直到调用stopSelf(int)才停止传递intent。如果在被kill后还有未处理好的intent,那被kill后服务还是会自动启动。因此onstartCommand不会接收到任何null的intent。
客户端也可以使用bindService来保持跟service持久关联。谨记:如果使用这种方法,那么将不会调用onstartCommand(跟startService不一样,下面例子注释也有解析,大家可试试)。客户端将会在onBind回调中接收到IBinder接口返回的对象。通常IBinder作为一个复杂的接口通常是返回aidl数据。
Service也可以混合start和bind一起使用。
权限
要运行service,首先必须在androidManifest.xml里申明<service>标签。
Service能够保护个人的IPC调用,所以在执行实现该调用时前先使用checkCallingPermission(String) 方法检查是否有这个权限。

进程生命周期
当service运行在低内存的环境时,将会kill掉一下存在的进程。因此进程的优先级将会很重要:
1、 如果service当前正在执行onCreate、onStartCommand、onDestroy方法,主进程将会成为前台进程来保证代码可以执行完成避免被kill
2、 如果service已经启动了,那么主进程将会比其他可见的进程的重要性低,但比其他看不见的进程高。因为只有少部分进程始终是用户可见的,因此除非在极度低内存的时候,不然 service是不会被kill的。
3、 如果有客户端关联到service,那么service永远比客户端重要。也就是说客户端可见,那么service也可见(我理解这里的可见并不是可以看到,而是重要性,因为可见往往就表示重要性高)。
4、 Service可以使用startForeground API将service放到前台状态。这样在低内存时被kill的几率更低,但是文档后面又写了,如果在极度极度低内存的压力下,该service理论上还是会被kill掉。但这个情况基本不用考虑。
当然如果service怎么保持还是被kill了,那你可以通过重写onStartCommand返回变量来设置它的启动方式。比如:START_STICKY、START_REDELIVER_INTENT等等,前面已经讨论了它们的作用,这里就不再累赘了
另外:
service 的onCreate和onStartCommand 是运行在主线程的,所以如果里面有处理耗时间的任务。两种处理:
1、 请将它们都挪到新的线程里。
2、 用系统提供的IntentService,它继承了Service,它处理数据是用自身新开的线程。

启动关闭service实例

===================main文件========================
package com.services.coms;
import java.io.FileFilter;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.text.html;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainService extends Activity
private TextView textviewService;
private Button buttonStart ,buttonStop;
public static final int CMD_STOP_SERVICE = 0;
DataReceiver dateReceiver;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textviewService=(TextView)findViewById(R.id.textservice);
buttonStart=(Button)findViewById(R.id.buttonstart);
buttonStop=(Button)findViewById(R.id.buttonstop);
buttonStart.setOnClickListener(buttonClick);
buttonStop.setOnClickListener(buttonClick);


private View.OnClickListener buttonClick =new View.OnClickListener()
@Override
public void onClick(View v)
if(v==buttonStart)
Intent intentService=new Intent(MainService.this,MyService.class);
startService(intentService);
Log.i("onStartCommand", "OnClickListener=");
else if(v==buttonStop)
Intent intent=new Intent();
intent.setAction("AAAAA");
intent.putExtra("cmd",CMD_STOP_SERVICE);
sendBroadcast(intent);



;
private class DataReceiver extends BroadcastReceiver

@Override
public void onReceive(Context context, Intent intent)
Log.i("onStartCommand", "接受要更新的广播数据="+intent.getStringExtra("data"));
String Date=intent.getStringExtra("data");
textviewService.setText(Html.fromHtml("<font color=\'#0066CC\'><u>"+"Service的数据为:"+Date+"</font>"));


@Override
protected void onStart()
dateReceiver=new DataReceiver();
IntentFilter intentfilter=new IntentFilter();// 创建IntentFilter对象
intentfilter.addAction("AAAAA");
registerReceiver(dateReceiver, intentfilter);// 注册Broadcast Receiver
super.onStart();

@Override
protected void onStop()
unregisterReceiver(dateReceiver);// 取消注册Broadcast Receiver
super.onStop();



===================service文件===================
package com.services.coms;
import java.util.UUID;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service
CommandReceiver cmdReceiver;
boolean flag;

@Override
public void onConfigurationChanged(Configuration newConfig)
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);

@Override
public void onCreate()
cmdReceiver=new CommandReceiver();
flag=true;
Log.i("onStartCommand", "onCreate=");
super.onCreate();

@Override
public void onDestroy()
this.unregisterReceiver(cmdReceiver);// 取消BroadcastReceiver
super.onDestroy();

@Override
public void onLowMemory()
// TODO Auto-generated method stub
super.onLowMemory();

@Override
public void onRebind(Intent intent)
// TODO Auto-generated method stub
super.onRebind(intent);

@Override
public void onStart(Intent intent, int startId)
// TODO Auto-generated method stub
super.onStart(intent, startId);

@Override
public int onStartCommand(Intent intent, int flags, int startId)
Log.i("onStartCommand", "onStartCommand=");
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("AAAAA");
registerReceiver(cmdReceiver, intentFilter);
doJob();// 调用方法启动线程

return super.onStartCommand(intent, flags, startId);

@Override
public boolean onUnbind(Intent intent)
// TODO Auto-generated method stub
return super.onUnbind(intent);

@Override
public IBinder onBind(Intent intent)
// TODO Auto-generated method stub
return null;

//接受广播
private class CommandReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
int cmd=intent.getIntExtra("cmd", -1);
if(cmd==MainService.CMD_STOP_SERVICE)//如果等于0
flag=false;//停止线程
stopSelf();//停止服务




public void doJob()
new Thread()
@Override
public void run()
while(flag)//如果==true执行发送广播
try
Thread.sleep(1000);//休眠1秒
catch (InterruptedException e)
e.printStackTrace();

Log.i("onStartCommand", "run=");
Intent intent=new Intent();
intent.setAction("AAAAA");
intent.putExtra("data",UUID.randomUUID()+"");
sendBroadcast(intent);//发送广播名称aaaaa 参数名字data



.start();



==================layout文件=====================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_
>
<TextView
android:layout_
android:layout_
android:text="@string/hello"
/>
<TextView
android:layout_
android:layout_
android:id="@+id/textservice"
></TextView>
<Button
android:id="@+id/buttonstart"
android:layout_
android:layout_
android:text="启动服务"
android:gravity="center"
></Button>
<Button
android:id="@+id/buttonstop"
android:layout_
android:layout_
android:text="停止服务"
android:gravity="center"
></Button>
</LinearLayout>

原文链接:http://blog.csdn.net/centralperk/article/details/7764379
参考技术A 可以在销毁Activity时 通知 service 销毁。
在Activity :
onDestory()
//
发送 广播 通知 serivice 关闭。
sendBroadCast();
参考技术B http://www.oschina.net/question/565065_66801
看完这个帖子你就明白了

Android中Activity的隐式启动

ps:本文系转载文章,阅读原文可获取源码,文章末尾有原文链接

在Android开发中,Activity的启动方式有2种,有两种是显示启动和隐式启动,显示启动是要指定被组件对象的信息(包名和类名);隐式启动就是在AndroidManifest.xml文件中的Activity IntentFilter;如果一个Activity的文章启动显示显示启动,又隐式启动,那么就以启动的方式启动;本该是讲信息IntentFilter,IntentFilter需要过滤,它需要过滤的信息有action、category、data,在调用的过程中,如果Intent不能匹配目标Activity的IntentFilter,那么启动Activity就会失败。

一个Activity的IntentFilter有多个,一个Intent任意匹配一个IntentFilter就可以成功启动Activity;只有一个Intent中匹配任意一个IntentFilter的action(至少一个)、category(至少一个)、data(至少一个)同时匹配成功启动Activity。

下面我放一下我自己写的简单IntentFilter的配置信息:

<activity android:name=".SecondActivity">

        <intent-filter>
            <action android:name="android.intent.action.VIEW" />

            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />

            <data
                android:host="homePage"
                android:scheme="recyclemobilephones" />
            <data android:mimeType="video/*"/>
        </intent-filter>
    </activity>

1、动作的匹配原则

action的值是字符串,系统预定义了一些动作,我们也可以在自己的APP中自定义动作,一个IntentFilter可以有多个动作,Intent中动作值和IntentFilter任意一个动作值一样,包括必须字母大小写,只能算它们之间的动作匹配成功。

2、类别的匹配原则

category的是字符串类型,系统里值定义了几个类别,我们也可以自定义几个类别;一个Intent可以有多个类别,也可以没有,如果Intent有多个类别,那么Intent至少有一个类别和IntentFilter的类别相同,才能匹配成功;如果Intent里一个也没有类别,那么IntentFilter里必须配置

<category android:name="android.intent.category.DEFAULT" />
,不然的话匹配失败,因为在Activity的startActivity方法的实现

里默认给 category 添加 android.intent.category.DEFAULT 的。

3、数据的匹配原则

数据是由几个不同的属性组成的,并且它们的属性的值都是字符串类型的,如果 IntentFilter 中定义了数据,那么 Intent 中要添加切换相匹配的数据;下面是状态数据的属性属性哪些:

           <data android:scheme="string"
                android:host="string"
                android:port="string"
                android:path="string"
                android:pathPattern="string"
                android:pathPrefix="string"
                android:mimeType="string"
                >
            </data>

我们来分析一下数据,总体上来说数据是由mimeType和Uri组成,mimeType是指图像/jpeg、video/*等各种媒体格式,Uri的数据格式比较复杂,还有Uri的组成:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

方案:模式,是http等,假方案一般没有在Uri中,那么Uri的其他参数是束缚的。

主持人:主机名,比如 www.xxx.com,xxx 一般是公司的名字,如果主机没有定义,那么就和方案一样,Uri 的其他参数也是优秀的。

端口:端口号,比如8080。

path:完整的路径信息。

pathPattern:完整的路径信息,它里面还可以包含通配符 * 。

pathPrefix:路径的定位信息。

需要注意的是,如果 Intent 要使用完整的数据,也就是 Uri 和 mimeType,可以调用 Intent 的 setDataAndType 方法,不能把 Intent 的 setType 和 setData 方法一起调用,它们两种方法都是把对方的值彼此置入空的,要两个方法 Uri 和 mime Type 一个必须是空的,下面看看这两个的源码。

Intent 的 setType 方法:

public @NonNull Intent setType(@Nullable String type) {

    mData = null;
    mType = type;
    return this;

}

Intent 的 setData 方法:

public @NonNull Intent setData(@Nullable Uri data) {

    mData = data;
    mType = null;
    return this;

}

好,下面我们列举一个用隐式​​启动活动的例子,每个例子的IntentFilter都必须添加一行代码,如下所示:

<category android:name="android.intent.category.DEFAULT" />

(1)利用系统预定义的action启动Activity:

执行startActivity方法的Intent的代码如下

var intent: Intent = Intent(Intent.ACTION_VIEW);
intent.putExtra("key","这是利用系统预定义的action启动Activity")
startActivity(intent)

AndroidManifest.xml 文件中 Activity 的 IntentFilter 配置如下

<intent-filter>

     <action android:name="android.intent.action.VIEW" />
      <category android:name="android.intent.category.DEFAULT" />

</intent-filter>

(2)利用自定义的action启动Activity:

执行startActivity方法的Intent的代码如下

var intent: Intent = Intent("xiaoer");
intent.putExtra("key","这是利用自定义的action启动Activity")
startActivity(intent)

AndroidManifest.xml 文件中 Activity 的 IntentFilter 配置如下

<intent-filter>

      <action android:name="xiaoer" />
       <category android:name="android.intent.category.DEFAULT" />

</intent-filter>

(3)利用系统预定义的category启动Activity,action用android.intent.action.VIEW:

执行startActivity方法的Intent的代码如下

var intent: Intent = Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_APP_BROWSER)
intent.putExtra("key","这是利用系统预定义的category启动Activity")
startActivity(intent)

AndroidManifest.xml 文件中 Activity 的 IntentFilter 配置如下

<intent-filter>

   <action android:name="android.intent.action.VIEW" />
   <category android:name="android.intent.category.APP_BROWSER"/>
   <category android:name="android.intent.category.DEFAULT" />

</intent-filter>

(4)利用自定义的category启动Activity,action用android.intent.action.VIEW:

执行startActivity方法的Intent的代码如下

var intent: Intent = Intent(Intent.ACTION_VIEW);
intent.addCategory("xiaoer_study")
intent.putExtra("key","这是利用自定义的category启动Activity")
startActivity(intent)

AndroidManifest.xml 文件中 Activity 的 IntentFilter 配置如下

<intent-filter>

    <action android:name="android.intent.action.VIEW" />
    <category android:name="xiaoer_study" />
    <category android:name="android.intent.category.DEFAULT" />

</intent-filter>

(5)利用只包含uri的data启动Activity,action用android.intent.action.VIEW:

执行startActivity方法的Intent的代码如下

var intent: Intent = Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("recyclemobilephones://homePage"))
intent.putExtra("key","这是利用只含有uri的data启动Activity")
startActivity(intent)

AndroidManifest.xml 文件中 Activity 的 IntentFilter 配置如下

<intent-filter>

   <action android:name="android.intent.action.VIEW" />
   <category android:name="android.intent.category.DEFAULT" />
   <data
        android:host="homePage"
        android:scheme="recyclemobilephones" />

</intent-filter>

(6)利用带有uri和mimeType的data启动Activity,action用android.intent.action.VIEW:

执行startActivity方法的Intent的代码如下

var intent: Intent = Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("recyclemobilephones://homePage_2"),"text/plain")
intent.putExtra("key","这是利用含有uri和mimeType的data启动Activity")
startActivity(intent)

AndroidManifest.xml 文件中 Activity 的 IntentFilter 配置如下

<intent-filter>

   <action android:name="android.intent.action.VIEW" />
   <category android:name="android.intent.category.DEFAULT" />
   <data
        android:host="homePage_2"
        android:mimeType="text/plain"
        android:scheme="recyclemobilephones" />

</intent-filter>

APP运行后的界面如下所示:

图片

点击任意一个请按钮,如果弹出选择框,点击“IntentFilter”APP

图片

以上是关于android中启动service的activity销毁了,这时怎么关闭service?的主要内容,如果未能解决你的问题,请参考以下文章

Android 9适配经验总结

Android中Activity的隐式启动

Android显式意图和隐式意图

Android 之 Service(一)启动,绑定服务

Android中Service通信——启动Service并传递数据

如何在Android中取得当前进程名