Android开发系列之探究活动
之前趁着空闲看了一遍郭霖大神的《第一行代码》收获很大,说实话很不错的一本书。因为一只从事iOS开发的工作,相对于android来说,总感觉两者有一些相似之处,比如一些控件的功能等,所以说学习起来还是很容易理解的。书中的一些代码也亲自敲了一遍,虽然不是太熟练但是对android开发也有了一些大致的了解。整本书看完后也就有点松懈了,平常工作中也没用到,渐渐就忘记了。忽然觉得语言开发这东西学的快,忘的也快。现在很后悔没有坚持下去,最近想要整理记录自己工作中遇到的技术,也趁着这个机会重新温习下android开发,认真记录,好好打理自己的博客。
一、概念理解
1,Android系统有四大组件分别是活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)、内容提供器(Content Provider):
(1)活动:它是所有Android应用程序的门面,凡是应用中能看的到的东西,都是放在活动中的;它是一种可以包含用户界面的组件,主要用于和用户进行交互。
(2)服务:它是Android中实现程序后台运行解决的方案,它非常适合用于去执行那些不需要和用户交互而且还要求长期运行的任务。
(3)广播接收器:它可以允许你的应用程序接受来自各处的广播消息,比如电话、短息等。
(4)内容提供器:它为应用程序之间共享数据提供了可能,比如读取系统电话薄中的联系人。
2,活动的生命周期
(1)活动状态
每个活动在其生命周期中最多可能会有四种状态:运行状态、暂停状态、停止状态、销毁状态。
a, 运行状态:当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。
b, 暂停状态:当一个活动不在处于栈顶位置,但仍可见时,这时活动就进入暂停状态(并不是每一个活动都会占满整个屏幕)。
c, 停止状态:当一个活动不在处于栈顶位置,并且完全不可见的时候,就进入了停止状态。此时,系统不会回收该活动,但是,当其它地方需要内存时,处于停止状态的活动有可能会被系统回收。
d, 销毁状态:当一个活动从返回栈中移除后就变成了销毁状态。
(2)活动的生存期
A,onCreate():活动第一次被创建的时候调用,可以在这个方法中完成活动的初始化操作,比如加载布局、绑定事件等。
B,onStart(): 活动由不可见变为可见的时候调用。
C,onResume():活动准备好和用户进行交互的时候调用。此时活动一定位于返回栈的栈顶,并且处于运行状态。
D,onPause(): 系统准备去启动或者恢复另一个活动的时候调用。通常会在该方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。
E,onStop(): 活动完全不可见时调用。它和onPause( )方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause()方法就会得到执 行,而onStop( )方法并不会执行。
F,onDestroy():活动被销毁之前调用,之后活动的状态将变为销毁状态。
G,onRestart():活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。
上述七个方法中除了onResult()方法,其它都是两两相对的,从而可以将活动分为三中生存期:完成生存期、可见生存期、前台生存期。
完整生存期:onCreate()方法和onDestroy()方法之间所经历的,就是完整生存期。
可见生存期:onStart()方法和onStop()方法之间所经历的,就是可见生存期。
前台生存期:onResume()方法和onPause()方法之间所经历的,就是前台生存期。
二、基础控件的使用
在android开发的过程中,一般对于控件的属性定义是在Activity对应的XML文件中完成的,它的相关语法的使用感觉很像CSS。下面就来介绍一些常用控件的使用方法:
(1)Button
首先在XML文件中定义Button的属性
1 <Button 2 android:id="@+id/btn01" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 android:layout_margin="30px" 6 android:background="@color/colorPrimary" 7 android:text="Button" 8 android:textAllCaps="false" 9 />
然后在Activity中根据id获取到Button,并添加点击事件
Button btn01 = (Button)findViewById(R.id.btn01); btn01.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "按钮点击了", Toast.LENGTH_SHORT).show(); } });
为Button添加事件的另一种方法就是在XML中定义属性android:onClick="btnAction",然后在activity中实现btnAction方法即可;当Button事件出发时,我们让弹出了一个Toast。还有一种添加事件的方法,是通过接口的方式来实现的。
1 public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 requestWindowFeature(Window.FEATURE_NO_TITLE); 7 //this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 8 setContentView(R.layout.main_xml); 9 //this.getSupportActionBar().hide(); 10 //this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 11 Button btn = (Button)findViewById(R.id.btn01); 12 btn.setOnClickListener(this); 13 } 14 public void onClick(View v){ 15 switch (v.getId()){ 16 case R.id.btn01: 17 //在此处添加逻辑 18 break; 19 default: 20 break; 21 } 22 }
(2)隐藏标题栏
方法一:如果创建的activity继承的是Activity, 可以使用requestWindowFeature(Window.FEATURE_NO_TITLE);隐藏标题栏,注意:此处代码要在setContentView()之前执行,不然会报错。如果默认继承的是AppCompatActivity,则上述方法失效,可以在setContentView()方法之后使用this.getSupportActionBar().hide();隐藏标题栏。
1 @Override 2 protected void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 //requestWindowFeature(Window.FEATURE_NO_TITLE); 5 6 setContentView(R.layout.main_xml); 7 this.getSupportActionBar().hide(); 8 9 }
方法二:可以在AndroidManifest.xml中作如下配置,这样就没有标题栏了
<application
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
>
(3)隐藏状态栏
//隐藏状态栏 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
(4)Menu的使用
在res目录下的menu文件夹下创建一个main.xml文件,内容如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <menu xmlns:android="http://schemas.android.com/apk/res/android"> 3 <item 4 android:id="@+id/add_item" 5 android:title="Add" /> 6 <item 7 android:id="@+id/remove_item" 8 android:title="Remove" /> 9 10 </menu>
注释:这里创建了两个菜单项,其中<item>标签就是用来创建具体的一个菜单项,然后通过android:id给这个菜单项指定一个唯一的标识符,通过android:title给这菜单指定一个名称。
然后打开Activity,重写onCreateOptionsMenu()方法,内容如下:
//通过getMenuInflater()方法得到MenuInflater对象 public boolean onCreateOptionsMenu(Menu menu){ //调用inflate()方法创建菜单 getMenuInflater().inflate(R.menu.main,menu); //如果返回false,创建的菜单无法显示 return true; }
当然,仅仅让菜单显示出来是不够的,菜单不是用来看的,关键是要菜单真正可用才行,因此还要再定义菜单响应事件。
在Activity中重写onOptionsItemSelected()方法,内容如下:
1 public boolean onOptionsItemSelected(MenuItem item){ 2 switch (item.getItemId()){ 3 case R.id.add_item: 4 Toast.makeText(this, "you click add", Toast.LENGTH_SHORT).show(); 5 break; 6 case R.id.remove_item: 7 Toast.makeText(this, "you click remove", Toast.LENGTH_SHORT).show(); 8 break; 9 default: 10 break; 11 } 12 return true; 13 }
三、Intent的使用
Intent是android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent一般可以用来启动活动、启动服务、以及发送广播等场景,其大致分为两种,显示Intent和隐式Intent,下面就来分别介绍一下:
1,显示Intent的使用
首先创建两个activity,并在所属的XML文件中分别创建两个Button,并在第一个活动的Button点击事件中使用Intent跳转到第二个活动。我们看到在Intent的构造函数接收了两个参数,第一个参数要求提供一个启动活动的上下文,第二个参数则是制定想要启动的目标活动,然后通过startActivity()来执行这个Intent。
public void btnAction(View view){ Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent); }
2,隐式Intent的使用
相比于显式Intent,隐式Intent则含蓄的多了,它并不明确指出我们想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮助找出合适的活动去启动。要想使用隐式的Intent我们需要在AndroidManifest.xml文件中进行一些配置,通过在<activity>标签下配置<intent-filter>的内容,可以指定当前活动能够响应的action和category。
<activity android:name=".SecondActivity"> <intent-filter> <action android:name="com.example.whs.activity.ACTION_START"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
在<action>标签中,我们指明了当前活动可以响应com.example.whs.activity.ACTION_START这个action,而<category>标签则包含了一些附加信息,更精确的指明了当前的活动能够响应的Intent中还可能带有的category。只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时,这个活动才能响应该Intent。
public void btnAction(View view){ Intent intent = new Intent("com.example.whs.activity.ACTION_START"); startActivity(intent); }
注意:因为android.intent.category.DEFAULT是一种默认的category,在调用startActivity()方法的时候会自动将这个category添加到Intent中。每个Intent中只能指定一个action,但却能指定多个category,我们可以在Intent中通过intent.addCategory的方法增加一个category,但是必须在<intent-filter>标签中声明可以响应这个category,否则程序会出现错误。
3,更多隐式Intent的用法
使用隐式我们不仅可以启动自己程序内的活动,还可以启动其它程序的活动,这使得android多个应用程序之间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页,这时没必要自己去实现一个浏览器,而是只需要调用系统的浏览器来打开这个网页就行了。
public void backAction(View view){ Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.baidu.com")); startActivity(intent); }
首先指定Intent的action为Intent.ACTION_VIEW,这是一个android系统内置的动作,其常量为android.intent.action.VIEW。然后通过Url.parse方法,将一个网址字符串解析成一个Url对象,再调用Intent的setData()方法将这个Url对象传递进去。与此对应,还可以在<intent-filter>标签中再配置一个<data>标签,用于更精确的指定当前活动能够响应什么类型的数据。
<activity android:name=".SecondActivity"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="http"/> </intent-filter> </activity>
<data>标签中可以配置以下内容:
android:scheme 用于指定数据的协议部分,如上例中的http部分。
android:host 用于指定数据的主机名部分,如上例中的www.baidu.com部分。
android:port 用于指定数据的端口部分,一般紧随在主机名之后。
android:path 用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
android:mimeType 用于指定可以处理的数据类型,允许使用通配符的方式进行指定。
除了http协议外,我们还可以指定很多的其它协议,比如geo表示显示地理位置、tel表示拨打电话,下面的代码就是展示调用系统拨号界面。首先指定了Intent的action是Intent.ACTION_DIAL,这又是android系统的内置动作。然后在data部分指定了协议是tel,号码是10086。
public void backAction(View view){ Intent intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); }
4,活动间数据的传递
(1)向下一个活动传递数据
Intent中提供了一系列putExtra()方法的重载,可以把想要传递的数据暂存在Intent中,启动另一个活动后,只需要把这些数据再从Intent中取出就可以了。注意,putExtra()方法接收两个参数,第一个参数是键,用于后面从Intent中取值,第二个参数才是真正要传递的数据。getIntent()方法获取到用于启动本activity的Intent,然后调用getStringExtra()方法,传入相应的键值,就可以得到传递的数据了。
1 public void btnAction(View view){ 2 String data = "hello MainActivity"; 3 Intent intent = new Intent(MainActivity.this, SecondActivity.class); 4 intent.putExtra("extra_data", data); 5 startActivity(intent); 6 } 7 8 //取数据 9 public void backAction(View view){ 10 11 Intent intent = getIntent(); 12 String data = intent.getStringExtra("extra_data"); 13 Log.d("SecondActivity",data); 14 }
(2)返回数据给上一个活动
在Activity中有一个startActivityForResult()方法用于启动活动,但是这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。该方法接收两个参数,第一个参数是Intent,第二个参数是请求码(只要是唯一只就可以),用于在之后的回调中判断数据的来源。在第一个activity中也要构建一个Intent,仅仅用于传递数据使用。我们只要把传递的数据放在Intent中,然后调用setResult()方法就可以了(该方法专门用于向上一个活动返回处理结果),此方法同样接收两个参数,第一个参数用于向上一个活动返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个值,第一个参数则是把带有数据的Intent传递回去,然后调用finish()方法来销毁当前活动。注意,当我们使用startActivityForResult()方法来启动下一个activity时,该活动被销毁之后会回调上一个活动的onActivityResult()方法,因此,我们需要在上一个activity中重写这个方法来得到返回的数据。onActivityResult()方法带有三个参数,第一个参数requestCode,即我们在启动活动时传入的请求码;第二个参数resultCode,即我们在返回数据时传入的处理结果;第三个参数data,即携带着返回数据的Intent。当用户按下Back键返回时,会执行onBackPressed()方法中的代码,在这里添加返回数据的逻辑也是可以的。
1 public void btnAction(View view){ 2 Intent intent = new Intent(MainActivity.this, SecondActivity.class); 3 startActivityForResult(intent, 1); 4 } 5 6 protected void onActivityResult(int requestCode, int resultCode, Intent data){ 7 switch (requestCode){ 8 case 1: 9 if (resultCode == RESULT_OK){ 10 String returnedData = data.getStringExtra("data_return"); 11 Log.d("firstActivity", returnedData); 12 } 13 break; 14 default: 15 break; 16 } 17 } 18 19 //第二个活动 20 public void backAction(View view){ 21 22 Intent intent = new Intent(); 23 intent.putExtra("data_return", "hello secondActivity"); 24 setResult(RESULT_OK, intent); 25 finish(); 26 }