ANDROID 开发一个新闻阅读器 2章 启动页
1.
功能描述
这一讲中我们将先实现一个开启页,通常我们在许多应用中都会看到开启页,当你点击一个应用后会先出现应用的 LOGO和一些开发团队的信息,当然同时后台可能正在运行一些启动逻辑。一个开启页面一般显示3秒左右的时间,太长会让用户产生应用是不是无法启动这样的疑惑。
例如像下面这款软件的启动页:

页面中介绍了应用的名字,显示了应用的图标来加深使用者的印象,下方的loading 提醒用户应用正在运行中。
现在我们就开发一个启动页,并让其顺利进入到下一个页面:
2.
界面布局
在layout 目录下创建 news_open.xml 用来作为页面对应的布局文件
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" //xml 描述文件的命名空间
3 android:orientation="vertical" //页面走向 垂直
4 android:layout_width="fill_parent" //宽 填满整个上层界面组件
5 android:layout_height="fill_parent" //高 填满整个上层界面组件
6 android:background="@drawable/open_bg"> //背景 显示一张图片
7 </LinearLayout>
首先定义一个LinearLayout, 将其背景设置为一张图片 open_bg,该图片会存放在 drawable目录下。
这里我们要再次说明下drawable目录,由于Android作为开源的系统被广大的手机商所使用,也造成了搭载硬件规格的不同,其突出的一点就是各个手机屏幕的大小和分辨率不一样,为了解决这个问题,google 把原先的drawable目录改成了支持

drawable-hdpi,drawable-ldpi,drawable-mdpi 这三种目录。 三个目录下分别对应高,中,低三种分辨率,当然这只是针对一些对图像要求特别高的应用,例如游戏。我们可以把图片都放置在 drawable-hdpi 这个目录下,当然你也可以继续沿用 drawable 目录。
考虑到一些开发者可能第一次接触Android,这里我们也介绍一下上面涉及到的几个属性
l android:orientation
页面走向属性: vertical 垂直,
horizontal 横向
l android:layout_width
宽度设置: fill_parent 宽度填满整个上层界面组件
wrap_content
自适应改变这个界面组件的宽度
l android:layout_height
高度设置: fill_parent 高度填满整个上层界面组件
wrap_content
自适应改变这个界面组件的高度
l android:backaround
组件背景:@color/red 显示定义在color资源文件中的颜色作为背景
@drawable/pic 显示定义在 drawable 目录中的图片作为背景
layout 文件创建完后,就要开始把控件一个一个塞进去了。
² ImageView :显示这个应用的图标
² TextView:显示应用的名字
² ProgressBar:loading 动画显示
² TextView: loading提示信息
下面是将控件全部加进去后的 news_open.xml 文件代码:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent"
6 android:background="@drawable/open_bg">
7
8 <RelativeLayout android:layout_width="fill_parent"
9 android:layout_height="fill_parent" > //相对位置页面布局,并且充满整个上层界面组件
10 <LinearLayout android:layout_width="fill_parent"
11 android:layout_height="wrap_content"
12 android:orientation="vertical"
13 android:paddingTop="50dip" //和上方间距50dip的距离
14 android:gravity="top|center_horizontal"> //在上层界面的布局中处在上方的位置并且横向居中
15 <ImageView android:id="@+id/open_app_img" //声明一个ImageView 的控件, id为open_app_img
16 android:layout_width="wrap_content" //宽 自适应
17 android:layout_height="wrap_content" //高 自适应
18 android:layout_gravity="center_horizontal" //位置布局 横向居中
19 android:src="@drawable/open_app_img" /> //图片资源显示的内容为存放在 drawable 下的的 open_app_img
20 <TextView android:layout_width="wrap_content" //声明一个TextView 的控件
21 android:layout_height="wrap_content"
22 android:text="@string/app_name" //该TextView显示的内容为string文件下的 app_name 字段
23 android:textStyle="bold" //字体样式
24 android:textSize="20dip" //字体大小
25 android:textColor="@color/black" /> //字体颜色
26 </LinearLayout>
27
28 <LinearLayout android:layout_width="fill_parent"
29 android:layout_height="fill_parent"
30 android:paddingBottom="20dip"
31 android:gravity="bottom|center_horizontal">
32 <ProgressBar android:id="@+id/openProgressBar" //进度条控件,声明ID
33 android:layout_width="28dip" //定义该进度动画的宽和高都为28dip
34 android:layout_height="28dip"
35 android:indeterminateDrawable="@drawable/progress_spin" //定义在drawable 下的文件 progress_spin.xml 里面描述了整个进度条的样式
36 android:indeterminateOnly="true"
37 android:indeterminateBehavior="repeat" //动画不断重复
38 android:indeterminateDuration="3500" /> //动画运作时间
39 <TextView android:id="@+id/progressText"
40 android:layout_width="wrap_content"
41 android:layout_height="wrap_content"
42 android:text="loading..."
43 android:textStyle="bold"
44 android:textColor="@color/black" />
45 </LinearLayout>
46 </RelativeLayout>
47 </LinearLayout>
48
我们再看下progressbar的样式文件 progress_spin.xml
1 <?xml version="1.0" encoding="utf-8" ?>
2 //声明是个旋转的loading 样式
3 <rotate xmlns:android="http://schemas.android.com/apk/res/android"
4 android:pivotX="50%"
5 android:pivotY="50%"
6 android:fromDegrees="0"
7 android:toDegrees="360">
8 <shape // 样式定义成不断旋转的圆形
9 android:shape="ring"
10 android:innerRadiusRatio="4"
11 android:thicknessRatio="5.333"
12 android:useLevel="false">
13 <size // 大小
14 android:width="18dip"
15 android:height="18dip" />
16 <gradient // 动画过程
17 android:type="sweep"
18 android:useLevel="false"
19 android:startColor="#006688cc"
20 android:centerColor="#886688cc"
21 android:endColor="#ff6688cc"
22 android:centerY="0.50" />
23 </shape>
24 </rotate>
这样表现层的代码基本完成了,下面就让我们看看后台的代码
3.
后台逻辑层
我们先来看 openActivity.java 文件
1 import android.app.Activity;
2 import android.os.Bundle;
3
4 public class openActivity extends Activity{
5
6
7 @Override
8 public void onCreate(Bundle savedInstanceState) {
9 super.onCreate(savedInstanceState);
10 setContentView(R.layout.news_open);
11 }
12
13 }
14
基本上没太多多余的代码,只要注意 setContentView 中set的是 news_open.xml 的 View。
需要注意的是,创建项目的时候 默认的入口Activity 是我们创建时定义的 mainActivity.java。
所以
AndroidManifest.xml 要修改成:
1
2 <?xml version="1.0" encoding="utf-8"?>
3 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
4 package="com.thinkland.demo.mnr"
5 android:versionCode="1"
6 android:versionName="1.0">
7 <application android:icon="@drawable/icon" android:label="@string/app_name">
8 <activity android:name=".openActivity" //这里改成 openActivity
9 android:label="@string/app_name">
10 <intent-filter>
11 <action android:name="android.intent.action.MAIN" />
12 <category android:name="android.intent.category.LAUNCHER" />
13 </intent-filter>
14 </activity>
15 <activity android:name=".mainActivity" /> //原先的 mainActivity可以另外定义成一个Activity
16 </application>
17 <uses-sdk android:minSdkVersion="3" />
18
19 </manifest>
运行模拟器可以看到如下的效果:

这样一个开启页面已经基本完成,不过可能你会问,那如何跳转去下一个页面呢?
接下来让我们对 openActivity.java 做些许改动,使其能跳转去下一个页面。
openActivity.java 定义如下:
1 import com.thinkland.demo.mnr.common.MyNewsReaderConstant;
2
3 import android.app.Activity;
4 import android.content.Intent;
5 import android.os.Bundle;
6 import android.os.Handler;
7 import android.os.Message;
8
9 public class openActivity extends Activity{
10
11 protected static final int thread1 = 0x2211;
12
13 @Override
14 public void onCreate(Bundle savedInstanceState) {
15 super.onCreate(savedInstanceState);
16 setContentView(R.layout.news_open);
17
18 //开启一个子线程
19 Thread t1 = new Thread(new initialOpen());
20 t1.start();
21 }
22
23 public class initialOpen implements Runnable{
24
25 //运行子线程,每次都等待2秒,然后调用gotoNextActivity()方法
26 public void run() {
27 try {
28 Thread.sleep(2000);
29 } catch (InterruptedException e) {
30 // TODO Auto-generated catch block
31 e.printStackTrace();
32 }
33 gotoNextActivity();
34
35 }
36 //发送消息 thread1,通知 Handler 消息接收器 messageListener
37 public void gotoNextActivity(){
38
39 Message m1 = new Message();
40 m1.what = thread1;
41
42 messageListener.sendMessage(m1);
43 }
44 }
45
46 //声明一个消息接受器 messageListener, 接受到消息后判断,如果是thread1的话开始新的Acticity mainActivity.
47 private Handler messageListener = new Handler(){
48
49 public void handleMessage(Message msg){
50 switch(msg.what){
51 case thread1:
52 Intent aitent = new Intent(openActivity.this, mainActivity.class);
53 Bundle b1 = new Bundle();
54 b1.putString(MyNewsReaderConstant.OPEN_GOTO_VALUE, "This message is form openActivity");
55 aitent.putExtras(b1);
56
57 startActivity(aitent);
58 break;
59 }
60 }
61 };
62
63 }
如上面代码中的注释,首先开启了一个线程,作用就是等待2秒然后发送1个消息给消息接收器,然后接受器再接受到这个消息后开启一个新的 Activity。
这里我们首先要介绍下 消息接受器 Handler 和 消息类 Message。由于Android 的子线程是不允许修改主线程的 View。这样就限制了很多的逻辑的实现,为了解决这个问题,google提供了Message 这种方式,我们可以声明一个Message 对象,然后通过Message来发送信息,在主线程中再定义一个接受器 Handler 用来接受这些消息,并判断内容,具体实现如下。
消息接受器:
1 private Handler messageListener = new Handler(){
2
3 public void handleMessage(Message msg){
4 switch(msg.what){
5 case thread1:
6 //一些操作
7 break;
8 }
9 }
10 };
消息发送:
1 Message m1 = new Message();
2 m1.what = 标示符; //通常采用 类似int thread1 = 0x2211 保证唯一性
3 messageListener.sendMessage(m1); //发送出去
当然,消息也可以存放一个对象并发送,具体如下:
1 Message m2 = messageListener.obtainMessage(0, 存放的对象);
2 m2.what =标示符;
3 messageListener.sendMessage(m2);
而接受的时候则可以通过如下方法获取该对象
1 private Handler messageListener = new Handler(){
2
3 public void handleMessage(Message msg){
4 实例化该对象 = (声明对象) msg.obj; //例如传了个List 那就是 List alist = (List)msg.obj
5 switch(msg.what){
6 case thread1:
7 //一些操作
8 break;
9 }
10 }
11 };
而开启一个新的Activity则执行如下的逻辑:
1 Intent aitent = new Intent(openActivity.this, mainActivity.class);
2 Bundle b1 = new Bundle();
3 b1.putString(MyNewsReaderConstant.OPEN_GOTO_VALUE, "This message is form openActivity");
4 aitent.putExtras(b1);
5 startActivity(aitent);
我们首先声明一个 Intent 对象
同时也声明了一个Bundle 对象,并且往中的KEY MyNewsReaderConstant.OPEN_GOTO_VALUE 中放入了值 “This
message is form openActivity”, 而这就是 2个Activity 之间传递值的方式。最后将该Bundle对象put进Intent, 调用方法
startActivity(Intent对象).
需要说明的是,MyNewsReaderConstant 这个类是笔者用来专门存放一些常量的的,这样做会比较方便后期的维护。这个class放在 COMMON\这个目录下,其内容如下:
1 public class MyNewsReaderConstant {
2
3 public static String OPEN_GOTO_VALUE = "openGotoValue";
4
5 }
然后我们再在 mainActivity.java 做些改动,具体如下:
1 import com.thinkland.demo.mnr.common.MyNewsReaderConstant;
2
3 import android.app.Activity;
4 import android.content.Intent;
5 import android.os.Bundle;
6 import android.widget.Toast;
7
8 public class mainActivity extends Activity {
9 /** Called when the activity is first created. */
10 @Override
11 public void onCreate(Bundle savedInstanceState) {
12 super.onCreate(savedInstanceState);
13 setContentView(R.layout.main);
14
15 Intent mainIntent = getIntent(); //获取Intent 对象
16 Bundle mainBundle = mainIntent.getExtras(); //获取Intent中的Bundle
17 if(mainBundle != null){
18 String testStr = mainBundle.getString(MyNewsReaderConstant.OPEN_GOTO_VALUE);
19 //如果该Bundle不为空,查看MyNewsReaderConstant.OPEN_GOTO_VALUE里是否有值,如果有,通过Toast 的方式显示出来
20 Toast.makeText(this, testStr, Toast.LENGTH_SHORT).show();
21 }
22 }
23 }
24
Toast 类似与一个弹出的提示消息,其具体写法
1 Toast.makeText(Context 对象, 显示的内容, 显示时间长短).show();
显示时间长短: Toast.LENGTH_SHORT 或者 Toast.LENGTH_LONG
好了现在再让我们运行一下程序
界面1:
界面2:

可以看到 界面2上出现里一个小框,这个就是Toast框,而里面的值就是我们在2个Activity 之前传递的。
不过现在我们又发现了一个新的问题,但我点击模拟器上的BACK键,画面会到了启动页,然后就一直在启动页了,所以我们还在在启动页的逻辑里加上一小段代码来避免这种情况,具体如下:
在openActivity.java
最后重写onPause方法
1 @Override
2 public void onPause() {
3 super.onPause();
4 this.finish();
5 }
每次当一个新的Activity开启的时候就将开启页的 Activity 关掉,也就是调用 finish()方法。这时候页面就不会回到开启页面,而是直接回到了手机home页。

现在一个完整的开启页就完成了。
程序包地址:http://u.115.com/file/f5a50dbe54#MyNewsReader_L5.zip
posted on 2011-04-07 14:14 thinkland001 阅读(225) 评论(0) 收藏 举报
浙公网安备 33010602011771号