@[TOC]
Android 日志工具的使用
Log.v() 。用于打印那些最为琐碎的、意义最小的日志信息。对应级别verbose,是Android日志里面级别最低的一种。
Log.d() 。用于打印一些调试信息,这些信息对你调试程序和分析问题应该是有帮助的。对应级别debug,比verbose高一级。
Log.d()传入两个参数:1.tag 一般情况下传入当前类的类名,用于过滤打印信息。2.msg 这里是想要打印的具体内容。
Log.i() 。用于打印一些比较重要的数据,这些数据应该是你非常想看到的、可以帮你分析用户行为数据。对应级别info,比debug高一级。
Log.w() 。用于打印一些警告信息,提示程序在这个地方可能会有潜在的风险,最好去修复一下这些出现警告的地方。对应级别warn,比info高一级。
Log.e() 。用于打印程序中的错误信息,比如程序进入到了catch语句当中。当有错误信息打印出来的时候,一般都代表你的程序出现严重问题了,必须尽快修复。对应级别error,比warn高一级。
注:logcat中的过滤器 1.Show only selected application表示只显示当前选中程序的日志。 2.Firebase是谷歌提供的一个分析工具,基本没什么用。 3.No Filters相当于没有过滤器,会把所有的日志都显示出来。
活动
1.活动(Activity)可以包含用户界面的组件,用于和用户的交互。
2.项目中的任何活动都需要重写Activity的onCreate() 方法。
3.最好是每一个活动都可以对应一个布局。
活动中加载一个布局
在活动方法中
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//这里给当前活动加载一个布局
//参数传入要加载的布局的id
setContentView(R.layout.first_layout);
}
}
注:布局文件的id在文件R中,在我们创建布局的时候Android Studio已经帮我们添加到了R文件中,调用时R.layout.布局名就可以得到布局的id。
将活动在AndroidManifest文件中注册
每个活动都要在AndroidManifest文件中注册,只有注册后该活动才会生效。但是这一步Android Studio也会帮我们完成。
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
//这里直接写.FirstActivity指定那个活动,上面package已近写入了包路径
<activity android:name=".FirstActivity"></activity>
</application>
</manifest>
将活动配置为主活动
在<activity>标签中加入<intent-filter>标签,在<intent-filter>标签中添加
<action android:name="android.intent.action.MAIN"/>和
<category android: name="android.intent.category.LAUNCHER" />
这两句声明。
指定活动的标题栏内容
<activity>标签的android:label="This is FirstActivity"属性指定活动标签栏显示内容。
在活动中使用Toast弹出层
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
//获取布局的按钮实例
Button button1 = (Button) findViewById(R.id.button_1);
//给按钮注册一个监听器
button1.setOnClickListener(new View.OnClickListener() {
//点击按钮箭头按钮中的单击事件
@Override
public void onClick(View v) {
//创建一个toast对象,用show将弹出层展示出来
Toast.makeText(FirstActivity.this, "You clicked Button 1",
Toast.LENGTH_SHORT).show();
}
});
在活动中使用Menu
创建菜单项
首先在res目录下新建一个menu文件夹,右击res目录→New→Directory,输入文件夹名menu,点击OK。接着在这个文件夹下再新建一个名叫main的菜单文件,右击menu文件夹→New→Menu resource file。
在main.xml文件中添加如下代码:
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
//一个item标识一个菜单项,id标识一个菜单的id编号
<item
android:id="@+id/add_item"
android:title="菜单名称"/>
<item
android:id="@+id/remove_item"
android:title="菜单名称"/>
</menu>
显示菜单项
在调用菜单的活动中重写onCreateOptionsMenu()方法,在方法中编写如下代码:
public boolean onCreateOptionsMenu(Menu menu) {
//getMenuInflater() 方法能够得到MenuInflater 对象,再调用它的inflate() 方法就可以给当前活动创建菜单了。给方法传入R.menu.main
getMenuInflater().inflate(R.menu.main, menu);
//返回true将菜单显示出来
//返回flase创建的菜单将无法显示
return true;
}
使用菜单
在显示菜单的活动中重写onOptionsItemSelected()方法,在方法中编写如下代码:
public boolean onOptionsItemSelected(MenuItem item) {
//switch获取当前点击的菜单it
switch (item.getItemId()) {
//对比id,执行操作
case R.id.add_item:
//满足条件,弹出弹出层
Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
销毁一个活动
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//调用此方法销毁活动
finish();
}
});
使用intent在不同的活动之间跳转
Intent显示的跳转
创建布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 2"
/>
</LinearLayout>
Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent一般可被用于启动活动、启动服务以及发送广播等场景。
Intent有多个构造函数的重载,其中一个是Intent(Context packageContext, Class<?> cls) 。这个构造函数接收两个参数,第一个参数Context 要求提供一个启动活动的上下文,第二个参数Class 则是指定想要启动的目标活动,通过这个构造函数就可以构建出Intent 的“意图”。
Activity类中提供了一个startActivity() 方法,这个方法是专门用于启动活动的,它接收一个Intent 参数,这里我们将构建好的Intent传入startActivity() 方法就可以启动目标活动了。
代码如下:
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建一个Intent,传入要跳转的活动
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
//调用启动活动的方法
startActivity(intent);
}
});
Intent隐式的跳转
配置AndroidManifest.xml文件
//配置要跳转到的活动的<activity>标签
<activity android:name=".SecondActivity" >
//在其中加入 <intent-filter>
<intent-filter>
//在<intent-filter>中加入以下两个自闭和标签
<action android:name="com.example.activitytest.ACTION_START"/>//指明要响应的action
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
只有<action> 和<category> 中的内容同时能够匹配上Intent中指定的action 和category 时,这个活动才能响应该Intent。
修改FirstActivity(跳转的前的活动)的按钮的单击事件
//触发按钮的单击事件
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//写入action 标签中的内容
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
}
});
注:这里<category android:name="android.intent.category.DEFAULT" />是一种默认的category ,在调用startActivity()会自动将这个category添加到Intent中。
每个Intent中只能指定一个acyion,但是我们可以给它指定多个category。
增加一个category 的代码
//当前的intent对象的addCategory
intent.addCategory("com.example.activitytest.MY_CATEGORY");
这样会报错,我们需要在这个活动的<intent-filter>标签中再添加一个category 来响应它。
<category android:name="com.example.activitytest.MY_CATEGORY"/>
更多的隐式Intent用法
有时我们的程序中不单单要调用我们自己的活动,我们有时还需要调用其他程序的活动,intent的这一点使得我们的Android程序可以在多个程序之间共享。
intent调用一个网页,打开系统浏览器
我么只需要修改当前活动中按钮的单击事件就可以
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
}
});
这里Intent.ACTION_VIEW 是一个Android的内置活动。这个动作的常量为:android.intent.action.VIEW。这里我们通过Uri.parse() 方法,将一个网址字符串解析成一个Uri 对象,再调用Intent的setData() 方法将这个Uri 对象传递进去。
再次运行程序,点击按钮,我们就可以打开系统浏览器了。
注:我们可以在<intent-filter>标签中配置一个<data>标签,用于更加精确的指定当前活动能够响应什么类型的数据。
主要有一下几种:
android:scheme 。用于指定数据的协议部分,如上例中的http部分。
android:host 。用于指定数据的主机名部分,如上例中的www.baidu.com部分。
android:port 。用于指定数据的端口部分,一般紧随在主机名之后。
android:path 。用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
android:mimeType 。用于指定可以处理的数据类型,允许使用通配符的方式进行指定。
当<data>标签中的内容和intent中携带的Data完全一致时,当前活动才能够
例子
右击com.example.activitytest包→New→Activity→Empty Activity,新建ThirdActivity,并勾选Generate Layout File,给布局文件起名为third_layout,点击Finish完成创建。然后编辑third_layout.xml,将里面的代码替换成如下内容:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 3"
/>
</LinearLayout>
ThirdActivity中的代码保持不变就可以了,最后在AndroidManifest.xml中修改ThirdActivity的注册信息:
<activity android:name=".ThirdActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
</activity>
我们在ThirdActivity的<intent-filter> 中配置了当前活动能够响应的action 是Intent.ACTION_VIEW 的常量值,而category 则毫无疑问指定了默认的category 值,另外在<data> 标签中我们通过android:scheme 指定了数据的协议必须是http协议,这样ThirdActivity应该就和浏览器一样,能够响应一个打开网页的Intent了。
注:这里的声明,我们将ThirdActivity活动声明成了一个可以响应http协议的活动,当我们做一个http协议的动作是,系统会提示我们打开当前ThirdActivity活动。
电话协议
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
});
打开拨号界面,并且输入当前电话10086。
在调用下一个活动的同时传递数据
Intent中提供了一系列putExtra()方法的重载,可以将我们需要的数据传入到Intent中。启动至一个活动后,我们可以将Intent中的数据取出,这样我们便实现了数据的传输。
//我们在目标活动的上一个活动中书写
button1.setOnClickListener(new View.OnClickListener() {
//按钮的单击事件
@Override
public void onClick(View v) {
//声明字符串
String data = "Hello SecondActivity";
//显示调用下一个活动
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
//将创建好的字符串传入到intent中
//这里按照键值对来设置
intent.putExtra("extra_data", data);
//调用下一个活动
startActivity(intent);
}
});
在目标活动中书写
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
//获取当前intent
Intent intent = getIntent();
//读取字符串
String data = intent.getStringExtra("extra_data");
//日志打印字符串
Log.d("SecondActivity", data);
}
}
注:这里获取数据时:
字符串 用getStringExtra() 方法
int类型 用getIntExtra() 方法
boolean类型 用getBooleanExtra() 方法
返回数据给上一个活动
Activity中还有一个startActivityForResult() 方法也是用于启动活动,这个方法期望在启用的活动销毁时,给当前活动返回一个数据。startActivityForResult()方法中需要两个参数,第一个参数是Intent,第二个参数是请求码。用于之后的回调中判断数据的来源。
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//显式调用
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
//打开下一个活动
startActivityForResult(intent, 1);
}
});
注:这里请求码必须是唯一的值,避免后期冲突
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
//声明一个按钮
Button button2 = (Button) findViewById(R.id.button_2);
//按钮单击事件
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建Intent
Intent intent = new Intent();
//写入返回数据到intent
intent.putExtra("data_return", "Hello FirstActivity");
//用于向上一个活动返回数据
//参数一用于向上一个活动返回处理结果
//参数二用于向上一个活动返回intent
setResult(RESULT_OK, intent);
//销毁当前活动
finish();
}
});
}
}
读取返回的数据时
我们要在目标活动中书写如下代码
//requestCode 判断数据来源
//resultCode 判断返回结果
//data 返回的内容
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
//判断数据来源
case 1:
//判断处理结果
if (resultCode == RESULT_OK) {
//获取返回数据
String returnedData = data.getStringExtra("data_return");
//打印返回数据
Log.d("FirstActivity", returnedData);
}
break;
default:
}
}
onActivityResult() 方法带有三个参数,第一个参数requestCode ,即我们在启动活动时传入的请求码。第二个参数resultCode ,即我们在返回数据时传入的处理结果。第三个参数data ,即携带着返回数据的Intent。由于在一个活动中有可能调用startActivityForResult() 方法去启动很多不同的活动,每一个活动返回的数据都会回调到onActivityResult() 这个方法中,因此我们首先要做的就是通过检查requestCode 的值来判断数据来源。确定数据是从SecondActivity返回的之后,我们再通过resultCode 的值来判断处理结果是否成功。最后从data 中取值并打印出来,这样就完成了向上一个活动返回数据的工作。
在按下back键回到上一个活动时传递数据
我们需要在当前活动中重写onBackPressed方法
//当用户按下back键时,将会调用onBackPressed方法
@Override
public void onBackPressed() {
//需要返回的intent
Intent intent = new Intent();
//写入参数到intent
intent.putExtra("data_return", "Hello FirstActivity");
//返回参数到上一个活动中
setResult(RESULT_OK, intent);
//销毁当前活动
finish();
}
活动的生命周期
返回栈
经过前面的学习,我们发现在Android中活动时可以叠加的,每当我们启动一个新的活动,就会覆盖在原来的活动之上,当我们在点击back键时,就会销毁当前的活动,在此下的活动就会显现出来。
其实Android是使用任务(Task)来管理活动的,一个任务就是一组放在栈里面的活动集合,这个栈被称为是返回栈。
栈是一种后进先出的书籍结构。在一般情况下,当我们启动了一个新的活动时,这个活动就会存在于返回栈中,并且是处于返回栈的最顶端。当我们按下back键或调用finish()方法时,当前的栈中最顶端的活动就会出栈,这时当前一个活动就会处于栈的最顶端。系统总是会显示最顶端的活动给用户。
如下图:
活动的状态
运行状态
当一个活动处于栈的最顶端时,这个活动就处于运行状态。系统是不愿意回收处于活动状态的活动的。
暂停状态
当一个活动不再处于栈的最顶端,电视仍然可见时,这个活动就处于暂停状态。处于暂停活动的活动仍然是活的,出现这种情况是因为不是每个活动都可以占满屏幕,这种状态下的活动用户任然可见,所以系统只有在内存极低的情况下才会回收这个活动。
停止状态
当一个活动不再处于栈的最顶端,而且不可见时,这个活动就处于停止状态。这种状态下的活动,系统仍然会为这种活动保存相应的状态和成员变量,只有在其他地方需要内存事,处于停止状态的活动才有可能被系统回收。
销毁状态
当一个活动从栈中移除时就处于销毁状态。系统将回收这个状态下的活动。
活动的生存期
Activity类中定义可7个回调方法,覆盖了活动生命周期的每个环节:
onCreate()这个方法会在活动第一次被创建的时候调用,一般我们在这个方法中完成活动的初始化操作,比如加载布局,绑定事件。
onStart()这个方法在活动由不可见变为可见的时候调用。
onResume()这个方法在活动准备好和用户交互的时候调用,此时活动处于栈的最顶端,处于运行状态。
onPause() 这个方法在系统准备启动或者恢复一个活动的时候调用。我们通常会将资源的释放放在这个方法中,以及将一些关键的数据保存在这个方法中。
onStop()这个活动会在当前活动完全不可见时执行,当打开的活动不能完全覆盖当前活动时,这个方法不会执行。
onDestroy()这个方法在活动被销毁之前调用,此方法之后,活动状态将变为销毁状态。
onRestart()这个方法在活动由停止状态变为运行转态之前调用,也就是是活动被重新启动时调用。
根据这些方法,我么将活动的生存期分为:
完整生存期
活动在onCreate()方法和onDestroy() 方法之间所经历的,就是活动的完整生存期。一般情况下,一个活动会在onCreate()方法中完成各种初始化操作,会在onDestroy()方法中完成内存的释放。
可见生存期
活动在onStart() 方法和onStop() 方法之间所经历的,就是可见生存期。
在这一时期,活动总是处于用户可见的状态,虽然在这一时期,活动和用户之间可能无法交互,但是我们可以通过onStart()方法对用户可见的资源进行加载,用onStop()方法对资源进行释放,从而保证处于停止状态的活动不会占据过多的内存。
前台生存期
活动在onResume() 方法和onPause() 方法之间所经历的就是前台生存期。在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行交互的,我们平时看到和接触最多的也就是这个状态下的活动。