1.src
毫无疑问, src 目录是放置我们所有 Java 代码的地方,它在这里的含义和普通 Java项目下的 src 目录是完全一样的,展开之后你将看到我们刚才创建的 HelloWorldActivity文件就在里面。
2.gen
这个目录里的内容都是自动生成的,主要有一个 R.java 文件,你在项目中添加的任何资源都会在其中生成一个相应的资源 id。这个文件永远不要手动去修改它。
3.assets
这个目录用得不多,主要可以存放一些随程序打包的文件,在你的程序运行时可以动态读取到这些文件的内容。另外,如果你的程序中使用到了 WebView 加载本地网页的功能,所有网页相关的文件也都存放在这个目录下。
4.bin
这个目录你也不需要过多关注,它主要包含了一些在编译时自动产生的文件。其中会有一个你当前项目编译好的安装包,展开 bin 目录你会看到 HelloWorld.apk,把这个文件拷到手机上就可以直接安装了。
5.libs
如果你的项目中使用到了第三方 Jar 包,就需要把这些 Jar 包都放在 libs 目录下,放在这个目录下的 Jar 包都会被自动添加到构建路径里去。你可以展开上图中 Android 4.0Android Private Libraries、 Android Dependencies 这些库,其中显示的 Jar 包都是已经被添加到构建路径里的。
6.res
这个目录下的内容就有点多了,简单点说,就是你在项目中使用到的所有图片、布局、字符串等资源都要存放在这个目录下,前面提到的 R.java 中的内容也是根据这个目录下的文件自动生成的。当然这个目录下还有很多的子目录,图片放在 drawable 目录下,布局放在 layout 目录下,字符串放在 values 目录下,所以你不用担心会把整个 res 目录弄得乱糟糟的。
7.AndroidManifest.xml
这是你整个 Android 项目的配置文件,你在程序中定义的所有四大组件都需要在这个文件里注册。另外还可以在这个文件中给应用程序添加权限声明,也可以重新指定你创建项目时指定的程序最低兼容版本和目标版本。由于这个文件以后会经常用到,我们用到的时候再做详细说明。
8.project.properties
这个文件非常地简单,就是通过一行代码指定了编译程序时所使用的 SDK 版本。我们的 HelloWorld 项目使用的是 API 14,你也可以在这里改成其他版本试一试。这样整个项目的目录结构就都介绍完了,如果你还不能完全理解的话也很正常,毕竟里面有太多的东西你都还没接触过。不用担心,这并不会影响到你后面的学习。
1. Log.v()
这个方法用于打印那些最为琐碎的,意义最小的日志信息。对应级别 verbose,是Android 日志里面级别最低的一种。
2. Log.d()
这个方法用于打印一些调试信息,这些信息对你调试程序和分析问题应该是有帮助的。对应级别 debug,比 verbose 高一级。
3. Log.i()
这个方法用于打印一些比较重要的数据,这些数据应该是你非常想看到的,可以帮你分析用户行为的那种。对应级别 info,比 debug 高一级。
4. Log.w()
这个方法用于打印一些警告信息,提示程序在这个地方可能会有潜在的风险,最好去修复一下这些出现警告的地方。对应级别 warn,比 info 高一级。
5. Log.e()
这个方法用于打印程序中的错误信息,比如程序进入到了 catch 语句当中。当有错误信息打印出来的时候,一般都代表你的程序出现严重问题了,必须尽快修复。对应级别 error,比 warn 高一级。
example:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.hello_world_layout); Log.d("HelloWorldActivity", "onCreate execute"); }
活动( Activity) 是最容易吸引到用户的地方了,它是一种可以包含用户界面的组件,主要用于和用户进行交互。一个应用程序中可以包含零个或多个活动,但不包含任何活动的应用程序很少见,谁也不想让自己的应用永远无法被用户看到吧?
项目中的任何活动都应该重写 Activity 的 onCreate()方法,但目前我们的FirstActivity内部还什么代码都没有,所以首先你要做的就是在 FirstActivity中重写 onCreate()方法,代码如下所示:
public class FirstActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } }
first_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<Button android:id="@+id/button_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 1" /> </LinearLayout>
这里添加了一个 Button 元素,并在 Button 元素的内部增加了几个属性。 android:id 是给当前的元素定义一个唯一标识符,之后可以在代码中对这个元素进行操作。 你可能会对@+id/button_1 这种语法感到陌生,但如果把加号去掉,变成@id/button_1,这你就会觉得有些熟悉了吧,这不就是在 XML 中引用资源的语法吗,只不过是把 string 替换成了 id。是的,如果你需要在 XML 中引用一个 id,就使用@id/id_name 这种语法,而如果你需要在 XML 中定义一个 id,则要使用@+id/id_name,android:layout_height 指定了当前元素的高度,这里使用 wrap_content,表示当前元素的高度只要能刚好包含里面的内容就行。 android:text 指定了元素中显示的文字内容。
FirstActivity->onCreate()
public class FirstActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.first_layout); } }
这里调用了 setContentView()方法来给当前的活动加载一个布局,而在setContentView()方法中,我们一般都会传入一个布局文件的 id。
所有的活动都要在 AndroidManifest.xml 中进行注册才能生效,那么我们现在就打开 AndroidManifest.xml 来给 FirstActivity 注册吧
活动的注册声明要放在<application>标签内,这里是通过<activity>标签来对活动进行注册的。首先我们要使用 android:name 来指定具体注册哪一个活动,-interchange-newline"> 那么这里填入的.FirstActivity 其实这不过就是 com.example.activitytest.FirstActivity 的缩写而已。
在<activity>标签的内部我们 加入了 <intent-filter>标签,并在这个标签里添加了 <action android:name=
"android.intent.action.MAIN" />和<category android:name="android.intent.category.LAUNCHER" />这两句声明如果你想让 FirstActivity 作为我们这个程序的主活动,即点击桌面应用程序图标时首先打开的就是这个活动,那就一定要加入这两句声明。
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.first_layout); }
其中 requestWindowFeature(Window.FEATURE_NO_TITLE)的意思就是不在活动中显示标题栏,注意这句代码一定要在 setContentView()之前执行,不然会报错。
Toast 是 Android 系统提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息通知给用户,这些信息会在一段时间后自动消失,并且不会占用任何屏幕空间,首先需要定义一个弹出 Toast 的触发点,正好界面上有个按钮,那我们就让点击这个按钮的时候弹出一个 Toast 吧。在 onCreate()方法中添加代码:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.first_layout); Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(FirstActivity.this, "You clicked Button 1", Toast.LENGTH_SHORT).show(); } }); }
makeText()方法需要传入三个参数。第一个参数是 Context,也就是 Toast 要求的上下文,由于活动本身就是一个 Context 对象,因此这里直接传入 FirstActivity.this即可。第二个参数是 Toast显示的文本内容,第三个参数是 Toast显示的时长,有两个内置常量可以选择 Toast.LENGTH_SHORT 和 Toast.LENGTH_LONG。
1)显示Inent
second_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/button_2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 2" /> </LinearLayout>
SecondActivity
最后在 AndroidManifest.xml 中为 SecondActivity 进行注册。
由于 SecondActivity 不是主活动,因此不需要配置<intent-filter>标签里的内容,注册活动的代码也是简单了许多。 现在第二个活动已经创建完成,剩下的问题就是如何去启动这第二个活动了
有多个构造函数的重载,其中一个是 Intent(Context packageContext, Class<?> cls)。这个构造函数接收两个参数,第一个参数 Context 要求提供一个启动活动的上下文,第二个参数 Class 则是指定想要启动的目标活动, 通过这个构造函数就可以构建出 Intent 的“意图”。
修改 FirstActivity 中按钮的点击事件
2)隐式Intent
通过在<activity>标签下配置<intent-filter>的内容, 可以指定当前活动能够响应的 action和 category,打开 AndroidManifest.xml,添加如下代码:
在 <action>标签中我们指明了当前活动可以响应 com.example.activitytest.ACTION_START 这个 action,而<category>标签则包含了一些附加信息,更精确地指明了当前的活动能够响应的 Intent 中还可能带有的 category。只有<action>和<category>中的内容同时能够匹配上 Intent 中指定的 action 和 category 时,这个活动才能响应该 Intent。
修改 FirstActivity 中按钮的点击事件
android.intent.category.DEFAULT 是一种默认的 category,在调用startActivity()方法的时候会自动将这个 category 添加到 Intent 中
每个 Intent 中只能指定一个 action,但却能指定多个 category。目前我们的 Intent 中只有一个默认的 category
修改 FirstActivity 中按钮的点击事件
此时,程序运行会出错,因为我们刚刚在 Intent 中新增了一个 category,而 SecondActivity 的<intent-filter>标签中并没有声明可以响应这个 category,所以就出现了没有任何活动可以响应该 Intent 的情况
3)更多隐式Intent
调用系统的浏览器来打开这个网页
我们首先指定了 Intent 的 action 是 Intent.ACTION_VIEW,这是一个 Android 系统内置的动作,其常量值为 android.intent.action.VIEW。然后通过 Uri.parse()方法,将一个网址字符串解析成一个 Uri 对象,再调用 Intent 的 setData()方法将这个 Uri 对象传递进去
1)Intent 中提供了一系列 putExtra()方法的重载,可以把我们想要传递的数据暂存在 Intent 中,启动了另一个活动后,只需要把这些数据再从Intent 中取出就可以了
然后我们在 SecondActivity 中将传递的数据取出,并打印出来
2)Activity 中还有一个 startActivityForResult()方法也是用于启动活动的,但这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。
startActivityForResult()方法接收两个参数,第一个参数还是 Intent,第二个参数是请求码,用于在之后的回调中判断数据的来源。我们还是来实战一下, 修改 FirstActivity 中按钮的点击事件,代码如下所示:
这里我们使用了 startActivityForResult()方法来启动 SecondActivity,请求码只要是一个唯一值就可以了,这里传入了 1。接下来我们在 SecondActivity 中给按钮注册点击事件,并在点击事件中添加返回数据的逻辑,代码如下所示:
setResult()这个方法非常重要,是专门用于向上一个活动返回数据的。 setResult()方法接收两个参数,第一个参数用于向上一个活动返回处理结果,一般只使用 RESULT_OK 或RESULT_CANCELED 这两个值,第二个参数则是把带有数据的 Intent 传递回去, 然后调用了 finish()方法来销毁当前活动。
由于我们是使用 startActivityForResult()方法来启动 SecondActivity 的,在 SecondActivity被销毁之后会回调上一个活动的 onActivityResult()方法,因此我们需要在 FirstActivity 中重写这个方法来得到返回的数据,如下所示:
如果用户在 SecondActivity 中并不是通过点击按钮,而是通过按下Back 键回到 FirstActivity, 这样数据不就没法返回了吗?没错,不过这种情况还是很好处理的,我们可以通过重写 onBackPressed()方法来解决这个问题