About Java Android Web etc …

ActionBar 作为导航条的一个Bug

Android兼容开发包Support Package)的示例中,演示了ViewPager和ActionBar导航条一起使用的一个示例,该示例的代码目录位于:

android-sdk-windows\extras\android\support\v13\samples\Support13Demos

目录中的

/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java

Java类中。

运行界面如下:

ActionBar导航示例

ActionBar导航示例

如果修改其中的代码,多添加一个ViewPager和Tab导航,当屏幕横屏的时候则Tab导航会自动变为List导航。如下图:
继续阅读 »

课程十六:执行网络操作

在Android中执行网络操作需要如下基本条件:

1.添加相应的网络权限

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

2.选择使用哪种HTTP 客户端

大多数的Android程序都使用HTTP来发送和接收数据,Android包含两种HTTP 客户端实现: HttpURLConnection 和 Apache HttpClient ,这两种都支持HTTPS、流(streaming)上传和下载、可配置的超时时间、IPv6以及连接池。对于运行在2.3+以上的版本中建议使用HttpURLConnection,详情请参考这里的介绍
继续阅读 »

要不要使用Splash Screen

关于Splash Screen(启动界面)大家应该司空见惯了。特别是在PC横行的时代,几乎是每个PC程序的必备武器,比如下图的Eclipse 启动界面。

eclipse 启动界面

eclipse 启动界面

现在在Android程序中,也有越来越多的程序开始使用启动界面了,比如下图中几个全球比较流行的程序启动界面。
继续阅读 »

使用备份API

当用户更换设备或者重置现有设备数据的时候,他们可能希望Google Play能恢复他们以前设备上安装的程序。刚开始的时候
该功能并没有实现,所以有很多用户都开始抱怨他们安装的程序和数据丢失了。

对于用户数据非常小的情况(小于1M),比如 用户的设置信息、日志信息或者游戏的高分信息以及其他状态信息,备份API为此种情况
提供了一个轻量级的解决方案。这节内容将告诉您如何集成备份API到程序中,以及如何使用备份API来恢复数据。

继续阅读 »

Android 程序和GAE同步

课程内容

  1. 搭建环境
  2. 创建项目
  3. 创建数据层
  4. 创建持久化层
  5. 在Android App中查询和更新数据
  6. 配置C2DM 服务器端
  7. 配置C2DM 客户端

您还应该阅读

动手试试

这节内容使用的云任务示例代码最早出现在Google I/O 的讲座
Android + AppEngine: A Developer’s Dream Combination 中。您可以自由的使用该示例代码。

Cloud Tasks
App

编写一个带有云端同步功能的App将会是一个挑战。这里牵扯到很多细微的技术问题,比如服务器端的认证授权、共享的数据模型以及服务器端的API等等。而Google的Eclipse开发插件简化了这个过程,使用该工具可以自动生成一个Android客户端和GAE服务器端的示例程序,并且可以相互通讯。这节内容将告诉您如何通过该工具来创建这样的一个项目。

下面将会告诉您如下内容:

继续阅读 »

课程十五:与云端同步

通过提供强大的网络连接API,Android框架帮助您创建云端同步功能App,您可以同步数据到云端,确保所有的设备数据都是同步的,并且重要的数据总是备份到云端。

这节课程介绍了启用云端功能的不同策略。包括和您自己的web程序同步、以及如何备份程序数据到云端,这样当用户在新的设备上安装您的程序的时候,可以把这些数据同步下来。

课程

与GAE同步
介绍如何创建一个配对的GAE程序和Android程序,他们分享同一个数据模型,使用AccountManager来授权并通过REST或者C2DM来通讯。
使用备份API
介绍如何把备份功能集成到您的程序中,这样用户的数据可以在不同设备间无缝同步。

TapLogger 并非只针对Android

今天关于TapLogger的以讹传讹再次让Android机友伤透了心。 以为自己的爱机又爆出安全漏洞了, 自己的银行卡密码又很容易的被狗日的木马轻易的盗走了! 其实事情没这么严重,该问题也不仅仅只是Android的问题,其他带有运动传感器的手机一样存在该问题,比如 IPhone手机 等。
继续阅读 »

小函数和高内聚类示例

下面的函数用来打印1000个质数。

public class PrintPrimes {
    public static void main(String[] args) {
        final int M = 1000;
        final int RR = 50;
        final int CC = 4;
        final int WW = 10;
        final int ORDMAX = 30;
        int P[] = new int[M + 1];
        int PAGENUMBER;
        int PAGEOFFSET;
        int ROWOFFSET;
        int C;
        int J;
        int K;
        boolean JPRIME;
        int ORD;
        int SQUARE;
        int N;
        int MULT[] = new int[ORDMAX + 1];
        J = 1;
        K = 1;
        P[1] = 2;
        ORD = 2;
        SQUARE = 9;
        while (K < M) {
            do {
                J = J + 2;
                if (J == SQUARE) {
                    ORD = ORD + 1;
                    SQUARE = P[ORD] * P[ORD];
                    MULT[ORD - 1] = J;
                }
                N = 2;
                JPRIME = true;
                while (N < ORD && JPRIME) {
                    while (MULT[N] < J)
                        MULT[N] = MULT[N] + P[N] + P[N];
                    if (MULT[N] == J)
                        JPRIME = false;
                    N = N + 1;
                }
            } while (!JPRIME);
            K = K + 1;
            P[K] = J;
        }
        {
            PAGENUMBER = 1;
            PAGEOFFSET = 1;
            while (PAGEOFFSET <= M) {
                System.out.println("The First " + M + " Prime Numbers --- Page " + PAGENUMBER);
                System.out.println("");
                for (ROWOFFSET = PAGEOFFSET; ROWOFFSET < PAGEOFFSET + RR; ROWOFFSET++) {
                    for (C = 0; C < CC; C++)
                        if (ROWOFFSET + C * RR <= M)
                            System.out.format("%10d", P[ROWOFFSET + C * RR]);
                    System.out.println("");
                }
                System.out.println("\f");
                PAGENUMBER = PAGENUMBER + 1;
                PAGEOFFSET = PAGEOFFSET + RR * CC;
            }
        }
    }
}

在一个函数中完成这个任务,存在的问题: 比较深的缩进嵌套层次导、一些难以理解的变量名称、和一些紧密耦合的代码块,导致该代码阅读起来很困难, 如果使用小函数并且结合内的高内聚特性重构该功能,其代码将变得更易阅读,如下:

import java.io.PrintStream;
import java.util.ArrayList;

public class PrintPrimes {
    public static void main(String[] args) {
        final int NUMBER_OF_PRIMES = 1000;
        int[] primes = PrimeGenerator.generate(NUMBER_OF_PRIMES);
        final int ROWS_PER_PAGE = 50;
        final int COLUMNS_PER_PAGE = 4;
        RowColumnPagePrinter tablePrinter = new RowColumnPagePrinter(ROWS_PER_PAGE,
                COLUMNS_PER_PAGE, "The First " + NUMBER_OF_PRIMES + " Prime Numbers");
        tablePrinter.print(primes);
    }
}

class RowColumnPagePrinter {
    private int mRowsPerPage;
    private int mColumnsPerPage;
    private int mNumbersPerPage;
    private String mPageHeader;
    private PrintStream mPrintStream;

    public RowColumnPagePrinter(int rowsPerPage, int columnsPerPage, String pageHeader) {
        mRowsPerPage = rowsPerPage;
        mColumnsPerPage = columnsPerPage;
        mPageHeader = pageHeader;
        mNumbersPerPage = rowsPerPage * columnsPerPage;
        mPrintStream = System.out;
    }

    public void print(int data[]) {
        int pageNumber = 1;
        for (int firstIndexOnPage = 0; firstIndexOnPage < data.length; firstIndexOnPage += mNumbersPerPage) {
            int lastIndexOnPage = Math.min(firstIndexOnPage + mNumbersPerPage - 1, data.length - 1);
            printPageHeader(mPageHeader, pageNumber);
            printPage(firstIndexOnPage, lastIndexOnPage, data);
            mPrintStream.println("\f");
            pageNumber++;
        }
    }

    private void printPage(int firstIndexOnPage, int lastIndexOnPage, int[] data) {
        int firstIndexOfLastRowOnPage = firstIndexOnPage + mRowsPerPage - 1;
        for (int firstIndexInRow = firstIndexOnPage; firstIndexInRow <= firstIndexOfLastRowOnPage; firstIndexInRow++) {
            printRow(firstIndexInRow, lastIndexOnPage, data);
            mPrintStream.println("");
        }
    }

    private void printRow(int firstIndexInRow, int lastIndexOnPage, int[] data) {
        for (int column = 0; column < mColumnsPerPage; column++) {
            int index = firstIndexInRow + column * mRowsPerPage;
            if (index <= lastIndexOnPage)
                mPrintStream.format("%10d", data[index]);
        }
    }

    private void printPageHeader(String pageHeader, int pageNumber) {
        mPrintStream.println(pageHeader + " --- Page " + pageNumber);
        mPrintStream.println("");
    }

    public void setOutput(PrintStream printStream) {
        this.mPrintStream = printStream;
    }
}

class PrimeGenerator {
    private static int[] mPrimes;
    private static ArrayList<Integer> mMultiplesOfPrimeFactors;

    protected static int[] generate(int n) {
        mPrimes = new int[n];
        mMultiplesOfPrimeFactors = new ArrayList<Integer>();
        set2AsFirstPrime();
        checkOddNumbersForSubsequentPrimes();
        return mPrimes;
    }

    private static void set2AsFirstPrime() {
        mPrimes[0] = 2;
        mMultiplesOfPrimeFactors.add(2);
    }

    private static void checkOddNumbersForSubsequentPrimes() {
        int primeIndex = 1;
        for (int candidate = 3; primeIndex < mPrimes.length; candidate += 2) {
            if (isPrime(candidate))
                mPrimes[primeIndex++] = candidate;
        }
    }

    private static boolean isPrime(int candidate) {
        if (isLeastRelevantMultipleOfNextLargerPrimeFactor(candidate)) {
            mMultiplesOfPrimeFactors.add(candidate);
            return false;
        }
        return isNotMultipleOfAnyPreviousPrimeFactor(candidate);
    }

    private static boolean isLeastRelevantMultipleOfNextLargerPrimeFactor(int candidate) {
        int nextLargerPrimeFactor = mPrimes[mMultiplesOfPrimeFactors.size()];
        int leastRelevantMultiple = nextLargerPrimeFactor * nextLargerPrimeFactor;
        return candidate == leastRelevantMultiple;
    }

    private static boolean isNotMultipleOfAnyPreviousPrimeFactor(int candidate) {
        for (int n = 1; n < mMultiplesOfPrimeFactors.size(); n++) {
            if (isMultipleOfNthPrimeFactor(candidate, n))
                return false;
        }
        return true;
    }

    private static boolean isMultipleOfNthPrimeFactor(int candidate, int n) {
        return candidate == smallestOddNthMultipleNotLessThanCandidate(candidate, n);
    }

    private static int smallestOddNthMultipleNotLessThanCandidate(int candidate, int n) {
        int multiple = mMultiplesOfPrimeFactors.get(n);
        while (multiple < candidate)
            multiple += 2 * mPrimes[n];
        mMultiplesOfPrimeFactors.set(n, multiple);
        return multiple;
    }
}

重构后的代码新创建了额外的两个类,PrimeGenerator 顾名思义用来生成质数、而RowColumnPagePrinter类用来格式化结果。 每个类中的函数看起来都是那么的一目了然。

也许您会有如下疑问:

重构后的代码执行效率是不是很低啊?从一个函数变为多个类和函数的调用,这些调用操作会不会消耗很多时间啊!

关于这个问题,由于现代的虚拟机优化技术导致函数之间的调用不像远古时代那么耗费时间, 我们只能告诉您这样的代码通常不会引起效率问题,如果有一天您真的发现您代码中有效率问题,需要优化代码,那么是这种结构良好易于阅读的代码更容易优化呢?还是结构糟糕、阅读困得的代码更易优化呢?

 

使用和版本关联的组件

这节内容介绍如何添加选择不同实现的逻辑以及如何在对应的版本中选择对应的实现方式,如何创建版本感知的布局。

添加选择逻辑

TabHelper 抽象类作为
factory工厂方法类来创建版本相关的
TabHelperCompatTab 实例。

继续阅读 »

使用旧的API来实现接口

这节内容介绍如何在旧版本上模仿新版本的功能。

选择一种替代方案

在旧版本中实现新的UI特性的最具挑战性的任务就是:选择一种旧版本支持的替代方案。有时候使用旧版本中的UI特性可以模仿新的UI特性。例如:
继续阅读 »

返回顶部