安卓第九夜 狂風

Vamei發表於2014-08-16

作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段宣告。謝謝!

 

我們經常需要在安卓應用中包含簡易的網頁顯示功能。我將在這一講中實現網頁的顯示。

《狂風》,來自小Willem,荷蘭畫派黃金時代的作品。作為當時海上馬車伕的荷蘭,對航海題材的畫情有獨鍾。 這種傾斜的船身,是當時的畫家常用的手法,用於表現很強的風。

 

描述

上一講實現了一個類別條目頁面。現在,我希望點選某個類別後,能再次以條目的方式顯示所有的聯絡人。在這個新的條目頁面中,點選某個聯絡人後,能顯示該聯絡人的URL指向的頁面。相關的安卓知識點為:

  • Intent和Bundle。傳遞資料。
  • WebView。用於顯示一個網頁。

 

新的資料庫查詢方法

我將增加一個條目頁面,用於顯示某個類別下的所有聯絡人。在資料層面上,我需要從資料庫中取出某個類別下的所有聯絡人。在上一講中,我建立了ContactsManager類,用於和資料庫互動。但之前的CRUD方法無法滿足我的需求。我將為該類增加新的方法,以便從資料庫中取出某個類別下的所有聯絡人。這個方法如下:

    // Getting all contacts of a category
    public List<Contact> getContactsByCategoryId(int categoryId) {
        List<Contact> contacts = new LinkedList<Contact>();
        
        SQLiteDatabase db = this.getReadableDatabase();
 
        Cursor cursor = db.query(TABLE_CONTACTS, new String[] { KEY_ID,
            KEY_NAME, KEY_URL, KEY_CATEGORY_ID }, KEY_CATEGORY_ID + "=?",
            new String[] { String.valueOf(categoryId) }, null, null, null, null);

        // iterate over all retrieved rows
        Contact contact = null;
        if (cursor.moveToFirst()) {
            do {
                contact = new Contact();
                contact.setId(Integer.parseInt(cursor.getString(0)));
                contact.setName(cursor.getString(1));
                contact.setUrl(cursor.getString(2));
                
                Category category = getCategory(Integer.parseInt(cursor.getString(3)));
                contact.setCategory(category);
  
                // Add contact to contacts
                contacts.add(contact);
            } while (cursor.moveToNext());
        }
  
        // return contacts
        return contacts;
    }

上面方法中查詢了資料庫的TABLE_CONTACTS表格。我在資料庫的query()方法中規定,在資料庫查詢時,將只保留符合KEY_CATEGORY_ID等於categoryId條件的資料記錄。該方法將返回某個categoryId下的所有Contact資料,也就是某個目錄下的所有聯絡人資訊。

我將在後面使用這一新增方法。

 

在Intent放入附加資料

我希望點選類別後,能夠進入顯示該類別所有聯絡人,即啟動一個新的聯絡人條目頁面。由於類別的數目是動態變化的,我不可能為每個類別建立一個下游頁面(而且這樣也太麻煩了)。然而,我可以把類別資訊傳遞給同一個下游頁面,讓該下游頁面根據類別,進行不同的處理。這個資料傳遞的任務,將由Intent完成。從概念漫遊(上)中,我們已經知道,Intent就像傳令兵。現在,我要讓傳令兵夾帶一點“私貨”了。

package me.vamei.vamei;

import java.util.List;

import me.vamei.vamei.model.Category;
import me.vamei.vamei.model.ContactsManager;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

public class CategoryActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_category);
        
        ListView listview = (ListView) findViewById(R.id.categoryList);
        
        ContactsManager cm              = new ContactsManager(this);
        final List<Category> categories = cm.getAllCategories();
        
        CategoryAdapter adapter = new CategoryAdapter(this,
            R.layout.list_category, categories);
        
        listview.setAdapter(adapter);
        
        listview.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
                Intent intent = new Intent(CategoryActivity.this, ContactListActivity.class);
                // put extra data into intent
                // the data will be passed along with the intent, as a key-value pair
                intent.putExtra("CATEGORY_ID", categories.get(position).getId());
                
                startActivity(intent);
            }
        });
    }
}

putExtra()方法在Intent中放入一個鍵值對。"CATEGORY_ID"是“鍵”,而點選條目對應Category的ID是“值”。

putExtra()方法會先建立一個Bundle物件,再傳遞這個Bundle物件。在安卓中,一個Bundle物件即一個鍵值對。鍵是一個字串,值是任意可以打包的物件(parcelable object)。Bundle在安卓中的用途非常廣泛。

 

我可以用下面的語句,等效的代替上面的putExtra():

Bundle extra = new Bundle();
extra.putString("CATEGORY_ID",  categories.get(position).getId());
intent.putExtra(extra);

即手動建立Bundle物件,再利用putExtra()將Bundle物件附加在Intent物件上。

 

提取Intent中的附加資料

在下游的Activity中,我可以通過Context的getIntent()方法來獲取Intent物件。下游Activity是新建的ContactListActivity。它將以條目的方式,顯示類別下所有聯絡人:

package me.vamei.vamei;

import java.util.List;

import me.vamei.vamei.model.Contact;
import me.vamei.vamei.model.ContactsManager;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

public class ContactListActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact_list);
        
        // Get extra data from the Intent
        // i.e., category id
         Intent intent = getIntent();
        int cat_id    = intent.getIntExtra("CATEGORY_ID", -1);
        
        ContactsManager cm     = new ContactsManager(this);
        final List<Contact> contacts = cm.getContactsByCategoryId(cat_id);
        
        ListView listview = (ListView) findViewById(R.id.contactList);
        
        ContactAdapter adapter = new ContactAdapter(this,
                R.layout.list_contact, contacts);
            
        listview.setAdapter(adapter);
        
        listview.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
                Intent intent = new Intent(ContactListActivity.this, BlogActivity.class);
                // Put extra data into the Intent, which is a URL
                intent.putExtra("BLOG_URL", contacts.get(position).getUrl());
                
                startActivity(intent);
            }
        });
    }
}

我在第一部分編寫的資料庫互動方法getContactsByCategoryId(),在上面的Activity中登場。提取出的Contact表,通過ListView和ContactAdapter,顯示為聯絡人的條目頁面。在點選條目後,URL資訊放入Intent中,並啟動下游的BlogActivity。BlogActivity根據Intent中的URL,來開啟聯絡人的網頁。

練習 參考安卓第八夜 瑪麗蓮夢露,增加ContactAdapter,activity_category_list.xml和list_contact.xml,以完整的實現聯絡人條目頁面。 

練習 根據之前提到的adb shell,為資料庫增加Category和Contact記錄。

 

聯絡人條目

 

使用WebView

下面我要新增BlogActivity。它使用了WebView檢視元素來顯示Web頁面。我將增加一個佈局檔案activity_blog.xml,這個檔案包含一個簡單的WebView檢視元素:

<WebView  xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/web"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

通過操縱該檢視元素,我可以把網頁載入入這個檢視元素。 

 

下面,我將建立對應的BlogActivity。它將從Intent中提取URL地址。WebView的loadUrl()方法,用於載入URL所指向的網頁:

package me.vamei.vamei;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.webkit.WebView;

@SuppressLint("SetJavaScriptEnabled")
public class BlogActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_blog);

        // Receive the URL from the upstream activity
         Intent intent = getIntent();
        String url    = intent.getStringExtra("BLOG_URL");
        
        WebView webView = (WebView) findViewById(R.id.web);
        
        // Enable JavaScript
        webView.getSettings().setJavaScriptEnabled(true);
        
        // Load the web page of the URL
        webView.loadUrl(url);
    }
}

注意上面的getSettings()方法將返回一個WebSettings物件,包含了WebView的設定功能。該物件的setJavaScriptEnabled()方法,將允許WebView執行網頁上的JavaScript指令碼。

 

為了WebView正常執行,我需要賦予應用訪問網際網路的許可權,在AndroidManifest.xml中增加uses-permission標籤:

 

<manifest ...>
    ... 
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

 

 

 

 

 

總結

putExtra(), getIntent(), getIntExtra()

WebView, getSettings(), loadUrl()

 

歡迎繼續閱讀“Java快速教程”系列文章  

相關文章