Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2618424
  • 博文数量: 315
  • 博客积分: 3901
  • 博客等级: 少校
  • 技术积分: 3640
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-08 15:32
个人简介

知乎:https://www.zhihu.com/people/monkey.d.luffy Android高级开发交流群2: 752871516

文章分类

全部博文(315)

文章存档

2019年(2)

2018年(1)

2016年(7)

2015年(32)

2014年(39)

2013年(109)

2012年(81)

2011年(44)

分类: Android平台

2013-06-01 14:17:06

    本学习篇,主要学习电子书籍,跟着作者开发一个BMI“人体健康计算器”,在这个感谢书籍作者,感谢网友的分享。同时自己也记录以下自己这两天学习android的过程,相信对今后自己要走的路是有帮助的。
    我们需要怀着一颗坚毅的心,勇敢的走下去 ==== 关键是要耐得住寂寞,(*^__^*) 嘻嘻...

    下面就开始了,讲诉以下两天看这边书的JingLi【工程开发描述】,过程省去了android开发环境的搭建,之前已经搭建好,这里稍微捣鼓了下就可以用了。其中关于整个工程目录的分析,作者已经分析的很好了,当然自己看了一遍,基本上了gai,不过神速不一定就是明白,所以自己还是半斤八两,入门而已。
    
    首先开发程序需要了解该应用程序所要实现的功能,之后就是功能之后的基本界面demo,界面布局当然随之而来;该程序是一个计算BMI值的小程序,类似计算器;关于BMI解释【来自百度百科】:
    BMI指数(身量指数,简称体质指数又称,英文为Body Mass Index,简称BMI),是用体重公斤数除以身高米数平方得出的数字,是目前国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。主要用于用途,当我们需要比较及分析一个人的体重对于不同高度的人所带来的健康影响时,是一个中立而可靠的指标。
体重指数, 男性, 女性
过轻:低于20;低于19
适中:20-25; 19-24
过重:25-30; 24-29
肥胖:30-35; 29-34
非常肥胖, 高于35, 高于34
专家指出最理想的体重指数是22。
    知道了BMI,我们就知道了需要的基本的控件:体重输入编辑框、身高输入编辑框、【计算】按钮,BMI值文本显示控件(TextView);当然还可以显示建议的文字,所以还需要建议文本显示控件(TextView);这里我多增加了一个activity用于显示应用程序启动动画,觉得好玩,(*^__^*) 嘻嘻...

    新建一个android工程后主要需要关注AndroidManifest.xml文件、layout/下的xml文件、以及values/下的xml文件,当然src/下的java文件是整个逻辑和实现。我的android工程目录主要如下,一些是新增的:

    Report是新增的activity,report.xml、advice.xml、report.xml都是新增的,作者的本意是新建一个activity,然后点击计算按钮的时候,跳转到另一个activity去显示结果;这里我将该activity改为了开机画面显示的activity,显示了几张图片之后,直接跳转到计算页面。应用程序图片也进行了修改,具体修改方式就是打开AndroidMainifest.xml文件,工程左下角方向有很多选项:

点击Application选项,可以看到icon选项,之后可以选择本地图片【image】,工程会自动生成各种尺寸的应用程序icon:

    
    图标啥的不重要,关键是其它的。布局,布局得想好,不然界面很丑,我们80后还是喜欢非主流的,嘿嘿.   之前说过的文本编辑框、按钮,TextView,都是安装作者的来的。这里要注意的就是,可能你新建的工程生成的layout/xxxx.xml文件并不是垂直布局的,可能类似:
    xmlns:tools=""
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >


            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />




    这种相对布局,对刚入门的我不太明白,为了早点出效果,我将其改为了作者的布局,原先的代码可以删掉或者全部注释掉,自己重新添加布局代码:
    activity_bmi.xml 

点击(此处)折叠或打开

  1. <LinearLayout xmlns:android=""
  2.     android:layout_width="fill_parent"
  3.     android:layout_height="fill_parent"
  4.     android:orientation="vertical" >

  5.     <!--
  6.          <TextView
  7.         android:layout_width="fill_parent"
  8.         android:layout_height="wrap_content"
  9.         android:text="@string/hello_world" />
  10.     -->

  11.     <TextView
  12.         android:layout_width="fill_parent"
  13.         android:layout_height="wrap_content"
  14.         android:text="@string/height" />

  15.     <!-- android:hint是输入提示 -->
  16.     <EditText
  17.         android:id="@+id/height"
  18.         android:layout_width="fill_parent"
  19.         android:layout_height="wrap_content"
  20.         android:hint="@string/bmi_height_tip"
  21.         android:inputType="number"
  22.         android:text="" />

  23.     <TextView
  24.         android:layout_width="fill_parent"
  25.         android:layout_height="wrap_content"
  26.         android:text="@string/weight" />

  27.     <!-- android:inputType替代了android:numeric="integer"消除了警告 -->
  28.     <EditText
  29.         android:id="@+id/weight"
  30.         android:layout_width="fill_parent"
  31.         android:layout_height="wrap_content"
  32.         android:hint="@string/bmi_weight_tip"
  33.         android:inputType="number"
  34.         android:text="" />

  35.     <Button
  36.         android:id="@+id/submit"
  37.         android:layout_width="fill_parent"
  38.         android:layout_height="wrap_content"
  39.         android:text="@string/bmi_btn" />

  40.     <TextView
  41.         android:id="@+id/result"
  42.         android:layout_width="fill_parent"
  43.         android:layout_height="wrap_content"
  44.         android:text="" />

  45.     <TextView
  46.         android:id="@+id/suggest"
  47.         android:layout_width="fill_parent"
  48.         android:layout_height="wrap_content"
  49.         android:text="" />

  50. </LinearLayout>
    从这个BMI计算器界面布局文档来看,有几点需要注意:
    1> android:id这个属性,成为了控件的标识,类似一个变量地址,通过变量我们就可以取得控件,就是这样,我是这么想的。
 
2> android:text,文本属性,对于TextView和Button而言,我们可以直接进行文本赋值,但是为了更好的封装性和模块之间的耦合度,我们将控件需要显示的文本记录到values/strings.xml文件中,用的时候直接通过 @string/表示符id 获得很方便的。values/xxx.xml后面写到。
 3
android:hint="@string/bmi_weight_tip" 和 android:inputType="number" ,前者是文本编辑框的文本提示,当收到输入时,自动消失;哎哟,效果还不多;后者是文本编辑框的输入类型限定,这里限定为数字,因此字母啥的,木有用啊,到底是肿么一回事啊....  顺便说下LinearLayout,初学比较容易的布局方式,我喜欢,嘿嘿...

    基本布局都知道了,那么顺便来看下按钮控件显示的文本来源吧-就是values/strings.xml了:
    strings.xml

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>

  3.     <string name="app_name">BMI</string>
  4.     <string name="action_settings">Settings</string>
  5.     <string name="height">身高</string>
  6.     <string name="weight">体重</string>
  7.     <string name="bmi_btn">计算BMI值</string>
  8.     <string name="bmi_result">你的BMI值是</string>
  9.     
  10.     <string name="bmi_height_tip">请输入数字(cm)</string>
  11.     <string name="bmi_weight_tip">请输入数字(kg)</string>
  12.     <string name="input_tip">亲,请输入哈!</string>
  13.     
  14.     <string name="ok_label">确认</string>
  15.     <string name="home_page">首页</string>
  16.     <string name="home_page_url">http://www.androidbmi.googlecode.com</string>
  17.     
  18.     <string name="about_title">关于 Android BMI</string>
  19.     <string name="about_msg">感谢支持n感谢作者n感谢所有关心和帮助过我的人</string>
  20.     <string name="thanks">感谢使用</string>

  21. </resources>
    这里我把,后续用到的一些文本一块给出了。原理都一样,不用惊慌,不过我一向比较着急,这样不好,真不好...
    作者还说了,可以自己新建一个存放string的xml文件,名字随意,这里我新建了advice.xml report.xml文件,advice.xml文件用汉语存放给用户的建议信息,report.xml文件用于存在Report这个新增的activity的一些信息:
    
    这里的activity之前是用过显示计算后的报告的,这里我改成开机动画,所以名字啥的,我已经懒到不改了。这样也不好,实际中最好严格要求自己,so......
    advice.xml

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.     <string name="advice_light">你该多吃点</string>
  4.     <string name="advice_average">你的体型很棒哦!</string>
  5.     <string name="advice_heavy">你该减肥了</string>
  6. </resources>
    这样基本算是具备开发BMI计算器的条件了(刚才还想说具备要求了,唉,这措辞都不会了,神马口才丫,汗!!!),那就直接上吧,看实际代码,动画部分最后才说,毕竟动画神马的都是外表。
    
    好在android一个小的应用程序文件不多,代码也不算是特别多。Look...
    BMI.java

点击(此处)折叠或打开

  1. package com.demo.android.bmi;

  2. import java.text.DecimalFormat;

  3. import android.net.Uri;
  4. import android.os.Bundle;
  5. import android.app.Activity;
  6. import android.app.AlertDialog;
  7. import android.content.DialogInterface;
  8. import android.content.Intent;
  9. import android.content.SharedPreferences;
  10. import android.util.Log;
  11. import android.view.Menu;
  12. import android.view.MenuItem;
  13. import android.view.View;
  14. import android.widget.Button;
  15. import android.widget.EditText;
  16. import android.widget.TextView;
  17. import android.widget.Toast;

  18. public class Bmi extends Activity {

  19.     @Override
  20.     protected void onCreate(Bundle savedInstanceState)
  21.     {
  22.         super.onCreate(savedInstanceState);
  23.         setContentView(R.layout.activity_bmi);

  24.         findViews();
  25.         restorePrefs();
  26.         setListeners();
  27.     }

  28.     @Override
  29.     protected void onStop()
  30.     {
  31.         super.onStop();
  32.         SharedPreferences settings = getSharedPreferences(PREF, 0);
  33.         settings.edit()
  34.         .putString(PREF_HEIGHT, field_height.getText().toString())
  35.         .commit();
  36.     }

  37.     public void findViews()
  38.     {
  39.         button_calc = (Button)findViewById(R.id.submit);
  40.         field_height = (EditText)findViewById(R.id.height);
  41.         field_weight = (EditText)findViewById(R.id.weight);
  42.         view_result = (TextView)findViewById(R.id.result);
  43.         view_suggest = (TextView)findViewById(R.id.suggest);
  44.     }

  45.     private void restorePrefs()
  46.     {
  47.         SharedPreferences settings = getSharedPreferences(PREF, 0);
  48.         String pref_height = settings.getString(PREF_HEIGHT, "");
  49.         if (!"".equals(pref_height))
  50.         {
  51.             field_height.setText(pref_height);
  52.             field_weight.requestFocus();
  53.         }
  54.     }

  55.     public void setListeners()
  56.     {
  57.         button_calc.setOnClickListener(calcBMI);
  58.     }

  59.     private Button.OnClickListener calcBMI = new Button.OnClickListener()
  60.     {
  61.         public void onClick(View v)
  62.         {
  63.             DecimalFormat nf = new DecimalFormat("0.00");
  64.             try
  65.             {
  66.                 double height = Double.parseDouble(field_height.getText().toString())/100;
  67.                 double weight = Double.parseDouble(field_weight.getText().toString());
  68.                 double BMI = weight / (height * height);

  69.                 view_result.setText(getText(R.string.bmi_result) + nf.format(BMI));

  70.                 if (BMI > 25)
  71.                 {
  72.                     view_suggest.setText(R.string.advice_heavy);
  73.                 }
  74.                 else if (BMI < 20)
  75.                 {
  76.                     view_suggest.setText(R.string.advice_light);
  77.                 }
  78.                 else
  79.                 {
  80.                     view_suggest.setText(R.string.advice_average);
  81.                 }
  82.             }
  83.             catch(Exception err)
  84.             {
  85.                 Log.e(TAG, "error: " + err.toString());
  86.                 Toast.makeText(Bmi.this, R.string.input_tip, Toast.LENGTH_SHORT).show();
  87.             }
  88.         }
  89.     };

  90.     private void openOptionsDialog()
  91.     {
  92.         new AlertDialog.Builder(Bmi.this)
  93.         .setTitle(R.string.about_title)
  94.         .setMessage(R.string.about_msg)
  95.         .setPositiveButton(R.string.ok_label, new DialogInterface.OnClickListener() {
  96.             @Override
  97.             public void onClick(DialogInterface dialog, int which) {
  98.                 Toast.makeText(Bmi.this, R.string.thanks, Toast.LENGTH_SHORT).show();
  99.             }
  100.         })
  101.         .setNegativeButton(R.string.home_page, new DialogInterface.OnClickListener() {
  102.             @Override
  103.             public void onClick(DialogInterface dialog, int which) {
  104.                 Uri uri = Uri.parse(getString(R.string.home_page_url));
  105.                 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
  106.                 startActivity(intent);
  107.             }
  108.         })
  109.         .show();
  110.     }

  111.     @Override
  112.     public boolean onCreateOptionsMenu(Menu menu)
  113.     {
  114.         //getMenuInflater().inflate(R.menu.bmi, menu);
  115.         super.onCreateOptionsMenu(menu);
  116.         menu.add(0, MENU_ABOUT, 0, "关于");
  117.         menu.add(0, MENU_EXIT, 0, "退出");
  118.         return true;
  119.     }

  120.     @Override
  121.     public boolean onOptionsItemSelected(MenuItem item)
  122.     {
  123.         super.onOptionsItemSelected(item);
  124.         switch (item.getItemId())
  125.         {
  126.         case MENU_ABOUT:
  127.         {
  128.             openOptionsDialog();
  129.         }
  130.         break;
  131.         case MENU_EXIT:
  132.         {
  133.             finish();
  134.         }
  135.         break;
  136.         default:
  137.             break;
  138.         }
  139.         return true;
  140.     }

  141.     private Button button_calc;
  142.     private EditText field_height;
  143.     private EditText field_weight;
  144.     private TextView view_result;
  145.     private TextView view_suggest;

  146.     private static final int MENU_ABOUT = Menu.FIRST;
  147.     private static final int MENU_EXIT = Menu.FIRST + 1;

  148.     private static final String TAG = "Bmi";
  149.     private static final String PREF = "BMI_PREF";
  150.     private static final String PREF_HEIGHT = "BMI_Height";
  151. }
    我喜欢把变量啥的搁后面,习惯了C++了吧,估计是。这里重点说的不是计算的逻辑,因为逻辑本身不复杂,一看就明白的。想说的一是记忆文本框的上次输入,二是文本框提示,三是异常处理,还有个菜单,忘了还有个uri跳转的。

    1> 记忆文本框
        当关闭应用程序后再次打开应用程序,文本编辑框可以显示上次的值,这就是memory,ok!这需要重载void onStop(){}接口;这样当程序退出时,会调用该接口,然后记住当前输入值;然后我们可以实现类似void restorePrefs(){}这样的接口,获得SharedPreferences对象,然后通过该对象拿到之前以PREF_HEIGHT命名的字符串,然后EditText调用setText显示之,为了更好的体验,我们可以显示完本文本框后,让光标移动到下一个文本编辑框,只需调用EditText对应的requestFocus就可以了!还不错,懂了点.
 2> 文本框提示\uri
        文本提示框,这个我主要是用在点击菜单下的关于条目时,显示一些关于和感谢信息,就像这样:
    
    关于文本框的接口openOptionsDialog,也就是是一个标题啊、message、.setPositiveButton就是点击事件【点击确认的时候,该文本框消失,会显示一个Toast文本框,这个文本框我比较喜欢,跟提示信息似的,一闪而过,不影响视觉啥的】,.setNegativeButton就是uri事件啥的,值得去看官方文档研究以下一些属性;其中需要注意下Intent这个玩意...

 3> 异常处理
    异常处理和c++类似,try{}catch{},这里我就是捕捉编辑框不输入的情况,此时提示“亲,请输入哦”之类的信息。还好我不是xx销售人员,不然亲都亲麻木了,玩笑了。Toast挺不错的,注意:Toast.LENGTH_SHORT是表示短暂显示。

 4> 菜单

    菜单的话只需要重载boolean onCreateOptionsMenu(Menu menu) {}和boolean onOptionsItemSelected(MenuItem item)接口就行了。具体不解释,你能懂,退出是调用finish()就ok!注意:菜单ID的定义【可以自定id】
private static final int MENU_ABOUT = Menu.FIRST;  
private static final int MENU_EXIT = Menu.FIRST + 1; 

    差不多了,代码也有按钮事件,只需要获得文本然后转换为字符串,然后解析得到double类型的数据,然后一乘一显示就基本大功小成了。试试,还不多:
    
    其实界面不漂亮,也不非主流,啥时候多学点一个外观属性和布局,改好看点...

    现在回过头来我们看看Activity是怎么被调的,秘密就在AndroidManifest.xml里面,我们来看看:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android=""
  3.     package="com.demo.android.bmi"
  4.     android:versionCode="1"
  5.     android:versionName="1.0" >

  6.     <uses-sdk
  7.         android:minSdkVersion="8"
  8.         android:targetSdkVersion="17" />

  9.     <application
  10.         android:allowBackup="true"
  11.         android:icon="@drawable/ic_launcher"
  12.         android:label="@string/app_name"
  13.         android:theme="@style/AppTheme" >
  14.         <activity
  15.             android:name="com.demo.android.bmi.Bmi"
  16.             android:label="@string/app_name" >
  17.             <!--
  18.             <intent-filter>
  19.                 <action android:name="android.intent.action.MAIN" />
  20.                 <category android:name="android.intent.category.LAUNCHER" />
  21.             </intent-filter>
  22.             -->
  23.         </activity>

  24.         <!-- 开机动画Activity设为程序入口 -->
  25.         <activity
  26.             android:name="Report"
  27.             android:label="@string/report_title" android:icon="@drawable/ic_launcher">
  28.             <intent-filter>
  29.                 <action android:name="android.intent.action.MAIN" />
  30.                 <category android:name="android.intent.category.LAUNCHER" />
  31.             </intent-filter>
  32.         </activity>
  33.         
  34.     </application>
  35. </manifest>
    <!-- 开机动画Activity设为程序入口 -->这部分之前没有,我后面加的。所以抛开这部分,你可以看到com.demo.android.bmi.Bmi这个activity,启动靠的就是<intent-filter></intent-filter>部分,如果你将这个部分搁到其它activity,那么它将启动对应的activity,所以我将其挪到了开机动画activity,增加的画面感,虽然没用...
    对于发布程序,可能还需要修改流水号,版本啥的。坐在床上,背好酸,真不是个好姿势...

    最后来展示下动画吧,activity结构都和bmi差不多的,不过用到了ImageView控件显示图片【感谢网友】,自己添加了一个activity跳转代码;图片搁到了drawable-xxhdpi/ 目录下,搁在其它和drawable有关的目录应该可以。

    1> 布局页面
    report.xml

点击(此处)折叠或打开

  1. <LinearLayout xmlns:android=""
  2.     android:layout_width="fill_parent"
  3.     android:layout_height="fill_parent"
  4.     android:orientation="vertical" >

  5.     <!-- android:contentDescription="@string/desc"辅助功能提供,为一些没有文字描述的View提供说明 -->
  6.     <ImageView
  7.         android:contentDescription="@string/desc"
  8.         android:id="@+id/imageView"
  9.         android:layout_width="fill_parent"
  10.         android:layout_height="fill_parent" />

  11. </LinearLayout>
      2> 键值对代码搁在了values/ 下的同名文件report.xml,名字相同了,不太好反正。虽然不会互相干扰。

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.     <string name="report_title">BMI</string>
  4.     <string name="desc">启动动画</string>
  5. </resources>
    3> 实现
    report.java

点击(此处)折叠或打开

  1. package com.demo.android.bmi;

  2. import android.annotation.SuppressLint;
  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. import android.widget.ImageView;

  9. public class Report extends Activity {
  10.     @Override
  11.     protected void onCreate(Bundle savedInstanceState)
  12.     {
  13.         super.onCreate(savedInstanceState);
  14.         setContentView(R.layout.report);

  15.         //程序启动显示背景图片
  16.         this.iv_Show_Image = (ImageView) this.findViewById(R.id.imageView);
  17.         this.iv_Show_Image.setBackgroundResource(R.drawable.back);
  18.         autoShowImage();
  19.     }

  20.     public void autoShowImage()
  21.     {
  22.         new Thread(new Runnable()
  23.         {
  24.             @Override
  25.             public void run()
  26.             {
  27.                 while (true) {
  28.                     Message msg = new Message();
  29.                     msg.obj = index;
  30.                     handler.sendMessage(msg);
  31.                     index++;
  32.                     if(index >= int_Image.length)
  33.                     {
  34.                         /*index = 0;*/
  35.                         break;
  36.                     }
  37.                     try
  38.                     {
  39.                         Thread.sleep(5000);
  40.                     }
  41.                     catch (InterruptedException e)
  42.                     {
  43.                         e.printStackTrace();
  44.                     }
  45.                 }
  46.                 //close activity
  47.                 Report.this.finish();
  48.                 //switch to report page
  49.                 Intent intent = new Intent();
  50.                 intent.setClass(Report.this, Bmi.class);
  51.                 startActivity(intent);
  52.             }
  53.         }).start();
  54.     }

  55.     @SuppressLint("HandlerLeak")
  56.     public Handler handler = new Handler()
  57.     {
  58.         public void handleMessage(android.os.Message msg)
  59.         {
  60.             //这里之所以没有用switch来判断传回的msg。what 来控制 是应为这里的handler 只处理更新图片,传回来的信息就是图片的编号,所以不需要
  61.             iv_Show_Image.setBackgroundResource(int_Image[(Integer) msg.obj]);
  62.         };
  63.     };

  64.     private ImageView iv_Show_Image = null;
  65.     private int index = 0;
  66.     private int [] int_Image = {R.drawable.t1,R.drawable.t2,R.drawable.t3,R.drawable.t4};
  67. }
    图片显示启动了线程,图片显示结束后,我让其跳转到了bmi计算器界面,主要就是红色部分代码。That's all.

    还有很多没解释,我自己也在学啊学,只能这样了。还有R.java,BuildConfig.java啥的慢慢研究。其实关键还是需要了解android的整个机制,框架啥的,至于控件慢慢就会熟悉,关键的是思维方法,而不是华丽的外部,研究明白了,开发还不是手到擒来,当然过程很辛苦,体会思密达!

我缩小了,慢慢最小化,即将进入BMI计算界面,just hold on......................



    


    
阅读(12738) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~