2014/08/20

Android開發,appcompat_v7需要進版本管控嗎?

用Eclipse或Android Studio開發Android APP的朋友會發現,在ADT 22.6以後,當建立新的專案時,都會多一個appcompat_v7(或appcompat_v7_xx)的專案。
這專案是什麼?有什麼用途?網路上已有不少文章,大家找一下就可以找到一堆了 (參考)

那當專案要進版本管控(SVN, CVS, etc.)時,這個自動生成的support library project也需要跟著進去嗎?
找了一些文章,似乎沒有找到有較明確的說法。
當然,一起納管一定沒問題,可是納管這個自動生成的project似乎很沒道理。

換個角度來思考,如果我們在沒有這個project的workspace中,可以讓工具自動再生成這個project,讓我們的porject可以正常運作,那這個appcompat_v7就可以不用放進版本管控了。

做一個實驗,模擬一下當從SVN or CVS check-out一個專案時,是否能把整個開發環境建立回來。
開一個新的workspace,把一個之前做好的project給import進來,當然如預期的,會有一大堆的錯誤。錯誤當然都是跟support library有關。

接下來就要把support library project建立起來。相信大家的環境一定會有Android SDK。接著我們就要從下面的目錄把support library給import進來
<android_sdk>\extras\android\support\v7\appcompat  (註:<android_sdk>是指你SDK的安裝目錄)
不過還是一堆error


看一下原專案的properties,其library的名稱是appcompat_v7,但我們import進來的名稱是android-support-v7-appcompat,兩者名稱不同,必須修改一下讓兩者一致。那要修改那一個?我比較偏好改support library project的名稱。因為改properties裡的library名稱,再commit回版本管控時,可能會影響到別的同仁。

在project上right-click,用refactoring的功能來改project name為appcompat_v7 (如果在上一步驟所看到的project name不是這一個,以properties裡的設定為主)

修改完後,Eclipse就開始重新build workspace,這時errors就消失了

試跑了一下,原project的功能都正常。因此整個開發環境都回來了。
透過這個實驗可以得知,我們可以不用把support library project放進版本管控系統中,之後也能把開發環境重建起來。

補註:想瞭解Android support library有那些及分別有那些功能,<android_sdk>\extras\android\support\README.txt這份文件是個好起點

2014/08/15

在Android中周期性更新ListView的內容

在一個Activity裡有一個ListView,需要每10秒鐘更新ListView的資料
用寫Java的傳統想法,寫出了這樣的程式
其中ListItemProducer.getInstance().getList()會傳回ArrayList<string>

ArrayAdapter adapter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
  ...
  list = (ListView) findViewById(R.id.listView1);
adapter = new ArrayAdapter(ListActivity.this, android.R.layout.simple_list_item_1, ListItemProducer.getInstance().getList());
list.setAdapter(adapter);

timer = new Timer();
timer.schedule(new MyTask(), 5000, 10000);
}

class MyTask extends TimerTask {

@Override
public void run() {
adapter.notifyDataSetChanged();
}
}

一執行,當掉了,怎麼可能!?
這樣的Java程式我寫了無數次了,不應有錯呀
 靜下心仔細看了一下,原來出現"Only the original thread that created a view hierarchy can touch its views."的exception
Android只允許原始的thread去變動views,上面的MyTask是在另一個thread跑,不被允許去碰views
找找資料,Handler倒是個解決問題的好方向
於是加了這段

private Handler updateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
adapter.notifyDataSetChanged();
}
};

然後把 MyTask改成

class MyTask extends TimerTask {
@Override
public void run() {
try {
updateHandler.sendEmptyMessage(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}

讓MyTask在每次時間到時,透過handler來送message回原來的thread,讓原來的thread去做update views的工作

如何讓Android的WebView不會跳出browser來呈現網頁

在開發一個Android APP時,有一個需求是必須將網頁開在APP裡。

嗯...這不難,Android SDK有提供WebView元件可以用。用這段code就搞定了

WebView web = (WebView) findViewById(R.id.webView1);
web.getSettings().setJavaScriptEnabled(true);
web.loadUrl(url);

如果有這樣簡單,就不會寫這一篇了。
這樣的寫法當然可以將網頁開在WebView裡。不過,一遇到post form, redirect或其他的情況,就發現會跳出APP,用browser去顯現後面的網頁了。

做一下功課,瞭解了幾件事
  1. WebView如果沒有設定WebViewClient,那預設WebView會要Activity Manager來提供適當程式來處理這個URL。這也就是為什麼會跳出browser來顯現網頁
  2. 如果WebView有設定WebViewClient,這時會執行這WevViewClient的shouldOverrideUrlLoading method。這方法如果傳回true則表示APP會自行處理這個URL,否則WebView會接著出面來接手處理這個URL
瞭解了這段後,我們就須把剛剛的code改一下

WebView web = (WebView) findViewById(R.id.webView1);
web.getSettings().setJavaScriptEnabled(true);
web.setWebViewClient(new InsideWebViewClient());
web.loadUrl(url);

然後也要加個class
class InsideWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
    }
}

這樣,就可以達到需求了