打算寫一個稍微複雜的小程式,練習的項目:
- 使用 Regular Expression
- 使用 Network Connection
- 使用 Thread
以三個項目為出發點,把以前的老題目拿出來:定期抓台灣 Yahoo 首頁的兩則焦點新聞,顯示在 Android 模擬上。因此,先想一下排版問題,大概就三個 TextView,分別為 更新時間 和 兩則新聞。
建立 project
[Eclipse]->[File]->[New]->[Android Project]
Project name: MyWeb
Build Target: Android 2.2
Application name: MyWeb
Package name: com.test.Web
Create Activity: MyWeb
Min SDK Version: 8
設定使用網路權限
點選 AndroidManifest.xml 檔案,在 <manifest> 裡增加 <uses-permission android:name="android.permission.INTERNET" />
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.web"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MyWeb"
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>
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
設定排版
點選 main.xml 檔案,增加 3 個 TextView,分別為"更新時間"、"新聞1"和"新聞2"。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView android:id="@+id/UpdateDate" android:layout_width="fill_parent" android:layout_height="wrap_parent"></TextView>
<TextView android:id="@+id/News1" android:layout_width="fill_parent" android:layout_height="wrap_content"></TextView>
<TextView android:id="@+id/News2" android:layout_width="fill_parent" android:layout_height="wrap_content"></TextView>
</LinearLayout>
MyWeb.java
package com.test.web;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import com.test.web.GetYahooNews;
public class MyWeb extends Activity {
Handler jobs;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
jobs = new Handler();
new Thread( new GetYahooNews( this )).start();
}
public void updateNews( final ArrayList<String> news )
{
jobs.post( new Runnable(){
public void run()
{
TextView showTextView;
if( news != null && news.size() >= 2 )
{
if( ( showTextView = (TextView) findViewById(R.id.News1) ) != null )
showTextView.setText("[News] "+(String)news.get(0));
if( news.size() == 4 && ( showTextView = (TextView) findViewById(R.id.News2) ) != null )
showTextView.setText("[News] "+(String)news.get(2));
}
if( ( showTextView = (TextView) findViewById(R.id.UpdateDate) ) != null )
{
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
showTextView.setText( "[Update @ " + dateFormat.format(new Date() ) + "]" );
}
}
});
}
}
GetYahooNews.java
package com.test.web;
import java.io.*;
import java.util.ArrayList;
import java.util.regex.*;
import java.net.HttpURLConnection;
import java.net.URL;
import android.util.Log;
import com.test.web.MyWeb;
public class GetYahooNews implements Runnable {
MyWeb activity;
GetYahooNews( MyWeb n)
{
this.activity = n;
}
public static void report( String message )
{
//System.out.println( "[Report] " + message );
Log.d( "Report" , message );
}
public static ArrayList<String> getHotNews()
{
ArrayList<String> news = new ArrayList<String>();
HttpURLConnection con = null;
try
{
//*
URL url = new URL("http://tw.yahoo.com");
con = (HttpURLConnection) url.openConnection();
con.setReadTimeout(10000);
con.setConnectTimeout(15000);
con.setRequestMethod("GET" );
con.addRequestProperty("User-Agent","Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9");
con.setDoInput(true);
con.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8" ));
// */
// BufferedReader reader = new BufferedReader(new InputStreamReader( new FileInputStream("fetch.html"), "UTF-8" ));
String n, result="";
// while( ( n = reader.readLine() ) != null )
// result += n;
StringBuilder htmlContent = new StringBuilder();
while ((n = reader.readLine()) != null)
htmlContent.append(n);
result = htmlContent.toString();
// BufferedWriter out = new BufferedWriter( new FileWriter("fetch.html") );out.write(result);out.close();
String pattern;
int at;
pattern = "<label class=\"img-border clearfix\">";
if( ( at = result.indexOf(pattern) ) < 0 )
{
news.add( "format error 1" );
report( "format error 1" );
return news;
}
result = result.substring( at );
pattern = "<ol class=\"newsad clearfix\">";
if( ( at = result.indexOf(pattern) ) < 0 )
{
news.add( "format error 2" );
report( "format error 2" );
return news;
}
result = result.substring( 0 , at );
pattern = "<h3[^>]*>[^<]*<a href=\"(.*?)\"[^>]*>(.*?)</a></h3>";
Pattern p = Pattern.compile( pattern , Pattern.CASE_INSENSITIVE | Pattern.DOTALL );
Matcher m = p.matcher( result );
while( m.find() )
{
// report( "\n==== Get === \n" + m.group() + "\n" );
// report( "URL: " + m.group(1) );
// report( "Title: " + m.group(2) );
String newsTitle = ""+ m.group(2);
String newsUrl = "" + m.group(1);
if( ( at = newsUrl.indexOf( "http:" ) ) > 0 )
newsUrl = newsUrl.substring( at );
news.add( newsTitle );
news.add( newsUrl );
}
}catch(Exception e)
{
news.add( "Exception:"+e );
}
finally
{
if ( con != null )
con.disconnect();
}
return news;
}
public void run()
{
try
{
while( true )
{
try
{
// ArrayList<String> demo = new ArrayList<String>();demo.add("Yo1");demo.add("Yo2");demo.add("Yo3");demo.add("Yo4");activity.updateNews( demo );
activity.updateNews( getHotNews() );
Thread.sleep( 1000 * 60 * 60 * 2 ); // 2 hrs
}
catch(Exception e)
{
report( "run while Exception:"+e );
break;
}
}
}
catch( Exception e )
{
report( "run Exception:"+e );
}
}
}
在 MyWeb 裡有一樣東西比較特別,叫做 Handler,可以把他當作管理 Thread 的用法,在官網的描述裡,比較重要的敘述:
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
在這邊使用 Handler,是讓更新 UI 的部份能夠透過 Runnable 來處理事件,如果不使用的話,會有無法更新 UI 的現象,暫時還沒了解底層的問題。
接著是 MyWeb 裡的 updateNews 函數,其參數是使用 final 的描述,加上這個描述後,可以讓接下來的 new Runnalbe 裡,可以直接用傳進來的參數,如果不用 final 也有解法啦,就是自己在定義一個實做 Runnable 的物件,然後把參數都傳遞好,稍微麻煩一點:
public void updateNewsPrev( ArrayList<String> news )
{
class UIUpdate implements Runnable
{
ArrayList<String> news;
UIUpdate( ArrayList<String> in )
{
news = in;
}
public void run()
{
TextView showTextView;
if( news != null && news.size() >= 2 )
{
if( ( showTextView = (TextView) findViewById(R.id.News1) ) != null )
showTextView.setText("[News] "+(String)news.get(0));
if( news.size() == 4 && ( showTextView = (TextView) findViewById(R.id.News2) ) != null )
showTextView.setText("[News] "+(String)news.get(2));
}
if( ( showTextView = (TextView) findViewById(R.id.UpdateDate) ) != null )
{
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
showTextView.setText( "[Update @ " + dateFormat.format(new Date() ) + "]" );
}
}
}
jobs.post( new UIUpdate( news ) );
}
接下來是 GetYahooNews 的部份,其中 getHotNews 函數是擷取台灣 Yahoo 首頁的兩則新聞出來,以此當作資料,接著就只是單純的當個 Runnalbe 在跑,並且設定 2 小時跑一次,跑完一次會呼叫 MyWeb 的 updateNews 去更新 UI 部份。至於怎樣從 GetYahooNews 呼叫 MyWeb 呢?那就是一開始在使用 GetYahooNews 時,就把 MyWeb 傳進去給他記住,在此使用 activity 變數紀錄。
我想請問~~我測試您的程式碼沒問題,但是新聞都不會顯示,都只有顯示時間,可以幫我看一下是甚麼問題嗎??謝謝
回覆刪除版主回覆:(03/28/2011 01:55:59 PM)
有可能是取新聞的那段出了問題
你看著程式了解架構後,在自行修改吧 :)