第一行代码Android第二章读书笔记
- Activity
1.1 手动创建活动
1.2 Toast和Menu/销毁活动 - Intent
2.1 显示/隐式
2.2 传递/返回数据 - 活动的生命周期
3.1 返回栈
3.2 活动的生命周期/启动模式
3.3 活动被回收了怎么办?
3.4 一种知晓当前活动的方法
3.5 一种随时随地退出程序的方法 - 小结
1 Activity
活动的个人定义:一种可以和用户进行交互的窗口。
打开一个安卓应用,本质就是使用各种各样的活动和用户进行交互。我把它类比为桌面图形开发中的窗口,如MFC中的Dialog窗口。
1.1手动创建活动
流程:
- 创建一个无活动的项目
- 在Java下的包中,new一个activity
- 在res目录下,新建(或自动创建)一个layout文件夹
- 在layout目录下新建(或者自动创建)一个layout源文件
- 对layout源文件进行修改
- 在AndroidManifest文件中进行注册
关键点:
-1-在activity的注册中,要配置action和category,使之成为主活动
...
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
...
-2-一个activity对应一个layout,该代码写在onCreate中
setContentView(R.layout.first_layout);
-3-如书中在layout中添加了一个按钮,那么在activity的代码中也要new一个Button对象,并修改其内部的事件
1.2 Toast和Menu
Toast的个人定义:一个短暂的提示,悬浮出现。例如……
您正在使用2G/3G/4G网络
使用示例:
...//写在onCreate中
Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Toast.makeText(FirstActivity.this, "You clicked me! ", Toast.LENGTH_SHORT).show();
finish();
...
可以看到,主要的用法就是Toast.makeText(上下文, "String", 时间长度)
,时间长度可以使用内置的长度。
另外,中间的finish();
可以销毁该活动,类似于按下back键。但是,按下back键会先进行过场动画,再销毁;而使用finish();
则直接销毁。详见。
Menu的个人定义:一个菜单栏。例如最常见的即右上角的···
。
用法示例:
首先在res目录下new一个名为menu的文件夹,然后在其中new一个目录源文件。内容修改如下:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add"/>
<item
android:id="@+id/remove_item"
android:title="Remove"/>
</menu>
每一个item对应一个选项。
其后,在activity中,重写onCreateOptionsMenu()方法。重写的快捷键是Ctrl+O。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
继续重写onOptionsSelected():
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
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;
}
Menu使用item.getItemId()获取clicked item 的id。
(顺带一提,从notepad++进化到Android Studio感觉好像从汉朝进化到了2017年的上海。)
2 Intent
intent的个人定义:一个通道,用来启动另一个Activity(就目前进度而言)。
2.1显式/隐式
显式
在新建了一个活动(SecondActivity)之后,对按钮内的onClick()进行修改。
Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
如此,点击按钮以后,将显式地使用“意图”来打开活动。
隐式:
隐式的Intent,指定了一系列的action和category,只有同时满足两者才能完成调用。有点“对号入座”的意思。
在Manifest文件中对SecondActivity标签进行如下修改:
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
在<intent-filter>
添加了关于action和category的信息。从标签名也能看得出来,这是用于传递Intent信息的。
要使用隐式的Intent,要对按钮的onClick()进行如下修改:
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent("com.example.activityTest.ACTION_START");
startActivity(intent);
}
});
由于我们的SecondActivity使用了默认的Category,所以没有给Intent附加有关Category的信息。可以这么做:
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent("com.example.activityTest.ACTION_START"); Intent.addCategory("com.example.activityTest.MY_CATEGORY");
startActivity(intent);
}
});
光是这样还不能正常工作,要在SecondActivity中附加这样一条category标签<category android:name="com.example.activityTest.MY_CATEGORY"/>
写在<intent-filter>
标签里。
使用隐式Intent访问网页
隐式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.bing.com"));
startActivity(intent);
}
});
Intent.ACTION_VIEW是一个内置动作,其常量值为android.intent.action.VIEW,然后通过Uri.perse()方法,将一个网址字符串解析成一个Uri对象,再调用setData方法将这个Uri对象传递进去。
点击该按钮时,将直接打开系统浏览器,访问指定网址。
另外,假设我们新建了一个Activity,打算用该活动打开特定的网页,那么我们还可以在<intent-filter>
内添加<data>
标签,以实现过滤的目的。详见原书P47或这里。
另一个有趣的例子:使用Intent调用系统拨号界面:
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);
}
});
传递数据
在使用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.putExtra( "extra_data", data);
startActivity(intent);
}
});
这里的putExtra()
接受两个数据,第一个是key,第二个是传递的数据,有多重重载方式。
然后我们可以在SecondActivity中取出数据:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity",data);
}
这里将Intent传来的额外信息,按key获取之后,用log打印了出来。getXxxExtra()
有很多种方法,以此类推。
返回数据
如果要返回数据给上一个活动,要使用startActivityForResult()
来启动活动。该方法接受两个参数,第一个还是Intent,第二个是请求码,举例:
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(intent,1 );
}
});
以上是在FirstActivity中设定好的按钮事件。在SecondActivity中也设定一个按钮事件:
Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent();
intent.putExtra("data_return", "Hello FirstActivity");
setResult(RESULT_OK, intent);
finish();
}
});
其中的关键就是setResult()
用于向上一个活动返回数据。该方法接受两个参数,第一个是返回处理结果,一般只使用RESULT_OK和RESULT_CANCELED这两个值。第二个参数用于将带数据的Intent传递回去。然后调用finish()
来销毁当前活动。
此时,来自SecondActivity的Intent回到了FirstActivity,重写onActivityResult()
来得到返回的参数:
@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:
}
}
可以看到,流程是这样的:
1. 使用startActivityForResult(intent, 1);
指定一个请求码。
2. 使用setResult(RESULT_OK, intent);
返回一个执行结果。
3. 在onActivityResult(int requestCode, int resultCode, Intent intent)
中对每一个请求码,按照其返回结果做出相应处理。
这里还有一点,假如用户在SecondActivity中没有点击按钮销毁程序,而是直接使用back键(或者轻触返回——魅族大法好),就不会调用setResult(RESULT_OK, intent);
方法,就无法返回数据。对此的解决方法是,在SecondActivity中重写onBackPressed()
方法,代码如下所示:
@Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("data_return", "Hello FirstActivity");
setResult(RESULT_OK, intent);
finish();
}
这样,即使用户使用back键返回,也会传递数据给FirstActivity。
3 活动的生命周期
Android使用任务(Task)来管理活动,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。
3.1 返回栈
这部分的内容书上说的很详细,就不一一展开了。详见。
3.2 活动的生命周期/启动模式
书上很详细。或见此。
3.3 活动被回收了怎么办?
重写onSaveInstanceState()
回调方法,该方法保证活动在被回收之前一定会被调用。用法如下:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString("data_key", tempData);
}
可以看到,这里也是使用key-value对应的。要使用这里的数据,要在onCreate(Bundle savedInstanceState)
中填入savedInstanceState类(自动给你填好了),然后在方法中调用savedInstanceState.getString()
:
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
if(savedInstanceState != null){
String tempdata = savedInstanceState.getString("data_key");
Log.d("SecondActivity", tempdata);
}
}
3.4 一种知晓当前活动的方法
本书中讲述了一种知晓当前所处哪一个活动的方法。
很简单,就是新建一个BaseActivity
类,直接继承我们之前用的AppCompatActivity
类,并且重写其onCreate()
方法,在其中使用Log.d("TAG", getClass().getSimpleName());
静态方法直接打印出当前活动名即可。
3.5 一种随时随地退出程序的方法
其思路是新建一个类,用一个专门的List< Activity >容器来管理所有活动,并且写一个静态的add()
和remove()
方法,还有一个终极finishAll()
方法。
在我们的BaseActivity
类中,重写onCreate()
方法,使其调用add()
方法;重写onDestory()
方法,使其调用remove()
方法。当想要完全关闭程序的时候,直接调用finishAll()
方法就可以了。
4 小结
这是《第一行代码Android 第二版》的读书笔记,本书写的非常通俗易懂,对新人十分友好,我的读书笔记几乎就是原书的摘抄——我认为这样做效率不高,又兼这是本人所写第一篇博客,行文组织方面尚不熟悉,以后将会用更加概括性的语言来叙述,并适当减少示例代码。
读书笔记从第二章开始,第一张过于琐碎,讲出来反而没有书上清楚,故不提。