第二天 每日一句

来源:互联网 发布:c语言双阶乘 编辑:程序博客网 时间:2024/04/26 04:31

    谢谢大家的厚爱。今天是第二天了,第二个小项目,比第一个要复杂一点点。今天的项目呢是要做一个英语学习小软件,就是英语每日一句。由于是小项目,就不用那么复杂,没有自己去做服务器(自己做也可以,这样最好,可以扩展出很多项目。比如,糗事百科,知乎,或再大点的,美团,淘宝等。可是大项目是要团队做的)。在21世纪,作为一名程序员,不应该推崇单兵做战,之前倒是有很多大神,比如求伯君和WPS,但现在的系统都比较庞大,并且用户需求多元化,并且要求开发周期足够短,所以必须要团队合作。闲话少说,既然没有服务器,那资源从哪里来呢,本文选择金山词霸的每日一句。Let’s go.

 

一、需求分析

功能性需求:每日显示,一句英语,一张图片,还有翻译,和小编的废话

非功能性需求:要求无网络时程序不会死,网络请求时间要10s之内完成

废话:要想做好需求分析要作为用户去和用户沟通。此,仁者见仁,智者见智。

 

二、概要设计

内容:金山词霸每日一句http://news.iciba.com/dailysentence/detail-1504.html

数据接口:html

显示内容:图片,英语,汉语,小编

 

三、详细设计

1、html解析

本文采用JSoup(http://jsoup.org/)进行解析

使用JSoup很简单,首先是导入lib然后build path最后使用如下代码(或参考官方api)进行解析

<span style="font-family:SimSun;">Document doc = Jsoup.connect("http://en.wikipedia.org/").get();Elements newsHeadlines = doc.select("#mp-itn b a");</span>

2、异步任务

对于异步任务就是实现一个类继承AsyncTask类。

AsyncTask定义了三个泛型类型:Params Progress Result。

· Params 启动任务执行的输入参数

· Progress 后台任务执行的百分比

· Result 后台执行任务最终返回的结果

AsyncTask 一个异步加载数据最少要重写以下这两个方法:

· doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。

· onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

有必要的话还得重写以下这三个方法,但不是必须的:

· onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。

· onPreExecute()        这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。

· onCancelled()             用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则:

· Task的实例必须在UI thread中创建;

· execute方法必须在UI thread中调用;

· 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;

· 该task只能被执行一次,否则多次调用时将会出现异常;

具体实现请看四中的代码


3、网络图片下载

这个比较固定,基本如下函数,先建立http网络连接,获取到InputStream,然后通过Bitmap生成Bitmap,此时可以显示到ImageView上或者保存,这取决于你。

/** * 网络请求图片生成Bitmap *  * @param path * @return */private Bitmap getBitmapByUrl(String path) {Bitmap bm = null;URL url;try {url = new URL(path);HttpURLConnection con;con = (HttpURLConnection) url.openConnection();con.setDoInput(true);con.connect();InputStream is = con.getInputStream();bm = BitmapFactory.decodeStream(is);is.close();} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return bm;}


4、时间间隔计算

所有的时间都是从1979年开始的。Java提供了方法,可以把日期转换成秒数(相对于1979),然后我们可以把两个日期都转换成秒,然后相减,再然后就是把秒转换成天数,一天24个小时,这不用我说了吧。就知道两个日期相差几天了。

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");Date date = null;try {date = df.parse("2015-08-19");} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}long old = date.getTime();long now = System.currentTimeMillis();long day = (now - old) / 1000 / 60 / 60 / 12;


四、编码测试

AndroidMenifest.xml 对程序进行配置

<?xml version="1.0" encoding="utf-8"?><!-- package的包名是App运行的凭证 --><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.leo.everyday"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="13"        android:targetSdkVersion="21" />    <!-- 同样的网络权限 -->    <uses-permission android:name="android.permission.INTERNET" />    <!-- theme设置程序主题风格 holo风格 title栏将随着activity最上面颜色的改变而改变 -->    <application        android:allowBackup="true"        android:icon="@drawable/every_day"        android:label="@string/app_name"        android:theme="@android:style/Theme.Holo.Light.NoActionBar.TranslucentDecor" >        <activity            android:name=".MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

activity_main.xml 布局文件,内容的显示界面


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:background="@drawable/main_bg"    android:orientation="vertical"    android:paddingBottom="20dip"    android:paddingLeft="20dip"    android:paddingRight="20dip"    android:paddingTop="55dip" >    <ImageView        android:id="@+id/iv_image_main"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:adjustViewBounds="true"        android:scaleType="centerCrop"        android:src="@drawable/test" />    <ScrollView        android:layout_width="match_parent"        android:layout_height="wrap_content" >        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="vertical" >            <TextView                android:id="@+id/tv_text_main"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="EN"                android:textAppearance="?android:attr/textAppearanceMedium"                android:textColor="@android:color/black"                android:textStyle="bold" />            <TextView                android:id="@+id/tv_translate_main"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="CN"                android:textColor="@android:color/black"                android:layout_margin="6dip" />            <TextView                android:id="@+id/tv_editor_main"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="EDITOR"                android:textAppearance="?android:attr/textAppearanceMedium"                android:textColor="@android:color/black"                android:textStyle="italic" />        </LinearLayout>    </ScrollView></LinearLayout>


MainActivity.java

package com.leo.everyday;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import org.jsoup.Jsoup;import org.jsoup.nodes.Document;import org.jsoup.nodes.Element;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.os.Bundle;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;/** * @time 2015-09-12 * @author Leo * @describe 程序主Activity 负责网络请求数据得到html然后进行解析 最过显示到相应的控件上 *  */public class MainActivity extends Activity {private Context mContext = null;// 自己private static final String TAG = MainActivity.class.getSimpleName();// Log调试时作为标签private static final String MAIN_URL = "http://news.iciba.com/dailysentence/detail-";// 网络URLprivate static final String IMAGE_CLASS = "r_pic";// html中css定义的属性名 此为图片private static final String TEXT_CLASS = "en";// 英文文本private static final String TRANSLATE_CLASS = "cn";// 翻译文本private static final String EDITOR_CLASS = "editor";// 小编private ImageView imageShow = null;// 显示图片private TextView textShow = null, translateShow = null, editorShow = null;// 显示文本内容@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 设置布局文件// 游戏中会通过继承SurfaceView来自定义游戏布局// 会经常使用此方法findViewsByIds();// 根据ids初始化控件task.execute(calculateUrlByTime());// 执行异步任务 从4.0开始google限制不能在主线程中执行网络任务}/** * 取得控件 */private void findViewsByIds() {imageShow = (ImageView) findViewById(R.id.iv_image_main);textShow = (TextView) findViewById(R.id.tv_text_main);translateShow = (TextView) findViewById(R.id.tv_translate_main);editorShow = (TextView) findViewById(R.id.tv_editor_main);}/** * html解析的异步任务 */private AsyncTask<String, Integer, Sentence> task = new AsyncTask<String, Integer, Sentence>() {@Overrideprotected Sentence doInBackground(String... arg0) {// TODO Auto-generated method stubSentence mSentence = null;// bean接收数据try {Document dom = Jsoup.connect(arg0[0]).get();// Jsoup通过网络连接取得html文档Element imageElement = dom.getElementsByClass(IMAGE_CLASS).first();Element textElement = dom.getElementsByClass(TEXT_CLASS).first();Element translateElement = dom.getElementsByClass(TRANSLATE_CLASS).first();Element editorElement = dom.getElementsByClass(EDITOR_CLASS).first();String image = imageElement.getElementsByTag("img").first().attr("src");String text = textElement.getElementsByTag("a").first().text();String translate = translateElement.getElementsByTag("a").first().text();String editor = editorElement.text();mSentence = new Sentence(image, text, translate, editor);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {System.out.println("网络异常");}return mSentence;}@Overrideprotected void onPostExecute(Sentence result) {// TODO Auto-generated method stubsuper.onPostExecute(result);if (result != null) {showInformation(result);} else {toast("内容空,请重试");}}};/** * 弹出提示 *  * @param text */private void toast(String text) {Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();}/** * 把内容显示到控件上去 *  * @param result */private void showInformation(final Sentence result) {textShow.setText(result.getText());translateShow.setText(result.getTranslate());editorShow.setText(result.getEditor());/** * 偷一回懒 同样用简单异步任务加载图片 */new AsyncTask<String, Integer, Bitmap>() {@Overrideprotected Bitmap doInBackground(String... arg0) {// TODO Auto-generated method stubBitmap bmp = getBitmapByUrl(arg0[0]);return bmp;}@Overrideprotected void onPostExecute(Bitmap result) {// TODO Auto-generated method stubsuper.onPostExecute(result);imageShow.setImageBitmap(result);}}.execute(result.getImage());}/** * 网络请求图片生成Bitmap *  * @param path * @return */private Bitmap getBitmapByUrl(String path) {Bitmap bm = null;URL url;try {url = new URL(path);HttpURLConnection con;con = (HttpURLConnection) url.openConnection();con.setDoInput(true);con.connect();InputStream is = con.getInputStream();bm = BitmapFactory.decodeStream(is);is.close();} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return bm;}/** * 标准阶段1455对应时期为2015-08-19方便计算出以后日期对应的网页连接 比如:2015-08-20对应为1456和1457 */private static final long OLD_NUMBER = 1455;/** * 计算开始 *  * @return */private static String calculateUrlByTime() {String url = MAIN_URL + 1 + ".html";SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");Date date = null;try {date = df.parse("2015-08-19");} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}long old = date.getTime();long now = System.currentTimeMillis();long day = (now - old) / 1000 / 60 / 60 / 12;long number = OLD_NUMBER + day;url = MAIN_URL + number + ".html";return url;}}


Sentence.java

package com.leo.everyday;/** * @time 2015-09-12 * @author Leo * @describe 内容实体内 java bean *  */public class Sentence {private String image;private String text;private String translate;private String editor;public Sentence() {}public Sentence(String image, String text, String translate, String editor) {super();this.image = image;this.text = text;this.translate = translate;this.editor = editor;}public String getImage() {return image;}public void setImage(String image) {this.image = image;}public String getText() {return text;}public void setText(String text) {this.text = text;}public String getTranslate() {return translate;}public void setTranslate(String translate) {this.translate = translate;}public String getEditor() {return editor;}public void setEditor(String editor) {this.editor = editor;}}


 

项目源码:http://download.csdn.net/detail/zhaicaixiansheng/9101147

 

五、项目总结

   做一个项目最重要的不是编码,而是需求分析和测试。需求做不好,做了也白做;测试没做好,做了还是demo。一个项目要发布交互,首先就是稳定性。再一个就是在实际项目中,就算是大神也会遇到自己不会和地方,这就是知识盲点。或者说,等到了大神的阶段,都不屑于写代码记代码了。所以说,对于一个程序员,重要的是编程的思想和学习的能力。编程思想决定你写出的代码的质量,学习能力决定你开发的速度和发展的前景。对于编程思想,没什么好说的,什么《算法大全》《面向对象分析与设计》《数据结构》《设计模式》《软件工程》等等,这些一定要饿补。学到学习能力,每个人有自己的方法。对于IT技术,我的学习方法是,以IOS为例:首先选择一本书,重点看第一章和下面的目录,然后随便翻翻,这是为了对这个新东西有个全面的了解,知道他是什么,要做什么,能做什么,怎么做;然后就是看每张的最开始的容易的地方,这样是为了掌握基础的东西,可以写出helloworld类的程序。然后就是做项目,遇到什么不会的就百度谷歌api文档,进行学习使用;当你这样达到一定水平后,就是总结和看视频了,总结是系统的全面的理解。看视频是为了知道别人怎么做,并查漏补缺。

   好了说了那么多废话,希望对您有所帮助。加油!!!

 

 

 

 

3 0
原创粉丝点击