Android学习日志(一)第一行代码

@[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() 方法之间所经历的就是前台生存期。在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行交互的,我们平时看到和接触最多的也就是这个状态下的活动。

Android官方提供的活动生命周期的示意图

在这里插入图片描述
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342