m6 activity service

本文详细解析Android中服务(Service)与活动(Activity)的概念、生命周期、启动方式及内部调用过程。服务作为后台执行组件,可独立于用户界面运行,支持长时间任务处理。活动则是用户交互的主要界面,管理其生命周期对于应用流畅体验至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#什么是服务?  

  Service是一个应用程序组件,它能够在后台执行一些耗时较长的操作,并且不提供用户界面。服务能被其它应用程序的组件启动,即使用户切换到另外的应用时还能保持后台运行。此外,应用程序组件还能与服务绑定,并与服务进行交互,甚至能进行进程间通信(IPC)。 比如,服务可以处理网络传输、音乐播放、执行文件I/O、或者与content provider进行交互,所有这些都是后台进行的。


#Service 与 Thread 的区别


  服务仅仅是一个组件,即使用户不再与你的应用程序发生交互,它仍然能在后台运行。因此,应该只在需要时才创建一个服务。

  如果你需要在主线程之外执行一些工作,但仅当用户与你的应用程序交互时才会用到,那你应该创建一个新的线程而不是创建服务。 比如,如果你需要播放一些音乐,但只是当你的activity在运行时才需要播放,你可以在onCreate()中创建一个线程,在onStart()中开始运行,然后在onStop()中终止运行。还可以考虑使用AsyncTask或HandlerThread来取代传统的Thread类。

  **由于无法在不同的 Activity 中对同一 Thread 进行控制**,这个时候就要考虑用服务实现。如果你使用了服务,它默认就运行于应用程序的主线程中。因此,如果服务执行密集计算或者阻塞操作,你仍然应该在服务中创建一个新的线程来完成(避免ANR)。

#服务的分类

##按运行分类

  

 - 前台服务

  前台服务是指那些经常会被用户关注的服务,因此内存过低时它不会成为被杀的对象。 前台服务必须提供一个状态栏通知,并会置于“正在进行的”(“Ongoing”)组之下。这意味着只有在服务被终止或从前台移除之后,此通知才能被解除。
  例如,用服务来播放音乐的播放器就应该运行在前台,因为用户会清楚地知晓它的运行情况。 状态栏通知可能会标明当前播放的歌曲,并允许用户启动一个activity来与播放器进行交互。

  要把你的服务请求为前台运行,可以调用startForeground()方法。此方法有两个参数:唯一标识通知的整数值、状态栏通知Notification对象。例如:

  

```
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),System.currentTimeMillis());

Intent notificationIntent = new Intent(this,ExampleActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
        
startForeground(ONGOING_NOTIFICATION, notification);
```

  要从前台移除服务,请调用stopForeground()方法,这个方法接受个布尔参数,表示是否同时移除状态栏通知。此方法不会终止服务。不过,如果服务在前台运行时被你终止了,那么通知也会同时被移除。

 - 后台服务

##按使用分类  

 - 本地服务

  用于应用程序内部,实现一些耗时任务,并不占用应用程序比如Activity所属线程,而是单开线程后台执行。
  调用Context.startService()启动,调用Context.stopService()结束。在内部可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。

 - 远程服务

  用于Android系统内部的应用程序之间,可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。可以定义接口并把接口暴露出来,以便其他应用进行操作。客户端建立到服务对象的连接,并通过那个连接来调用服务。调用Context.bindService()方法建立连接,并启动,以调用 Context.unbindService()关闭连接。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。

#Service生命周期

  ![这里写图片描述](https://img-blog.youkuaiyun.com/20160503165018575)

Service生命周期方法:
```
public class ExampleService extends Service {
    int mStartMode;       // 标识服务被杀死后的处理方式
    IBinder mBinder;      // 用于客户端绑定的接口
    boolean mAllowRebind; // 标识是否使用onRebind

    @Override
    public void onCreate() {
        // 服务正被创建
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 服务正在启动,由startService()调用引发
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // 客户端用bindService()绑定服务
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // 所有的客户端都用unbindService()解除了绑定
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // 某客户端正用bindService()绑定到服务,
        // 而onUnbind()已经被调用过了
    }
    @Override
    public void onDestroy() {
        // 服务用不上了,将被销毁
    }
}
```

> 请注意onStartCommand()方法必须返回一个整数。这个整数是描述系统在杀死服务之后应该如何继续运行。onStartCommand()的返回值必须是以下常量之一:

>START_NOT_STICKY  
如果系统在onStartCommand()返回后杀死了服务,则不会重建服务了,除非还存在未发送的intent。 当服务不再是必需的,并且应用程序能够简单地重启那些未完成的工作时,这是避免服务运行的最安全的选项。 
 
>START_STICKY 
如果系统在onStartCommand()返回后杀死了服务,则将重建服务并调用onStartCommand(),但不会再次送入上一个intent, 而是用null intent来调用onStartCommand() 。除非还有启动服务的intent未发送完,那么这些剩下的intent会继续发送。 这适用于媒体播放器(或类似服务),它们不执行命令,但需要一直运行并随时待命。 

>START_REDELIVER_INTENT 
如果系统在onStartCommand()返回后杀死了服务,则将重建服务并用上一个已送过的intent调用onStartCommand()。任何未发送完的intent也都会依次送入。这适用于那些需要立即恢复工作的活跃服务,比如下载文件。

  服务的生命周期与activity的非常类似。不过,更重要的是你需密切关注服务的创建和销毁环节,因为后台运行的服务是不会引起用户注意的。

  服务的生命周期——从创建到销毁——可以有两种路径:

 - 一个started服务

  这类服务由其它组件调用startService()来创建。然后保持运行,且必须通过调用stopSelf()自行终止。其它组件也可通过调用stopService() 终止这类服务。服务终止后,系统会把它销毁。

  如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。

  

 -  一个bound服务
 
  服务由其它组件(客户端)调用bindService()来创建。然后客户端通过一个IBinder接口与服务进行通信。客户端可以通过调用unbindService()来关闭联接。多个客户端可以绑定到同一个服务上,当所有的客户端都解除绑定后,系统会销毁服务。(服务不需要自行终止。)

  如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。

![这里写图片描述](https://img-blog.youkuaiyun.com/20160503165622881) 

  这两条路径并不是完全隔离的。也就是说,你可以绑定到一个已经用startService()启动的服务上。例如,一个后台音乐服务可以通过调用startService()来启动,传入一个指明所需播放音乐的 Intent。 之后,用户也许需要用播放器进行一些控制,或者需要查看当前歌曲的信息,这时一个activity可以通过调用bindService()与此服务绑定。在类似这种情况下,stopService()或stopSelf()不会真的终止服务,除非所有的客户端都解除了绑定。

>   当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了)。

#在manifest中声明服务

  无论是什么类型的服务都必须在manifest中申明,格式如下:

```
<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>
```

Service 元素的属性有:

> android:name  -------------  服务类名

>android:label  --------------  服务的名字,如果此项不设置,那么默认显示的服务名则为类名

>android:icon  --------------  服务的图标

>android:permission  -------  申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务

>android:process  ----------  表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字

>android:enabled  ----------  如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false

>android:exported  ---------  表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false 

  android:name是唯一必需的属性——它定义了服务的类名。与activity一样,服务可以定义intent过滤器,使得其它组件能用隐式intent来调用服务。如果你想让服务只能内部使用(其它应用程序无法调用),那么就不必(也不应该)提供任何intent过滤器。
  此外,如果包含了android:exported属性并且设置为"false", 就可以确保该服务是你应用程序的私有服务。即使服务提供了intent过滤器,本属性依然生效。 

#startService 启动服务

  从activity或其它应用程序组件中可以启动一个服务,调用startService()并传入一个Intent(指定所需启动的服务)即可。

```
	Intent intent = new Intent(this, MyService.class);
	startService(intent);
```

服务类:

```
public class MyService extends Service {

	  /**
     * onBind 是 Service 的虚方法,因此我们不得不实现它。
     * 返回 null,表示客服端不能建立到此服务的连接。
     */
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
    
	@Override
    public void onCreate() {
        super.onCreate();
    }
     
    @Override
 public int onStartCommand(Intent intent, int flags, int startId)     {  	
    //接受传递过来的intent的数据 
     return START_STICKY; 
    };
     
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
	
}
```

  一个started服务必须自行管理生命周期。也就是说,系统不会终止或销毁这类服务,除非必须恢复系统内存并且服务返回后一直维持运行。 因此,服务必须通过调用stopSelf()自行终止,或者其它组件可通过调用stopService()来终止它。

#bindService 启动服务  

  当应用程序中的activity或其它组件需要与服务进行交互,或者应用程序的某些功能需要暴露给其它应用程序时,你应该创建一个bound服务,并通过进程间通信(IPC)来完成。

方法如下:

```
 Intent intent=new Intent(this,BindService.class); 
 bindService(intent, ServiceConnection conn, int flags)  

```

> 注意bindService是Context中的方法,当没有Context时传入即可。

在进行服务绑定的时,其flags有:

 - Context.BIND_AUTO_CREATE    
 
  表示收到绑定请求的时候,如果服务尚未创建,则即刻创建,在系统内存不足需要先摧毁优先级组件来释放内存,且只有驻留该服务的进程成为被摧毁对象时,服务才被摧毁 

 - Context.BIND_DEBUG_UNBIND     
 
  通常用于调试场景中判断绑定的服务是否正确,但容易引起内存泄漏,因此非调试目的的时候不建议使用

 - Context.BIND_NOT_FOREGROUND     
 
  表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行。

服务类:

```
public class BindService extends Service {

	 // 实例化MyBinder得到mybinder对象;
	private final MyBinder binder = new MyBinder();
	
	  /**
     * 返回Binder对象。
     */
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return binder;
	}
    
     /**
      * 新建内部类MyBinder,继承自Binder(Binder实现IBinder接口),
      * MyBinder提供方法返回BindService实例。
      */
  public class MyBinder extends Binder{
        
        public BindService getService(){
            return BindService.this;
        }
    }
     

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

启动服务的activity代码:

```
public class MainActivity extends Activity {

	/** 是否绑定 */  
	boolean mIsBound = false; 
	BindService mBoundService;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		doBindService();
	}
	/**
	 * 实例化ServiceConnection接口的实现类,用于监听服务的状态
	 */
	private ServiceConnection conn = new ServiceConnection() {  
		  
	    @Override  
	    public void onServiceConnected(ComponentName name, IBinder service) {  
	        BindService mBoundService = ((BindService.MyBinder) service).getService();  
	        
	    }  
	  
	    @Override  
	    public void onServiceDisconnected(ComponentName name) {  
	        mBoundService = null;  
	     
	    }  
	}; 
	
	/** 绑定服务 */  
	public void doBindService() {  
	    bindService(new Intent(MainActivity.this, BindService.class), conn,Context.BIND_AUTO_CREATE);  
	    mIsBound = true;  
	}  
	
	/** 解除绑定服务 */  
	public void doUnbindService() {  
	    if (mIsBound) {  
	        // Detach our existing connection.  
	        unbindService(conn);  
	        mIsBound = false;  
	    }  
	} 
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		
		doUnbindService();
	}
}
```

> 注意在AndroidMainfest.xml中对Service进行显式声明


判断Service是否正在运行:

```
private boolean isServiceRunning() {
    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    
  {
        if ("com.example.demo.BindService".equals(service.service.getClassName()))   {
            return true;
        }
    }
    return false;
}
```

 

#Activity是什么?

  我们都知道android中有四大组件(Activity 活动,Service 服务,Content Provider 内容提供者,BroadcastReceiver 广播接收器),Activity是我们用的最多也是最基本的组件,因为应用的所有操作都与用户相关,Activity 提供窗口来和用户进行交互。
  官方文档这么说:
  

> An activity is a single, focused thing that the user can do. Almost all activities interact with the user, so the Activity class takes care of creating a window for you in which you can place your UI with setContentView(View). 
> 
> 
> 大概的意思(原谅我):

>  activity是独立平等的,用来处理用户操作。几乎所有的activity都是用来和用户交互的,所以activity类会创建了一个窗口,开发者可以通过setContentView(View)的接口把UI放到给窗口上。

  Android中的activity全都归属于task管理 。task 是多个 activity 的集合,这些 activity 按照启动顺序排队存入一个栈(即“back stack”)。android默认会为每个App维持一个task来存放该app的所有activity,task的默认name为该app的packagename。

  当然我们也可以在AndroidMainfest.xml中申明activity的taskAffinity属性来自定义task,但不建议使用,如果其他app也申明相同的task,它就有可能启动到你的activity,带来各种安全问题(比如拿到你的Intent)。

#Activity的内部调用过程

  上面已经说了,系统通过堆栈来管理activity,当一个新的activity开始时,它被放置在堆栈的顶部和成为运行活动,以前的activity始终保持低于它在堆栈,而不会再次到达前台,直到新的活动退出。

  还是上这张官网的activity_lifecycle图:
  ![这里写图片描述](https://img-blog.youkuaiyun.com/20160425171711054) 

 

 - 首先打开一个新的activity实例的时候,系统会依次调用

> onCreate()  -> onStart() -> onResume() 然后开始running

   running的时候被覆盖了(从它打开了新的activity或是被锁屏,但是它**依然在前台**运行, lost focus but is still visible),系统调用onPause();

 
> 该方法执行activity暂停,通常用于提交未保存的更改到持久化数据,停止动画和其他的东西。但这个activity还是完全活着(它保持所有的状态和成员信息,并保持连接到**窗口管理器**)

接下来它有三条出路
①用户返回到该activity就调用onResume()方法重新running 

②用户回到桌面或是打开其他activity,就会调用onStop()进入停止状态(保留所有的状态和成员信息,**对用户不可见**)

③系统内存不足,拥有更高限权的应用需要内存,那么该activity的进程就可能会被系统回收。(回收onRause()和onStop()状态的activity进程)要想重新打开就必须重新创建一遍。

如果用户返回到onStop()状态的activity(又显示在前台了),系统会调用

> onRestart() ->  onStart() -> onResume() 然后重新running

在activity结束(调用finish ())或是被系统杀死之前会调用onDestroy()方法释放所有占用的资源。


> activity生命周期中三个嵌套的循环

 

 - activity的完整生存期会在 onCreate() 调用和 onDestroy() 调用之间发生。 
 
 - activity的可见生存期会在 onStart() 调用和 onStop() 调用之间发生。系统会在activity的整个生存期内多次调用 onStart() 和onStop(), 因为activity可能会在显示和隐藏之间不断地来回切换。 
 
 - activity的前后台切换会在 onResume() 调用和 onPause() 之间发生。
 因为这个状态可能会经常发生转换,为了避免切换迟缓引起的用户等待,这两个方法中的代码应该相当地轻量化。

##  activity被回收的状态和信息保存和恢复过程

```
public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		if(savedInstanceState!=null){ //判断是否有以前的保存状态信息
			 savedInstanceState.get("Key"); 
			 }
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
   @Override
protected void onSaveInstanceState(Bundle outState) {
	// TODO Auto-generated method stub
	 //可能被回收内存前保存状态和信息,
	   Bundle data = new Bundle(); 
	   data.putString("key", "last words before be kill");
	   outState.putAll(data);
	super.onSaveInstanceState(outState);
}
   @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
	// TODO Auto-generated method stub
	   if(savedInstanceState!=null){ //判断是否有以前的保存状态信息
			 savedInstanceState.get("Key"); 
			 }
	super.onRestoreInstanceState(savedInstanceState);
}
}
```

> onSaveInstanceState方法

  在activity 可能被回收之前 调用,用来保存自己的状态和信息,以便回收后重建时恢复数据(在onCreate()或onRestoreInstanceState()中恢复)。旋转屏幕重建activity会调用该方法,但其他情况在onRause()和onStop()状态的activity不一定会调用 ,下面是该方法的文档说明。

```
   One example of when onPause and onStop is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause is called and not onSaveInstanceState is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact. 
```

也就是说,系统灵活的来决定调不调用该方法,**但是如果要调用就一定发生在onStop方法之前,但并不保证发生在onPause的前面还是后面。**

> onRestoreInstanceState方法

  这个方法在onStart 和 onPostCreate之间调用,在onCreate中也可以状态恢复,但有时候需要所有布局初始化完成后再恢复状态。

  onPostCreate:一般不实现这个方法,当程序的代码开始运行时,它调用系统做最后的初始化工作。

#启动模式

##启动模式什么?
  
  简单的说就是定义activity 实例与task 的关联方式。
  
##为什么要定义启动模式? 

   为了实现一些默认启动(standard)模式之外的需求:
   

 - 让某个 activity 启动一个新的 task (而不是被放入当前 task )
 
 - 让 activity 启动时只是调出已有的某个实例(而不是在 back stack 顶创建一个新的实例) 
 
 - 或者,你想在用户离开 task 时只保留根 activity,而 back stack 中的其它 activity 都要清空

##怎样定义启动模式?

  定义启动模式的方法有两种:

### 使用 manifest 文件

  在 manifest 文件中activity声明时,利用 activity 元素的 launchMode 属性来设定 activity 与 task 的关系。

  

```
 <activity
            ......
            android:launchMode="standard"
             >
           .......
        </activity>
```

> 注意: 你用 launchMode 属性为 activity 设置的模式可以被启动 activity 的 intent 标志所覆盖。

####有哪些启动模式?


 - "standard" (默认模式) 
 
  当通过这种模式来启动Activity时, Android总会为目标 Activity创建一个新的实例,并将该Activity添加到当前Task栈中。这种方式不会启动新的Task,只是将新的 Activity添加到原有的Task中。 
  
 - "singleTop" 
 
   该模式和standard模式基本一致,但有一点不同:当将要被启动的Activity已经位于Task栈顶时,系统不会重新创建目标Activity实例,而是直接复用Task栈顶的Activity。
 
 - "singleTask"

  Activity在同一个Task内只有一个实例。
  
  如果将要启动的Activity不存在,那么系统将会创建该实例,并将其加入Task栈顶; 

  如果将要启动的Activity已存在,且存在栈顶,直接复用Task栈顶的Activity。 

  如果Activity存在但是没有位于栈顶,那么此时系统会把位于该Activity上面的所有其他Activity全部移出Task,从而使得该目标Activity位于栈顶。

 - "singleInstance" 

  无论从哪个Task中启动目标Activity,只会创建一个目标Activity实例且会用一个全新的Task栈来装载该Activity实例(全局单例).

  如果将要启动的Activity不存在,那么系统将会先创建一个全新的Task,再创建目标Activity实例并将该Activity实例放入此全新的Task中。

  如果将要启动的Activity已存在,那么无论它位于哪个应用程序,哪个Task中;系统都会把该Activity所在的Task转到前台,从而使该Activity显示出来。

### 使用 Intent 标志

  在要启动 activity 时,你可以在传给 startActivity() 的 intent 中包含相应标志,以修改 activity 与 task 的默认关系。

  

```
     Intent i = new Intent(this,NewActivity.class);
		i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		startActivity(i);
```

####可以通过标志修改的默认模式有哪些?

   

 - FLAG_ACTIVITY_NEW_TASK

  与"singleTask"模式相同,在新的 task 中启动 activity。如果要启动的 activity 已经运行于某 task 中,则那个 task 将调入前台。

 - FLAG_ACTIVITY_SINGLE_TOP

  与 "singleTop"模式相同,如果要启动的 activity位于back stack 顶,系统不会重新创建目标Activity实例,而是直接复用Task栈顶的Activity。

 - FLAG_ACTIVITY_CLEAR_TOP

  **此种模式在launchMode中没有对应的属性值。**如果要启动的 activity 已经在当前 task 中运行,则不再启动一个新的实例,且所有在其上面的 activity 将被销毁。

#### 关于启动模式的一些建议

   一般不要改变 activity 和 task 默认的工作方式。 如果你确定有必要修改默认方式,请保持谨慎,并确保 activity 在启动和从其它 activity 返回时的可用性,多做测试和安全方面的工作。


# Intent Filter

  android的3个核心组件——Activity、services、广播接收器——是通过intent传递消息的。intent消息用于在运行时绑定不同的组件。
  在 Android 的 AndroidManifest.xml 配置文件中可以通过 intent-filter 节点为一个 Activity 指定其 Intent Filter,以便告诉系统该 Activity 可以响应什么类型的 Intent。

##intent-filter 的三大属性

###Action 

  一个 Intent Filter 可以包含多个 Action,Action 列表用于标示 Activity 所能接受的“动作”,它是一个用户自定义的字符串。

  

```
<intent-filter > 
 <action android:name="android.intent.action.MAIN" /> 
 <action android:name="com.scu.amazing7Action" /> 
……
 </intent-filter>
```

在代码中使用以下语句便可以启动该Intent 对象:

```
Intent i=new Intent(); 
i.setAction("com.scu.amazing7Action");
```
Action 列表中包含了“com.scu.amazing7Action”的 Activity 都将会匹配成功

###URL

  在 intent-filter 节点中,通过 data节点匹配外部数据,也就是通过 URI 携带外部数据给目标组件。

  

```
<data android:mimeType="mimeType" 
	android:scheme="scheme" 
	 android:host="host"
	 android:port="port" 
	 android:path="path"/>
```
注意:只有data的所有的属性都匹配成功时 URI 数据匹配才会成功

###Category 

  为组件定义一个 类别列表,当 Intent 中包含这个类别列表的所有项目时才会匹配成功。

```
<intent-filter . . . >
   <action android:name="code android.intent.action.MAIN" />
   <category android:name="code android.intent.category.LAUNCHER" />
</intent-filter>
```

##Activity 种 Intent Filter 的匹配过程

  ①加载所有的Intent Filter列表
  ②去掉action匹配失败的Intent Filter
  ③去掉url匹配失败的Intent Filter
  ④去掉Category匹配失败的Intent Filter
  ⑤判断剩下的Intent Filter数目是否为0。如果为0查找失败返回异常;如果大于0,就按优先级排序,返回最高优先级的Intent Filter



# 开发中Activity的一些问题

 - 

 一般设置Activity为非公开的

  

```
<activity  
...... 
android:exported="false" /> 
```

注意:非公开的Activity不能设置intent-filter,以免被其他activity唤醒(如果拥有相同的intent-filter)。

 - 不要指定activity的taskAffinity属性

 - 不要设置activity的LaunchMode(保持默认)

  注意Activity的intent最好也不要设定为FLAG_ACTIVITY_NEW_TASK

 - 在匿名内部类中使用this时加上activity类名(类名.this,不一定是当前activity)

 - 设置activity全屏
 
    在其 onCreate()方法中加入:

```
// 设置全屏模式
 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 
 // 去除标题栏
 requestWindowFeature(Window.FEATURE_NO_TITLE);
```

  



  

  
  
    

转载于:https://my.oschina.net/u/2288454/blog/1921762

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值