安卓第九夜 狂风

作者: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快速教程”系列文章  

时间: 2024-09-23 04:05:58

安卓第九夜 狂风的相关文章

安卓第二夜 有趣的架构

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!   学习安卓的架构,是从操作系统的角度理解安卓.安卓使用Linux内核,但安卓的架构又与常见的Linux系统有很大的区别.我们先来回顾一下传统的Linux架构,再来看安卓的变化.   Linux系统架构 先来看常见的Linux系统架构,你可以参考Linux的架构     内核是系统的底层.Linux开机后,内核即启动,并存活于属于自己的内存空间,即内核空间(kernel spac

安卓第一夜 第一个应用

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!   承接"Java快速教程",我将开始写安卓相关的文章.   安卓(Android)开发主要使用Java语言.Java语言基础,是安卓开发的第一道门槛.再者,一个好的安卓应用往往配合有远程服务器.这两方面,可以参考Java快速教程中对Java语言和Play框架的讲解.安卓开发还需要其它技术的合作,包括操作系统.互联网.图形化界面.数据库等.可以说,移动开发是一个现实的战

Java快速教程

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!      Java是面向对象语言.这门语言其实相当年轻,于1995年才出现,由Sun公司出品.James Gosling领导了Java的项目小组.该项目的最初只想为家电设计一门容易移植的语言.然而,在获得了Netscape浏览器支持后,Java快速推广,应用广泛. Java受到C和C++的强烈影响.Java与C++相近,都是静态类型,但移除了C++中容易出错的一些特征,比如指针和

安卓第五夜 维纳斯的诞生

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!   之前各讲中,分别讲解了安卓的开发环境.架构和基本概念.从这一讲开始,我将制作一个简单的应用,并通过逐步升级它的功能,连带出安卓开发的多个情境. <维纳斯的诞生>是文艺复兴早期名画.相传美神维纳斯从海的泡沫中诞生,波提切利用大胆的笔触描绘这一古典神话.画面洋溢着对人体和美的热爱.如果在中世纪或者西班牙宗教审判时期,这幅画足够波提切利上火刑架了.    任务描述 我将制作一个简

从一篇好的软文看SEM

中介交易 SEO诊断 淘宝客 云主机 技术大厅 前天在网易新闻论坛看到一篇帖子<盘点:中国十大网络推手>,这篇文章当时被推上网易论坛首页.下面我把这篇文章贴出来,再来与大家交流一下好的软文与SEM之间的关系. 天仙妹妹.二月丫头.芙蓉姐姐.流氓燕--近两年来,各具特色的网络红人层出不穷,让网民目不暇接.网上传说"红人幕后有'黑手'",找寻到这些"黑手"时,他们认为自己不是"网络黑手",而是网络"推手".层出不穷的网

安卓第四夜 概念漫游(下)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!   在安卓第三夜 概念漫游(上)中,我介绍了安卓最基本的功能单元和Intent的连接方式.在这个骨架之上,我们可以进一步增加一些与开发密切相关的重要概念.   Context 一个应用是由多个Activity和Service这样的功能单元组成.一个应用共享有一个Application Context对象.在功能单元内部,可以用特定的方法来调用该对象.正如名字所表示的,Contex

安卓第六夜 凡高的自画像

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!   在上一讲中,我已经制作了一个简单的Android应用.项目的主要文件包括: MainActivity.java activity_main.xml 在这一讲,我将拓展应用的功能,从而允许用户输入个人信息.   <自画像>,凡高.凡高一生不得志,精神更是越来越差.在割掉自己的耳朵一部分后,画家给自己留下了这幅自画像.在当时,这幅画依然是无人问津.   描述 我将创建一个新的A

安卓第八夜 玛丽莲梦露

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!    上一讲说明了数据库中存取数据的方法.这一讲将以条目的视图方式,来以相似的视图方式,显示多个数据对象.这种方式特别适合于显示从数据库中取出的多个结构相似的数据,比如多个联系人,或者多个联系人分类. <玛丽莲梦露>,这是一副现代艺术作品.听到玛丽莲梦露自杀的消息后,现代艺术家沃霍尔深为震惊.他通过重复玛丽莲梦露的形象,创作了这幅波普艺术的名作.每一个形象既是重复,又有变化.

安卓第十夜 亚当的诞生

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!   上一讲介绍了用WebView来抓取一个网页内容.这一讲我将介绍如何在安卓内部直接进行HTTP通信. <亚当的诞生>,西斯廷礼拜堂的吊顶画,米开朗基罗之作.当时的教皇强迫沉迷于雕塑的米开朗基罗画巨幅壁画.米开朗基罗认为这是在浪费自己的才华,充满愤怒的作画.当然,他又成功了.   描述 这一讲中,我将使用JSON,将数据库备份到远程的数据库中.反过来我也将从远程数据库中抓取条目