Android开发中Fragment的使用及FragmentManager findFragmentById返回nul
Android Fragment的使用
1、使用支持库
如果您的应用需要运行在3.0及以上的版本,可以忽略这部分内容。
如果您的应用使用在3.0以下、1.6及以上的版本,需要使用支持库来构建。
使用支持库的步骤:
1.使用SDK下的SDK Manager工具下载Android Support Package
2. 在您的Android工程的顶级目录下创建一个libs目录
3. 找到您的SDK下的/extras/android/support/v4/android-support-v4.jar,并且拷贝到您的项目的libs下,选中这个jar包 → 右键 → Build Path → Add to Build Path
4.在您的项目的Manifest.xml文件的标签下添加:
android:targetSdkVersion="8"/>
其中targetSdkVersion是您的软件最小支持的版本
5.如果您的项目支持3.0以下的版本,请导入如下的包:android.support.v4.*;
在使用Fragment的Activity请继承FragmentActivity而不是Activity。如果您的系统是3.0或以上版本,同样需要导入类似的包,但是可以使用普通的Activity。
2、创建一个Fragment
Fragment支持在不同的Activity中使用并且可以处理自己的输入事件以及生命周期方法等。可以看做是一个子Activity。
创建一个Fragment
创建一个Fragment和创建一个Activity很类似,继承Fragment类,重写生命周期方法,主要的不同之处就是需要重写一个onCreateView()方法来返回这个Fragment的布局。例子:
Fragment的生命周期方法依赖于Activity的生命周期,例如一个Activity的onPause()的生命周期方法被调用的时候这个Activity中的所有的Fragment的onPause()方法也将被调用。
更多的内容请参照类Fragment。
使用XML添加Fragment到Activity
尽管Fragment可以被多个Activity重用,但是您也必须把Fragment关联到一个FragmentActivity上。可以使用XML布局文件的方式来实现这种关联。
说明:上面的所说的FragmentActivity适用在API在3.0以下的版本,3.0及以上的版本可以使用普通的Activity。
例子:
上面使用fragment标签,android:name=””指定一个添加到xml中的Fragment。对于创建不同的屏幕尺寸布局的更多信息,请阅读支持不同的屏幕尺寸。
当您添加一个片段一个活动布局定义的布局XML文件中的片段,你不能删除在运行时的片段。如果您打算在用户交互和交换片段,你必须添加的活性片段的活动时第一次启动。
3、构建一个灵活的UI
FragmentManager提供了对Activity运行时的Fragment的添加、删除、替换的操作。
在Activity运行期间你可以添加Fragment而不是在XML布局文件中进行定义。如果你打算在Activity中改变Fragment的生命过程。
如果要执行添加、删除、修改的操作,你必须通过FragmentManager的对象获得一个FragmentTransaction对象,通过它的API来执行这些操作。
添加一个Fragment到一个Activity,必须把这个Fragment添加到一个容器视图中。例子:
在Activity中你可以通过getFragmentManager()来获得Fragment对象,然后通过FragmentManager对象的beginFragmentTransaction()方法来获得FragmentTransaction对象。通过它的add()方法来添加一个Fragment到当前的Activity中。
一个FragmentTransaction对象可以执行多个增删修的方法,如果你想把这些修改提交到Activity上,必须在最后调用一下这个对象的commit()方法。例子:
由于不是定义在XML布局中的,所有可以转型删除和修改的操作。
如果替换或者删除一个Fragment然后让用户可以导航到上一个Fragment,你必须在调用commit()方法之前调用addToBackStack()方法添加到回退栈。如果你把这个Fragment添加到了回退栈,在提交之后这个Fragment是会被Stop而不是Destroyed。如果用户导航到这个Fragment,这个Fragment会被Restart而不是重新创建。如果你没有把它添加到回退栈,则在删除或者替换的时候它将被Destroyed。例子:
4、与其他Fragment的交互
两个单独的Fragment之间是不应该进行通信的。应该使用他们所存在的Activity作为沟通的纽带。
为了实现两个Fragment的交互,您可以在Fragment中定义一个接口,然后再这个接口中定义一个方法,在Fragment的onAttach()方法中调用这个接口中的方法。然后让Activity实现这个方法来完成Activity和Fragment之间的通信。例子:
定义接口并调用方法:
实现接口,在这个方法中可以进行与其他Fragment的数据的交互:
可以通过FragmentManager的findFragmentById()来查找一个Fragment。
FragmentManager findFragmentById返回nul解决办法
看Fragment的两种生成方式
一.用xml标签生成
在fragment的宿主activity中添加xml标签
<fragment
android:id="@+id/fragment_newsContent"
android:name="com.firstcode.section4_news.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
name为你创建的fragment类
这种方法在activity创建时fragment已经生成了
在Activity中获取fragment实例的操作:
NewsContentFragment fragment = (NewsContentFragment) getFragmentManager().findFragmentById(R.id.fragment_newsContent);
二、用java代码动态生成
在fragment的宿主activity的视图文件中添加FrameLayout进行占位
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragmentContainer"/>
在Activity中生成fragment的操作
FragmentManager fm = getFragmentManager();
fm.beginTransaction()
.add(R.id.fragmentContainer,“你创建的fragment类实例”)
.commit();
问题分析:
我在使用用FragmentManager.findFragmentById 返回nul的问题就在这,我是通过第二种方式来生成fragment的,也就是说在findFragmentById的实参
我填的是FrameLayout的Id,而非fragment的Id 所以会返回null
解决方案:
1.如果是静态生成fragment,获取fragment实例用getFragmentManager().findFragmentById
2.如果是java代码动态生成fragment,获取fragment实例直接new 一个就好了 没必要用getFragmentManager().findFragmentById
3.注意xml文件中的标签FrameLayout与fragment
还有个问题,我也是这样解决的 在fragment视图里给textview添加文字
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
原因是通过java代码生成的fragment add里的Id参数填的是fragment的id 所以fragment的视图没有生成
理解两种fragment生成方式最好的文档莫过于google官方的Android Training下面是中文翻译
使用xml标签添加fragment
使用java代码动态添加fragment
Android应用程序的组成部分和Manifest文件
Android应用程序由松散耦合的组件组成,并使用应用程序Manifest绑定到一起;应用程序Manifest描述了每一组件和它们之间的交互方式,还用于指定应用程序元数据、其硬件和平台要求、外部库以及必需的权限。
一、应用程序的基本结构模块
· Activity:应用程序的表示层。每个UI都是通过Activity类的一个或多个扩展实现的。Activity使用Fragment和视图来布局和显示信息,以及响应用户动作。
· Service:应用程序中不可见的工作者。运行时没有UI,可以更新数据源和Activity、触发通知和广播Intent。可以用来执行一个运行时间长的任务,或者不需要和用户交互的任务。
· Content Provider:可共享的持久数据存储器(内容提供者)。用来管理和持久化应用程序数据,通常会与SQL数据库交互。可以通过配置自己的Content Provider来允许其他应用程序访问,也可以访问其他应用。
· Intent:消息传递框架。Android中大量使用了Intent、Service或者Broadcast Receiver广播消息,以及请求对特定的一条数据执行操作。
· Broadcast Receiver: Intent侦听器(广播接收者)。可以监听到那些匹配指定的过滤标准的Intent广播。它会自动地启动应用程序来响应某个接收到Intent。
· Widget:可视化应用程序组件。它是Broadcast Receiver的特殊变体,可用于创建动态的交互式应用程序组件,用户可以把这些组件添加到他们的主屏幕上。
· Notification:它允许向用户发送信号,但却不会过分吸引他们的注意力或者打断他们当前的Activity。它们是应用程序不可见或者不活动时吸引用户注意的首选方法。
二、Manifest文件简介
每一个Android项目都包含一个Manifest文件——Android Manifest.xml,它存储在项目层次中的最底层。Manifest可以定义用用程序及其组件和需求的结构和元数据。
Manifest包含了组成应用程序的每一个Activity、Service、Content Provider和Broadcast Receiver的节点,并使用Intent Filter和权限来确定这些组件和其他应用程序是如何交互的。此文件还可以指定应用程序的元数据(图标、版本号、主题等等) 以及额外的顶层节点,这些节点可以指定必需的安全权限和单元测试,以及定义硬件、屏幕和平台支持要求。
Manifest文件有一个根manifest标签构成,该标签带有一个被设为项目包的package属性。它通常包含一个xmls:android属性来提供文件内使用的某些系统属性。
使用versionCode属性可讲当前的应用版本定义为一个整数,每次版本更新,这个数字都会增加。使用versionName可以定义一个显示给用户的公共版本号。
installLocation属性,是制定是否允许将程序安装到SD卡上,其值有preferExternal(首选外部存储器)和auto(系统决定)。不指定时,默认按到内部存储器中。由于取出或拒绝外部存储器存在的问题,以下程序不适合安装到外部存储器及其后果:
· 具有Widget/Live Wallpaper和Live Folder的应用程序: Widget/Live Wallpaper和Live Folder将从主屏幕上移除,而且重启系统后可能不在可用。
· 提供不中断服务的应用程序:程序和它运行的服务将被停止,并且不会自动重启。
· 输入法引擎:安装到外部存储器的任何IME都会被禁用。在外部存储器再次可用后,用户必须重新选择IME。
· 设备管理器:DeviceAdminReceiver及其管理能力将被禁用。
Manifest文件节点详解
首先看一下Manifest文件最基本的结构:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.codingblock.manifesttest" android:versionCode="1" android:versionName="1.0" android:installLocation="preferExternal" > <!-- ...nodes... --> </manifest>
manifest标签包含了一些节点(node),定义了组成应用程序的应用程序组建、安全设置、测试类和需求。下面是一些manifest子节点标签:
· uses-sdk:要想正确的运行程序,需要有minSKDVersion(默认值:1)、maxSDKVersion和targetSDKVersion属性。
· uses-configuration:使用此节点可以指定应用程序支持的每个输入机制的组合。一般不需要包含这个节点,不过对于需要特殊输入控制的游戏说很有用。以下是它的几个属性:
· reqFiveWayNav:要求设备有上、下、左、右导航,并且能够单击当前的选项时为true。包括跟踪求和D-pad。
· reqHarKeyboard:要求设备有硬件键盘时为true。
· reqKeyboardType:指定键盘类型为nokeys、qwerty、twelvekey、undefined。
· reqNavigation:导航设备(值:nonav、dpad、trackball、wheel或undefined)。
· reqTouchScreen:以指定必需的触摸屏输入(notouch、stylus、finger或undefined)。
· uses-feature:Android可以在各种各样硬件平台上运行。可以使用多个uses-feature节点来指定应用程序需要的每个硬件功能,以避免安装到不包含硬件功能的设备上。(如:NFC、蓝牙、摄像头等等)
· supports-screens:用于指定应用程序针对那些屏幕尺寸惊醒了设计和测试。当应用程序支持某个设备的屏幕是,一般就会使用开发人员提供的布局文件中的缩放属性来布局。在不支持的设备上运行时,系统可能会应用“兼容模式”来显示应用程序。
· supports-gl-texture:用于声明应用程序能够提供以一种特定的GL纹理压缩格式压缩的纹理资源。如果应用程序能够多种纹理压缩格式,就必须使用多个supports-gl-texture元素。
· uses-permission:声明应用程序所需权限。
· permission:应用程序组件也可以创建权限来限制对共享应用程序组件的访问。(可以使用permission标签来创建权限定义)
· instrumentation:instrumentation类提供了一个测试框架,用来在应用程序运行时测试应用程序组件。
· application:一个Manifest只能包含一个application节点。用于指定应用程序的各种元数据(标题、图标和主题)。在开发时,建议将debuggable设为true,以启用调试,发布时可以禁用此属性。application节点包含了Activity、Service、Content Provider和Broadcast Receiver等子节点。并通过创建和是用自己的Application类扩展来管理应用程序的状态。
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:debuggable="true" > <!-- ...nodes... --> </application>
以下是对application子节点的简单介绍:
· activity:应用程序的每一个Activity都需要一个此节点,并使用andorid:name属性来指定Activity类的名称。必须包含核心的启动Activity和其他所有可显示的Activity。启动一个没有定义的Activity就会抛出运行时异常。每一个activity节点都可以使用intent-filter子标签来定义用于启动该Activity的Intent。(指定类名时,可以使用“.”作为简写方式代替应用程序的包名)如下代码:
<activity android:name="com.codingblock.manifesttest.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
· service和activity标签一样,需要为应用程中使用的每一Service类添加一个此标签。同样它也支持使用intent-filter子标签来进行运行时绑定。
<service android:name=".MyService"> </service>
· provider:此标签用于指定应用程序中的每一Content Provider。(Content Provider用来管理数据库访问和共享)
<provider android:name=".MyContentProvider" android:authorities="com.codingblock.manifesttest.MyContentProvider"> </provider>
· receiver:通过添加receiver标签,可以注册一个Broadcast Receiver,而不用事先启动应用程序。一旦注册了之后,无论何时,只要与它相匹配的Intent被系统或应用程序广播出来,它就会立即执行。通过在manifest中注册一个Broadcast Receiver,可以使这个进程实现完全自治。如果一个匹配的Intent被广播了,则应用程序就会自动启动,并且你注册的Broadcast Receiver也会开始执行。每一个receiver节点都允许使用intent-filter子标签来定义可以用来触发接收器的Intent:
<receiver android:name=".MyIntentReceiver"> <intent-filter> <action android:name="com.codingblock.manifesttest.MyIntentReceiver"/> </intent-filter> </receiver>
· uses-library:用于指定该应用程序需要的共享库。
最近在做的项目中有很多下拉框,为了实现方便就用了Android 自带的Spinner,但是自带的Spinner的样式又不符合要求,就学习了一下自定义Spinner。下面是整个步骤:
1.准备好图片
2.style中定义
<!-- spinner -->
<style name="spinner_style">
<item name="android:background">@drawable/spinner</item>
<item name="android:paddingLeft">5dip</item>
3.调用
<Spinner
android:id="@+id/field_item_spinner_content"
style="@style/spinner_style"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
4.在layout中定义simple_spinner_item.xml
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:gravity="center_vertical"
android:textColor="#808080"
android:singleLine="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
5.java代码
ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext,R.layout.simple_spinner_item);
String level[] = getResources().getStringArray(R.array.affair_level);//资源文件
for (int i = 0; i < level.length; i++) {
adapter.add(level[i]);
}
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
效果图:
android应用开发中,加载显示大图片,我们可以使用BitmapFactory.Options,本文我们来讲讲BitmapFactory.Options的使用及BitmapFactory.Options避免 内存溢出 OutOfMemoryError的优化方法。
android中BitmapFactory.Options的使用是在加载图片时,就从图片的加载和使用说起
怎样获取图片的大小?
首先我们把这个图片转成Bitmap,然后再利用Bitmap的getWidth()和getHeight()方法就可以取到图片的宽高了。
新问题又来了,在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时,遇到大一些的图片,我们经常会遇到OOM(Out Of Memory)的问题。怎么避免它呢?
这就用到了我们上面提到的BitmapFactory.Options这个类。
BitmapFactory.Options这个类,有一个字段叫做 inJustDecodeBounds 。SDK中对这个成员的说明是这样的:
If set to true, the decoder will return null (no bitmap), but the out…
也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(String path, Options opt)并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。
示例代码如下:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(path, options);/* 这里返回的bmp是null */
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(path, options);/* 这里返回的bmp是null */
这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了。
有了宽,高的信息,我们怎样在图片不变形的情况下获取到图片指定大小的缩略图呢?
比如我们需要在图片不变形的前提下得到宽度为200的缩略图。
那么我们需要先计算一下缩放之后,图片的高度是多少 ,代码如下
int height = options.outHeight * 200 / options.outWidth;
options.outWidth = 200;
options.outHeight = height;
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
image.setImageBitmap(bmp);
int height = options.outHeight * 200 / options.outWidth;
options.outWidth = 200;
options.outHeight = height;
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
image.setImageBitmap(bmp);
这样虽然我们可以得到我们期望大小的ImageView
但是在执行BitmapFactory.decodeFile(path, options);时,并没有节约内存。要想节约内存,还需要用到BitmapFactory.Options这个类里的 inSampleSize 这个成员变量。
我们可以根据图片实际的宽高和我们期望的宽高来计算得到这个值。
options.inSampleSize = options.outWidth / 200;
/*图片长宽方向缩小倍数*
options.inSampleSize = options.outWidth / 200;
/*图片长宽方向缩小倍数*/
另外,为了节约内存我们还可以使用下面的几个字段:
options.inDither=false;/*不进行图片抖动处理*/
options.inPreferredConfig=null; /*设置让解码器以最佳方式解码*/
/* 下面两个字段需要组合使用 */
options.inPurgeable = true;
options.inInputShareable = true;
android的BitmapFactory.Options避免内存溢出OOM的优化方法
尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,
因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,
decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,
无需再使用java层的createBitmap,从而节省了java层的空间。
如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常
另外,decodeStream直接拿的图片来读取字节码了, 不会根据机器的各种分辨率来自动适应,
使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,
否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
另外,以下方式也大有帮助:
1. InputStream is = this.getResources().openRawResource(R.drawable.pic1);
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = 10; //width,hight设为原来的十分一
Bitmap btp =BitmapFactory.decodeStream(is,null,options);
2. if(!bmp.isRecycle() ){
bmp.recycle() //回收图片所占的内存
system.gc() //提醒系统及时回收
}
以下奉上一个方法:
Java代码
/** * 以最省内存的方式读取本地资源的图片 * @param context * @param resId * @return */ public static Bitmap readBitMap(Context context, int resId){ BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inPreferredConfig = Bitmap.Config.RGB_565; opt.inPurgeable = true; opt.inInputShareable = true; //获取资源图片 InputStream is = context.getResources().openRawResource(resId); return BitmapFactory.decodeStream(is,null,opt); }
优化Dalvik虚拟机的堆内存分配
对 于Android平台来说,其托管层使用的Dalvik JavaVM从目前的表现来看还有很多地方可以优化处理,比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。当然具体 原理我们可以参考开源工程,这里我们仅说下使用方法: private final static floatTARGET_HEAP_UTILIZATION = 0.75f; 在程序onCreate时就可以调用 VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。
介绍一下图片占用进程的内存算法吧。
android中处理图片的基础类是Bitmap,顾名思义,就是位图。占用内存的算法如下:
图片的width*height*Config。
如果Config设置为ARGB_8888,那么上面的Config就是4。一张480*320的图片占用的内存就是480*320*4 byte。
前面有人说了一下8M的概念,其实是在默认情况下android进程的内存占用量为16M,因为Bitmap他除了java中持有数据外,底层C++的 skia图形库还会持有一个SKBitmap对象,因此一般图片占用内存推荐大小应该不超过8M。这个可以调整,编译源代码时可以设置参数。
android 加载库后,如果重复加载同一个库,会出现已经加载得警告,也就是说,就不会重新加载so文件。这时候需要kill掉对应得activity,然后重新启动activity就可以使得so重新加载,对应代码:
int pid = android.os.Process.myPid();
android.os.Process.killProcess(pid);
Android Jni 用动态库的加载与卸载函数说明
一、当 Android 的 Virtual Machine 执行到 System.loadLibrary( "动态库名" ) 函数时,
首先会去执行 C 语言动态库里的 JNI_OnLoad 函数。
它的用途有两个:
1)告诉 Virtual Machine 当前动态库使用了哪个版本的 Jni。
如果当前动态库中没有提供 JNI_OnLoad 函数,
Virtual Machine 会默认为动态库使用的是最老的 Jni 1.1 版本。
由于新版 Jni 做了许多扩充,例如 Jni 1.4 的 java.nio.ByteBuffer。
2)动态库的开发者可以在 JNI_OnLoad 函数中进行动态库内的初始化设置(Initialization),
将此动态库中提供的各个本地函数(Native Function)登记到 Virtual Machine 里,
以便能加快以后调用动态库中的本地函数的效率,就是初始化设置的重要一项。
应用层级的 Java 类通过 Virtual Machine 才能调用到动态库中的本地函数。
如果没有注册登记过的话,Virtual Machine 就在 动态库名.so 里寻找要调用的本地函数。
如果需要连续调用很多次且每次都需要寻找一遍的话,会多花许多时间。
因此 C 语言动态库开发者可以自已将动态库中的本地函数向 Virtual Machine 进行注册登记。
代码示例:(注:由于新浪博客不支持 C 注释,所以请将 /* */ 想像替换为 /星 星/)
jint
JNI_OnLoad( JavaVM* vm,
void* reserved )
{
jint jintResult = -1;
JNIEnv* env = NULL;
/*Reference types, in C.
typedef void* jobject;
typedef jobject jclass; */
jclass cls = NULL;
/* typedef struct {
const char* name; /* Java 代码中调用的函数名字 */
const char* signature; /* 描述了函数的 参数 和 返回值 */
void* fnPtr; /* 函数指针转成无符号指针 */
} JNINativeMethod;
其中比较复杂的是第二个参数,
例如 "()V" 或 "(II)V" 或 "(Ljava/lang/String;)V"
实际上这些字符是与函数的 参数 及 返回值 类型是一一对应的,
括号()中的字符表示参数,括号后面的则代表返回值,
例如 "()V" 就表示 void 函数名();
"(II)V" 就表示 void 函数名( int, int );
"(Ljava/lang/String;)V" 就表示 void 函数名( jstring );
具体的每一个字符所表示的意义下面部分有所详见 */
/* 动态库中的本地函数信息数组 */
JNINativeMethod aJNINativeMethod[] = {
{ "MeasureDistance",
"(Ljava/lang/String;)V",
(void*)Java_MyJni_MyNDK_MyDemo_MyJniNDKDemo_MeasureDistance }
};
/* #if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif */
/* JavaVM::GetEnv 原型为 jint (*GetEnv)(JavaVM*, void**, jint); */
/* GetEnv()函数返回的 Jni 环境对每个线程来说是不同的,*/
/* 因此我们必须在每次进入函数时都要重新获取 */
if ( JNI_OK != (*vm)->GetEnv( vm,
(void**)env,
JNI_VERSION_1_6 ) )
{
/* 输出的 log 一般是到 /dev/log/ 下的三个设备中,可以用 logcat 工具查看 */
__android_log_write( ANDROID_LOG_INFO, /* 日志信息 */
"MyJniDemo", /* 日志标签 */
"Call JavaVM::GetEnv failed" ); /* 日志内容 */
return jintResult; /* 此时返回的是负壹(-1) */
}
/* 如果 将动态库中的本地函数向 Virtual Machine 进行注册登记失败 的话,则 */
/* 由于 aJNINativeMethod 是一组 函数名称 与 函数指针 的对照表,
在程序执行期间可以多次调用registerNativeMethods函数来更换注册登记本地函数 */
/* #if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif */
/* Reference types, in C.
typedef void* jobject;
typedef jobject jclass; */
/* struct JNINativeInterface 里的函数指针
jint (*RegisterNatives)( JNIEnv*,
jclass,
const JNINativeMethod*,
jint ); */
cls = (*env)->FindClass( env,
/* 下面的字符串就是描述 Java 代码中的主类 */
"MyJni/MyNDK/MyDemo/MyJniNDKDemo" );
if ( 0 > (*env)->RegisterNatives( env,
cls,
aJNINativeMethod,
sizeof( aJNINativeMethod ) /
sizeof( aJNINativeMethod[0] ) ) )
{
/* 输出的 log 一般是到 /dev/log/ 下的三个设备中,可以用 logcat 工具查看 */
__android_log_write( ANDROID_LOG_INFO, /*日志信息*/
"MyJniDemo", /*日志标签*/
"Register native methods failed" ); /*日志内容*/
return jintResult; /* 此时返回的是负壹(-1) */
}
jintResult = JNI_VERSION_1_6;
/* 此函数回传 JNI_VERSION_1_6 宏值给 Virtual Machine,
于是 Virtual Machine 就知道当前动态库所使用的 Jni 版本了 */
return jintResult; /* JNI_VERSION_1_6(0x00010006) */
}
二、JNI_OnUnload 函数与 JNI_OnLoad 函数相对应。
在 JNI_OnLoad 函数中进行的动态库内的初期化设置,
要在 Virtual Machine 释放该动态库时调用 JNI_OnUnload 函数来进行善后清除。
同 Virtual Machine 调用 JNI_OnLoad 一样,
调用 JNI_Unload 函数时,也会将 JavaVM 的指针做为第一个参数传递,原型如下:
jint
JNI_OnUnload( JavaVM* vm,
void* reserved );
三、JNINativeMethod::signature 描述字符串字符意义说明:
1)基本类型对应关系:
标识符 Jni 类型 C 类型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
2)基本类型数组:(则以 [ 开始,用两个字符表示)
标识串 Jni 类型 C 类型
[Z jbooleanArray boolean[]
[I jintArray int[]
[J jlongArray long[]
[D jdoubleArray double[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
3)类(class):(则以 L 开头,以 ; 结尾,中间是用 / 隔开的 包 及 类名)
标识串 Java 类型 Jni 类型
L包1/包n/类名; 类名 jobject
例子:
Ljava/net/Socket; Socket jobject
4)例外(String 类):
标识串 Java 类型 Jni 类型
Ljava/lang/String; String jstring
5)嵌套类(类位于另一个类之中,则用$作为类名间的分隔符)
标识串 Java 类型 Jni 类型
L包1/包n/类名$嵌套类名; 类名 jobject
例子:
Landroid/os/FileUtils$FileStatus; FileStatus jobject
相关文章
- 有时为了网站安全和版权问题,会对自己写的php源码进行加密,在php加密技术上最常用的是zend公司的zend guard 加密软件,现在我们来图文讲解一下。 下面就简单说说如何...2016-11-25
- 下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
- ps软件是现在很多人都会使用到的,HSL面板在ps软件中又有着非常独特的作用。这次文章就给大家介绍下ps怎么使用HSL面板,还不知道使用方法的下面一起来看看。  ...2017-07-06
详解redis desktop manager安装及连接方式
这篇文章主要介绍了redis desktop manager安装及连接方式,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-15- 许多的朋友对于Plesk控制面板应用不是非常的了解特别是英文版的Plesk控制面板,在这里小编整理了一些关于Plesk控制面板常用的使用方案整理,具体如下。 本文基于Linu...2016-10-10
使用insertAfter()方法在现有元素后添加一个新元素
复制代码 代码如下: //在现有元素后添加一个新元素 function insertAfter(newElement, targetElement){ var parent = targetElement.parentNode; if (parent.lastChild == targetElement){ parent.appendChild(newEl...2014-05-31Android开发中findViewById()函数用法与简化
findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20- 如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
- 大概有如下步骤 新建项目Bejs 新建文件package.json 新建文件Gruntfile.js 命令行执行grunt任务 一、新建项目Bejs源码放在src下,该目录有两个js文件,selector.js和ajax.js。编译后代码放在dest,这个grunt会...2014-06-07
使用percona-toolkit操作MySQL的实用命令小结
1.pt-archiver 功能介绍: 将mysql数据库中表的记录归档到另外一个表或者文件 用法介绍: pt-archiver [OPTION...] --source DSN --where WHERE 这个工具只是归档旧的数据,不会对线上数据的OLTP查询造成太大影响,你可以将...2015-11-24如何使用php脚本给html中引用的js和css路径打上版本号
在搜索引擎中搜索关键字.htaccess 缓存,你可以搜索到很多关于设置网站文件缓存的教程,通过设置可以将css、js等不太经常更新的文件缓存在浏览器端,这样访客每次访问你的网站的时候,浏览器就可以从浏览器的缓存中获取css、...2015-11-24- 夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
- 为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
- 如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
jQuery 1.9使用$.support替代$.browser的使用方法
jQuery 从 1.9 版开始,移除了 $.browser 和 $.browser.version , 取而代之的是 $.support 。 在更新的 2.0 版本中,将不再支持 IE 6/7/8。 以后,如果用户需要支持 IE 6/7/8,只能使用 jQuery 1.9。 如果要全面支持 IE,并混合...2014-05-31安装和使用percona-toolkit来辅助操作MySQL的基本教程
一、percona-toolkit简介 percona-toolkit是一组高级命令行工具的集合,用来执行各种通过手工执行非常复杂和麻烦的mysql和系统任务,这些任务包括: 检查master和slave数据的一致性 有效地对记录进行归档 查找重复的索...2015-11-24- 深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
- 一、下载 mysqlsla [root@localhost tmp]# wget http://hackmysql.com/scripts/mysqlsla-2.03.tar.gz--19:45:45-- http://hackmysql.com/scripts/mysqlsla-2.03.tar.gzResolving hackmysql.com... 64.13.232.157Conn...2015-11-24
- 目前,JSON已经成为最流行的数据交换格式之一,各大网站的API几乎都支持它。我写过一篇《数据类型和JSON格式》,探讨它的设计思想。今天,我想总结一下PHP语言对它的支持,这是开发互联网应用程序(特别是编写API)必须了解的知识...2015-10-30
- 下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02