Java语言中的异常处理

java异常分类

异常类层次

alt none

Throwable

Java中所以的异常都是有Throwable继承而来。

Error

Error类层次结构描述了JAVA运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的错误对象。如果程序出现了这样的内部错误,除了通告给用户,并尽力使程序安全终止之外,再无能为力。这种情况很少出现。

Exception

在设计JAVA程序时,需要关注Exception层次结构。这个层次结构又分为两个分支:

Runtime Exception

由程序错误导致的异常属于Runtime Exception,相当于C++中的logic_error类。如果出现“Runtime Exception”异常,那么就一定是你的问题。应该通过检测数组下表是否越界来避免ArrayIndexOutOfBoundsException异常;应该通过在使用变量之前检测是否为空来杜绝NullPointerException异常的发生。派生于Runtime Exception的异常包含下面几种情况:

  • 错误的类型转换
  • 数组访问越界
  • 访问空指针

IOException

派生于IOException的异常包含下面几种情况:

  • 试图在文件尾部后面读取数据
  • 试图打开一个错误格式的URL
  • 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在

未检查异常和已检查异常

未检查异常

Java语言规范将派生于Error类或RuntimeException类的所以异常称为“未检查异常(unchecked exception)”。

已检查异常

除上面所述的未检查异常外的所以异常都称为“已检查异常(checked exception)”。编译器将核查是否为所有的已检查异常提供了异常处理器。

声明异常

方法应该在其首部使用throws关键字声明所有可能抛出的异常。例如:

public FileInputStream(String name) throws FileNotFoundException

当一个方法有可能抛出多个已检查异常时,那么必须在方法的首部列出所有的异常类。例如:

class MyClass {
    public void MyMethod(String s) throws EOFException, IOException {
        //... ...
    }
}

在自己编写的方法时,不必将所有可能抛出的异常都进行声明。至于什么时候需要在方法中用throws字句声明异常,什么异常必须使用throws字句声明,需要记住在遇到下面4种情况时应该抛出异常:

  • 调用一个抛出已检查异常的方法时,例如,FileInputStream
  • 程序运行过程中发现错误,并且利用throws语句抛出一个已检查异常
  • 程序出现错误,例如,a[-1] = 0会抛出一个ArrayIndexOutOfBoundsException这样的未检查异常
  • Java虚拟机和运行库出现内部异常

如果出现前两种情况之一,则必须告诉调用这个方法的程序员有可能抛出异常。但是,并不需要声明Java的内部错误,即那些从Error继承而来的错误。任何程序代码都具有抛出那些异常的潜能,而我们对其没有任何的控制能力。同样的,也不应该声明从RuntimeException继承的那些未检查异常。例如:

    class MyClass {
       public  void MyMethod(String s) throws ArrayIndexOutOfBoundsException //这里不必要做声明未检查异常 
    }

总之一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么就应该避免(RuntingException)。如果方法没有声明所有可能发生的已检查异常,编译器就会给出一个错误信息。

子类中的异常

如果在子类中覆盖了超类的一个方法,子类方法中声明的异检查异常不能超过超类方法中声明的异常范围(也就是说,子类中抛出的异常范围更加小,或者根本不抛出异常)。

抛出异常

抛出一个已经存在的异常类,一般步骤如下:

  • 找到一个合适的异常类
  • 创建这个类的一个对象
  • 将对象抛出

例如:

void  MyMethod(Scanner in) throws EOFException {
    while(...) {
        if(!in.hasNext) {//EOF encountered
            if(n < len) 
                throw new EOFException();
        }
    }
}

创建异常

在程序中,可能会遇到任何标准异常类都没有能够充分描述清楚的问题。在这种情况下,我们可以定义一个派生于Exception或其子类的类,例如:

class FileFormatException extends IOException {
    public MyException() {}
    public MyException(String str) {
        super(str);
    }
}

使用MyException:

string readData(BufferedReader in) throws FileFormatException {
    ...
    while(...) {
        if(ch == -1){ //EOF encourntered
            if(n < len)
                throw new FileFormatException();
        }
    }
    return s;
}

捕获异常

Java中捕获异常的方法跟C++中一样,可以使用try catch字句。

捕获单个异常

public void read(String filename) {
    try{
        InputStream in = new InputStream(filename);
        int b;
        while((b = in.read()) != -1) {
            ...
        }
    } catch(IOException e) {
         e.printStackTrace();
    } finally {
        in.close();
    }
}

捕获多个异常

在一个try语句块中可以捕获多个异常类型,并对不同类型异常做不同的处理,例如:

try {
    //可能抛出异常的代码
} catch(MalformatURLException e1) {
    //处理MalformatURLException
} catch(UnknownHostException e2) {
    //处理UnknowHostException
} catch(IOException e3) {
    //处理IOException
} finally {
   //一些抛出异常后的处理
}

与C++语言的比较

  • C++中的logic_error类相当于Java中的RuntimeException
  • C++中的runtime_error类相当于Java中非RuntimeExcepton
  • C++ 中的throw与Java中的throws基本相同,但有一点重要的区别。在C++中,throw说明符是在运行时执行,而不是在编译时执行,也就是说,C++编译器将不处理任何异常说明符
  • C++中如果不给出throw声明,函数可能抛出任何异常。Java中如果没有throws说明符,函数将不能抛出任何异常检查
  • C++中可以抛出任何类型的值,Java中只能抛出Throwable子类的对象

ref:《Java 核心技术》

Nvidia显卡的xorg配置

生成xorg配置

如果发现系统/etc/X11/xorg.conf文件丢失,你可以使用下面的命令生成一个新的xorg.conf文件

$ X --configure

新生成的xorg.conf.new一般在用户目录下,具体路径请查看输出结果,得到xorg.conf.new文件后需要把它拷贝到/etc/X11/下,并且更改文件名为xorg.conf。如果这个自动生成的文件不符合需求就需要根据具体情况做相应的修改。当然,更方便的方法就使从别的机器上拷贝/etc/X11/xorg.conf到你的系统中,针对Nvidia显卡的xorg配置都使通用的,然后再做相应的修改。

单屏xorg的配置

xorg.conf内容

# nvidia-xconfig: X configuration file generated by nvidia-xconfig
# nvidia-xconfig:  version 260.19.44  ([email protected])  Sun Feb 27 21:50:39 PST 2011

Section "ServerLayout"
	InputDevice    "irtouch" "SendCoreEvents"
	Identifier     "Layout0"
	Screen      0  "Screen0"
	InputDevice    "Keyboard0" "CoreKeyboard"
	InputDevice    "Mouse0" "CorePointer"
	Option         "Xinerama" "0"
EndSection

Section "Files"
EndSection

Section "InputDevice"
	# generated from default
	Identifier     "Mouse0"
	Driver         "mouse"
	Option         "Protocol" "auto"
	Option         "Device" "/dev/psaux"
	Option         "Emulate3Buttons" "no"
	Option         "ZAxisMapping" "4 5"
EndSection

Section "InputDevice"
	# generated from default
	Identifier     "Keyboard0"
	Driver         "kbd"
EndSection

Section "Monitor"
	Identifier     "Monitor0"
	VendorName     "Unknown"
	ModelName      "Unknown"
	HorizSync       28.0 - 33.0
	VertRefresh     43.0 - 72.0
	Option         "DPMS"
EndSection

Section "Device"
	#Option        "Rotate" "CW"
	Identifier     "Device0"
	Driver         "nvidia"
	VendorName     "NVIDIA Corporation"
	BusID          "PCI:1:0:0"
EndSection

Section "Screen"
	Identifier     "Screen0"
	Device         "Device0"
	Monitor		   "Monitor0"
	Option         "TwinView" "0"
	Option         "ConnectedMonitor" "DFP-1"
	Option         "metamodes" "DFP-1: 1920x1080 +0+0"
	Option         "CustomEDID" "DFP-1:/etc/X11/edid.bin"
	SubSection     "Display"
		Depth      24
	EndSubSection
EndSection

### Touch Configuration Beginning ###
section "InputDevice"
	Identifier "irtouch"
	Driver "irtouch"
	Option "ScrenNumber" "0"
	Option "SendCoreEvents"
	Option "MinX" "0"
	Option "MinY" "0"
	Option "MaxX" "4095"
	Option "MaxY" "4095"
	Option "SwapXY" "0"
EndSection
### Touch Configuration End ###

xorg.conf解析

  • xorg.conf中的注释语句以’#’开头,遵守标准的shell注释。
  • xorg.conf配置以section为单位,每一个section都是以”<section>”开始,以””为结尾。
  • xorg.conf中”ServerLayout”,”Monitor”,”Device”,”Screen” section都有一个“Identifier”字段,这个字段可以用来把这4个section联系起来。

ServerLayout

用来配置Xserver的一些属性,比如Screen的摆放、输入输出设备等。

  • Screen 0 “Screen0”: 当前系统中使用了一个Screen,表识为0, 它对应到下面”Screen” section中表识为”Screen0″的Screen配置。当有多个Screen的时候可以使用这个字段来控制Screen的显示位置,在这个单屏系统中没有使用到这些特性。

Monitor

这个section用来配置显示器的一些信息,比如显示器的刷新率、分辨率等等。如果系统使用了EDID,就不需要更改这个section。只有当需要输出一个显示器不支持的分辨率并且不使用CustomEDID的时候才需要在这里指定刷新率、分辨率等内容。

Device

提供显卡硬件的信息。

  • BusID “PCI:1:0:0”: 系统显卡的PCI号。当有多个显卡的时候,就需要指定本Device对应哪一块显卡,PCI号可以

用下面的命令获得:

$ lspci | grep vga -i

可能的输出为:

01:00.0 VGA compatible controller: NVIDIA Corporation GT216 [GeForce GT 220] (rev a2)

把01:00.0转换成PCI:1:0:0 即是这块显卡在系统中的PCI号。

  • Option “Rotate” “CW”: 用来控制Xserver的旋转状态,可能的值有”CW”, “CCW”,分别表示顺时针和逆时针旋转90度。需要注意的是这里的旋转和X上层应用软件的旋转不是一回事。

Screen

这个section具体配置当前X的输出属性,包括输出分辨率,输出位置等。

  • Identifier “Screen0”: 本Screen的表识,被”ServerLayout”使用
  • Device “Device0”: 本Screen对应的硬件设备
  • Monitor “Monitor0”: 本Screen对应的显示器
  • Option “TwinView” “0”: 是否使用TwinView输出,TwinView可以简单理解成一块设备是否用做双屏显示,具体含义请查看“名词解释”,或者google之。
  • Option “ConnectedMonitor” “DFP-1”: 标志本Screen所使用的输出接口。可能的值有:
CRT-0: 一般是显卡的CRT输出口
DFP-1: 一般是显卡的DVI输出口
DFP-2: 一般是显卡的HDMI输出口

注:以上值可能会由于主板的不同出现不同的对应关系。

  • Option “metamodes” “DFP-1: 1920x1080_60 +0+0”: 这里给DFP-1(一般是DVI输出)指定一个分辨率(1920×1080)和偏移位置(+0+0)。显示器的左上角坐标为(0, 0),往右为X正轴,往下为Y正轴。Option “CustomEDID” “DFP-1:/etc/X11/edid.bin”: 告知Xserver不要读取显示器本身的EDID,使用这个指定的EDID,通常不推荐使用这个方式,但是当我们需要输出一个显示器不支持的分辨率时就需要用到这个属性。需要注意的是这里指定的EDID需要和显示器兼容,否则将输出黑屏,不兼容的情况包括EDID大小不一致,是否带声音等。

  • SubSection “Display”: xorg.conf支持子section,子section以”SubSection”开始,以”EndSubSection”结束。Depth 24: 指定本Screen的输出色深。可能的值有8, 16, 24, 32 。

InputDevice

配置xserver需要响应的输入设备属性,上面的例子展示的是”irtouch”公司的触摸屏配置。一般这个section由系统自动检测生成或者在安装输入设备驱动的时候自动添加。

双屏xorg的配置

xorg.conf内容

# nvidia-xconfig: X configuration file generated by nvidia-xconfig
# nvidia-xconfig:  version 260.19.44  ([email protected])  Sun Feb 27 21:50:39 PST 2011

Section "ServerLayout"
	InputDevice    "irtouch" "SendCoreEvents"
	Identifier     "Layout0"
	Screen      0  "Screen0"
	InputDevice    "Keyboard0" "CoreKeyboard"
	InputDevice    "Mouse0" "CorePointer"
	Option         "Xinerama" "0"
EndSection

Section "Files"
EndSection

Section "InputDevice"
	# generated from default
	Identifier     "Mouse0"
	Driver         "mouse"
	Option         "Protocol" "auto"
	Option         "Device" "/dev/psaux"
	Option         "Emulate3Buttons" "no"
	Option         "ZAxisMapping" "4 5"
EndSection

Section "InputDevice"
	# generated from default
	Identifier     "Keyboard0"
	Driver         "kbd"
EndSection

Section "Monitor"
	Identifier     "Monitor0"
	VendorName     "Unknown"
	ModelName      "Unknown"
	HorizSync       28.0 - 33.0
	VertRefresh     43.0 - 72.0
	Option         "DPMS"
EndSection

Section "Device"
	#Option        "Rotate" "CW"
	Identifier     "Device0"
	Driver         "nvidia"
	VendorName     "NVIDIA Corporation"
	BusID          "PCI:1:0:0"
EndSection

Section "Screen"
	Identifier     "Screen0"
	Device         "Device0"
	Monitor		   "Monitor0"
	Option         "TwinView" "1"
	Option         "ConnectedMonitor" "DFP-1, DFP-2"
	Option         "metamodes" "DFP-1: 1920x1080 +0+0, DFP-2: 1920x1080 +0+1080"
	Option         "CustomEDID" "DFP-1:/etc/X11/edid.bin; DFP-2: /etc/X11/edid.bin"
	SubSection     "Display"
		Depth      24
	EndSubSection
EndSection

### Touch Configuration Beginning ###
section "InputDevice"
	Identifier "irtouch"
	Driver "irtouch"
	Option "ScrenNumber" "0"
	Option "SendCoreEvents"
	Option "MinX" "0"
	Option "MinY" "0"
	Option "MaxX" "4095"
	Option "MaxY" "4095"
	Option "SwapXY" "0"
EndSection
### Touch Configuration End ###

xorg.conf解析

这里所谓的双屏是指由一块显卡进行两路输出(这里假设使用了DVI和HDMI输出,DVI对应到DFP-1,HDMI对应到DFP-2)。 跟单屏的配置比较会发现,大部分内容相同,主要区别出现在”Screen” section中:

  • Option “TwinView” “1”: 打开Xserver的双屏配置。
  • Option “ConnectedMonitor” “DFP-1, DFP-2”: 设置输出接口
  • Option “metamodes” “DFP-1: 1920×1080 +0+0, DFP-2: 1920×1080 +0+1080″: 这里需要为每一个输出接口设置相应的分辨率和偏移量。”+0+1080″把HDMI(DFP-2)输出到(0,1080)处,上面的实际上配置了这两个屏按垂直摆放。同理,水平摆放的配置为”+1920+0” 。
  • Option “CustomEDID” “DFP-1:/etc/X11/edid.bin; DFP-2: /etc/X11/edid.bin”: 同时为DFP-1,DFP-2指定了EDID。按需配置,可以只设置一个接口或者两个接口使用不一样的edid.bin文件。
  • 一个细节问题: “metamodes”属性中使用 逗号 作为分割符,而在”CustomEDID”属性中使用 分号 作为分割符。

输出非正常分辨率

这里所谓的非正常分辨率仅仅是指显示器不支持的分辨率,比如要在一台不支持1440×900的显示器上使用1440×900。有如下两种方法:

指定EDID法

  • 提供CustomEDID: 当xorg.conf中的Screen section被指定了CustomEDID属性,那么Xserver将不会读取物理显示器中的EDID,而是尝试加载你所指定的edid文件,比如”DFP-1:/etc/X11/edid.bin”,Xserver将读取/etc/X11/edid.bin中的配置,当然前提是确保你指定的EDID中有你需要的分辨率(这里是1440×900)。

指定”Screen”的输出分辨率:

Option         "metamodes" "DFP-1: 1440x900_60 +0+0"
  • 重启X

指定Modeline法

  • 生成Modeline: 生成Modeline的命令有:cvt, gtf, xvidtune。这里使用一般linux发行版自带的cvt: cvt命令的格式为:cvt 横向分辨率,纵向分辨率 刷新率 所以生成1440×900 60HZ分辨率的命令如下:
$ cvt 1440 900 60

输出:

Modeline "1440x900_60.00"  106.50  1440 1528 1672 1904  900 903 909 934 -hsync +vsync
提供Modeline行: 在对应的”Monitor” section中写入下面这行:
Modeline "1440x900_60.00"  106.50  1440 1528 1672 1904  900 903 909 934 -hsync +vsync
添加完 Modeline后就可以设置”Screen”的输出分辨率:
Option         "metamodes" "DFP-1: 1440x900_60 +0+0"
这里1440x900_60必须跟Modeline中的名字相同,否则xserver将找不到这个分辨率。

最后需要设置”Device”的如下属性:

Option         "ExactModeTimingsDVI" "True"
Option         "ModeValidation" "NoDFPNativeResolutionCheck"
Option         "FlatPanelProperties" "Scaling=Native"
  • 重启X,检查输出分辨率或者使用xrandr命令检查当前分辨率

可能出现的问题: 刷新频率是一个需要做微调的选项。受限以物理显示器的带宽,如果显示器使用60HZ生成的Modeline无法显示,那么需要适当的降低这个数,比如50HZ。

名词解释

TwinView

双显示器架构。在配备 NVIDIA TwinView™ 架构的情况下,单个 GPU 最终支持多显示屏幕技术。如果不是在单个显示屏的有限范围内出现堆叠的窗口,而是将不同的工作分别显示在多个显示屏幕上,效果会怎样?金融分析员可以利用一台显示器跟踪每一个数据流。图形艺术家可以将一个完整的显示屏幕用来显示调色板,而将另一个显示屏幕用来进行编辑。想象一下一边观看晚间新闻一边查收电子邮件会有怎样的感觉。支持多种显示选件(例如数字平面屏幕、RGB 显示器、电视机和模拟平面屏幕)可提供量身定做的视觉解决方案,从而满足个人需求并提高生产力。

Xinerama

Xinerama是X窗口系统的一个扩展,它使得基于X的应用程序可以把一个或多个物理显示器作为一个虚拟显示器来使用。

EDID

EDID(Extended Display Identification Data)是一种 VESA 标准数据格式,其中包含有关监视器及其性能的参数,包括供应商信息、最大图像大小、颜色设置、厂商预设置、频率范围的限制以及显示器名和序列号的字符串。这些信息保存在 display 节中,用来通过一个 DDC(Display Data Channel)与系统进行通信,这是在显示器和 PC 图形适配器之间进行的。最新版本的 EDID 可以在 CRT、LCD 以及将来的显示器类型中使用,这是因为 EDID 提供了几乎所有显示参数的通用描述。

Modeline

它可以为服务器提供有关所连接的计算机显示器的信息,以及如何在指定的显示分辨率下对其进行驱动的信息。(最初在 XFree86 上是在 XF86Config 中。)现在,在很多 Linux/UNIX 版本中,modeline 都不再需要了,因为服务器会在启动时根据各种参数来计算配置。但是当我们需要输出一个物理显示器不支持的分辨率的时候就需要为xserver写入Modeline。 一个modeline有10个参数,首先是一个指定分辨率的标签。第 2 个参数指定的是像素时钟频率(单位为 MHz)。下面是两组 4 个数字。第 1 组指定了 x 分辨率(宽度)以及相关参数;第 2 组指定的是 y 分辨率(高度)。另外,还可以添加其他参数作为选项来控制水平和垂直的同步值,还有一些选项可以控制隔行模式和双屏模式。

使用命令行工具构建 Android APK

新建工程

  • 查看构建目标

输入下面的命令查看所以可构建目标:

$android list targets

可能的输出:

Available Android targets:
----------
id: 1 or "android-3"
     Name: Android 1.5
     Type: Platform
     API level: 3
     Revision: 4
     Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
     ABIs : armeabi
----------
id: 2 or "Google Inc.:Google APIs:3"
     Name: Google APIs
     Type: Add-On
     Vendor: Google Inc.
     Revision: 3
     Description: Android + Google APIs
     Based on Android 1.5 (API level 3)
     Libraries:
      * com.google.android.maps (maps.jar)
          API for Google Maps
     Skins: QVGA-P, HVGA-L, HVGA (default), QVGA-L, HVGA-P
     ABIs : armeabi
----------
id: 3 or "android-11"
     Name: Android 3.0
     Type: Platform
     API level: 11
     Revision: 2
     Skins: WXGA (default)
     ABIs : armeabi
(等等,不一一列出)
  • 新建工程

在上一步的结果中选择一个构建目标,纪录下id后的数字,作为下面命令的target参数

$ android create yourProjectName \
> --target 1 \
> --path yourProjectFolder  \
> --activity yourActivity \
> --package com.yourdomain.project \

如果一切配置都正确,一个android工程就创建完成了。

更新工程

如果需要把工程由id:1更新到id:3,可以使用下列命令:

$ android update yourProjectName \
> --target 2 \
> --path  yourProjectFolder

构建工程

$ ant或者
$ ant debug

Android程序调用JNI

OS: MAC OS 10.7.5 Android: 4.3 NDK: android-ndk-r7c java: 1.6.0_51

使用JNI

在Eclipse中新建一个Android工程,假设项目目录为project,修改activity_main.xml 如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView android:id="@+id/showText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

MainActivity.java:

package net.lnmcc.usejni;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {
        // 加载JNI库
	static {
		System.loadLibrary("useJNI");
	}
	// 定义JNI方法 
	public native String getStringFromNative();
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 调用JNI方法 
		String strResult = getStringFromNative();
		TextView tv = (TextView)findViewById(R.id.showText);
		tv.setText(strResult);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

创建Application.mk

在项目根目录中创建Application.mk:

APP_PROJECT_PATH:=$(call my-dir)  #项目所在目录
APP_MODULES:=useJNI #应用程序的名字

编译上面的代码,在 bin/classes/net/lnmcc/usejni下生成了相应的class文件。

实现JNI

JNI头文件的生成

在项目根目录下新建jni文件夹,用来放置jni相关的文件。 JNI头文件可以使用javah来自动生成,这里的关键是路径一定要正确,:

$ cd project
$ javah -classpath bin/classes/  \
> -d jni  \
>  com.lnmcc.usejni.MainActivity #前缀一定是你的包名,否则找不到class文件

如果没有错误,javah就会自动生成net_lnmcc_usejni_MainActivity.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_lnmcc_usejni_MainActivity */

#ifndef _Included_net_lnmcc_usejni_MainActivity
#define _Included_net_lnmcc_usejni_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     net_lnmcc_usejni_MainActivity
 * Method:    getStringFromNative
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_net_lnmcc_usejni_MainActivity_getStringFromNative
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

实现JNI函数

在project/jni文件夹中新建C源代码文件,JNI函数的命名规则为:

JAVA_包名_类名_函数名

useJNI.c:

#include "net_lnmcc_usejni_MainActivity.h"

JNIEXPORT jstring JNICALL Java_net_lnmcc_usejni_MainActivity_getStringFromNative
  (JNIEnv *env, jobject obj) {

	return (*env)->NewStringUTF(env, (char*)"Hello, World");
}

创建Android.mk

在project/jni/文件夹中创建Android.mk文件:

LOCAL_PATH:=$(call my-dir) #项目根目录

include $(CLEAR_VARS) #除了LOCAL_PATH,清除其它LOCAL_变量的值

LOCAL_MODULE:=useJNI
LOCAL_SRC_FILES:=useJNI.c

include $(BUILD_SHARED_LIBRARY) # 编译成动态库

编译JNI库

$ cd project/jni
$ ndk-build #这是NDK-r7c提供的工具,确保在环境变量中

如果没有错误,输出:

Compile thumb  : useJNI <= useJNI.c
SharedLibrary  : libuseJNI.so
Install        : libuseJNI.so => libs/armeabi/libuseJNI.so

测试程序

在Eclipse中刷新项目,使在project/libs/armeabi/下出现libuseJNI.so,然后Run程序 。

WordPress twentytwelve主题修改页面宽度

Wordpress twentytwelve theme以简洁取胜,但是这个主题是固定页面宽度的(默认值为960),如果网站上放置的东西多一点就会显得拥挤不堪,破坏了其整体整洁性,下面介绍的方法可以很方便的更改这个主题的宽度:

  • 打开主题的style.css文件(可以使用WP后台编辑也可以直接进主机目录修改 一个可能的路径 /var/www/wordpress/wp-content/themes/twentytwelve

  • 查找下面的内容(在我的主机上是在655行)

/* Footer */
footer[role="contentinfo"] {
        border-top: 1px solid #ededed;                        
        clear: both;
        font-size: 12px;
        font-size: 0.857142857rem;                            
        line-height: 2;
        max-width: 960px;
        max-width: 68.571428571rem;                           
        margin-top: 24px;
        margin-top: 1.714285714rem;                           
        margin-left: auto;
        margin-right: auto;                                   
        padding: 24px 0;
        padding: 1.714285714rem 0;                            
}

把其中的max-width修改成符合你要求的数值,px和rem之间的换算关系可以简单的用px / 14来计算,比如1000px / 14 = 71.4285714rem 。

  • 查找下面这一段(在我的主机上是在1420行)
/* Minimum width of 600 pixels. */
@media screen and (min-width: 600px) {
        .author-avatar {
                float: left;
                margin-top: 8px;
                margin-top: 0.571428571rem;
        }
        .author-description {
                float: right;
                width: 80%;
        }
        .site {
                margin: 0 auto;
                max-width: 960px;
                max-width: 68.571428571rem;
                overflow: hidden;
        }

同上一步修改max-width 。

Done!