Andriod开发中AsyncHttpClient类库学习教程

 更新时间:2016年9月20日 19:58  点击:1443
Andriod开发AsyncHttpClient类是异步的,我们可以通过AsyncHttpClient实例请求网络,比如get、post等。

AsyncHttpClient client = newAsyncHttpClient();
 client.get("http://www.google.com", newAsyncHttpResponseHandler() {
 @Override
 public void onSuccess(String response) {
   System.out.println(response);
 }

});



通过AsyncHttpClient类的实例就可以执行网络请求,包括get、put、post、head、delete。并指定一个ResponseHandlerInterface的实例接收请求结果。(onSuccess参数不对,此处只说明基本用法,详细参数看源码)


主要类介绍

    AsyncHttpRequest

继承自Runnabler,被submit至线程池执行网络请求并发送start,success等消息

    AsyncHttpResponseHandler

接收请求结果,一般重写onSuccess及onFailure接收请求成功或失败的消息,还有onStart,onFinish等消息

    TextHttpResponseHandler

继承自AsyncHttpResponseHandler,只是重写了AsyncHttpResponseHandler的onSuccess和onFailure方法,将请求结果由byte数组转换为String

    JsonHttpResponseHandler

继承自TextHttpResponseHandler,同样是重写onSuccess和onFailure方法,将请求结果由String转换为JSONObject或JSONArray

    BaseJsonHttpResponseHandler

继承自TextHttpResponseHandler,是一个泛型类,提供了parseResponse方法,子类需要提供实现,将请求结果解析成需要的类型,子类可以灵活地使用解析方法,可以直接原始解析,使用gson等。

    RequestParams

请求参数,可以添加普通的字符串参数,并可添加File,InputStream上传文件

    AsyncHttpClient

核心类,使用HttpClient执行网络请求,提供了get,put,post,delete,head等请求方法,使用起来很简单,只需以url及RequestParams调用相应的方法即可,还可以选择性地传入Context,用于取消Content相关的请求,同时必须提供ResponseHandlerInterface(AsyncHttpResponseHandler继承自ResponseHandlerInterface)的实现类,一般为AsyncHttpResponseHandler的子类,AsyncHttpClient内部有一个线程池,当使用AsyncHttpClient执行网络请求时,最终都会调用sendRequest方法,在这个方法内部将请求参数封装成AsyncHttpRequest(继承自Runnable)交由内部的线程池执行。

    SyncHttpClient

继承自AsyncHttpClient,同步执行网络请求,AsyncHttpClient把请求封装成AsyncHttpRequest后提交至线程池,SyncHttpClient把请求封装成AsyncHttpRequest后直接调用它的run方法。


请求流程

    调用AsyncHttpClient的get或post等方法发起网络请求

    所有的请求都走了sendRequest,在sendRequest中把请求封装为了AsyncHttpRequest,并添加到线程池执行

    当请求被执行时(即AsyncHttpRequest的run方法),执行AsyncHttpRequest的makeRequestWithRetries方法执行实际的请求,当请求失败时可以重试。并在请求开始,结束,成功或失败时向请求时传的ResponseHandlerInterface实例发送消息

    基本上使用的都是AsyncHttpResponseHandler的子类,调用其onStart,onSuccess等方法返回请求结果

详细使用方法

官方建议使用一个静态的AsyncHttpClient,像下面的这样:

public class TwitterRestClient {
 private static final String BASE_URL = "http://api.twitter.com/1/";
 private static AsyncHttpClient client = newAsyncHttpClient();

 public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
 client.get(getAbsoluteUrl(url), params, responseHandler);
}
public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
 client.post(getAbsoluteUrl(url), params, responseHandler);
}
private static String getAbsoluteUrl(String relativeUrl) {
 return BASE_URL + relativeUrl;
}
}

封装的方法建议都加上Context参数,以在Activity pause或stop时取消掉没用的请求。

详细使用方法就不说了,直接看官方文档


其他说明及总结

Android-Async-Http的使用非常简单,通过AsyncHttpClient发起请求就可以了,如果需要添加参数,直接传一个RequestParams过去,而且参数可以是String、File和InputStream,可以很方便地上传文件。

每个请求都需要传一个ResponseHandlerInterface的实例用以接收请求结果或请求失败,请求结束等通知,一般是AsyncHttpResponseHandler的子类。

通过BinaryHttpResponseHandler可以发起二进制请求,如请求图片。

通过TextHttpResponseHandler可以发起返回结果为字符串的请求,一般这个使用较多。

也可以使用它的子类JsonHttpResponseHandler,返回结果是一个JSONObject或JSONArray。不过感觉这个类作用不大,一是有另一个类BaseJsonHttpResponseHandler,可以直接解析返回的JSON数据,二是JsonHttpResponseHandler的方法太复杂了,有太多的onSuccess和onFailure方法,都不知道重写哪个了。


如上图所示,每个子类有太多的onSuccess和onFailure了,尤其是JsonHttpResponseHandler,这应该算是这个类库的不足吧。所以平时使用时基本不使用JsonHttpResponseHandler,而是直接使用TextHttpResponseHandler,当然也可以使用BaseJsonHttpResponseHandler。

这个类库还有一点不足,就是onSuccess等方法一般会在主线程执行,其实这么说不严谨,看代码吧:

public AsyncHttpResponseHandler() {

   boolean missingLooper = null == Looper.myLooper();

   // Try to create handler

   if (!missingLooper)

       handler = new ResponderHandler(this);

   else {

       // There is no Looper on this thread so synchronous mode should be used.

       handler = null;

       setUseSynchronousMode(true);

       Log.i(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode.");

   }

   // Init Looper by calling postRunnable without an argument.

   postRunnable(null);

}

可以看到,内部使用了Handler,当新建AsyncHttpResponseHandler的实例的时候会获取当前线程的Looper,如果为空就启用同步模式,即所有的回调都会在执行请求的线程中执行,当在一个普通的后台线程时这样执行是正常的,而我们一般都会在主线程发请请求,结果就是所有的回调都会在主线程中执行,这就限制了我们在onSuccess中执行耗时操作,比如请求成功后将数据持久化到数据库。

不过可以看到创建Handler的时候使用了Looper对象,所以我们就可以改进一下其构造函数,添加一个Looper参数(同步修改子类),这样所有的回调就都会在Looper所在线程执行,这样我们只需要开启一个HandlerThread就行了。但这样和Looper为空时一样有一个弊端,如果要更新UI操作的话,还需要向一个主线程的Handler发送消息让UI更新。还有第二个弊端,所有回调都在同一个HandlerThread中执行,如果一个处理耗时太久会阻塞后面的请求结果处理,如果只是简单地写个数据库影响应该不大,如果真耗时太久,为这个耗时处理再开个线程

android手机安装包频繁提示解析错误怎么解决呢?解析错误一下是包有问题或不是安卓系统所支持的安装包了,下面我们一起来看问题的一个解决办法。

 Android操作系统作为目前唯一可以与苹果iOS系统平分秋色的一款新生系统,它之所以成长的如此之快,除了其很强的开源性,Android系统一个很大的优势就在于其海量增长的应用程序。一款好玩的应用程序是充实闲暇时光的一柄利器,当我们新入手一款Android手机,慢慢熟悉后或多或少都会想到丰富其内置的应用程序,看到好玩的游戏或软件都会想要下载安装。而如果大家的Android手机在安装apk程序途中弹出“解析包时出现问题”这样的提示,会不会觉得很揪心呢?那么Android解析包出现问题有没有好的解决办法呢?

安卓android手机安装包频繁提示解析错误解决方法1

    安卓android手机安装包频繁提示解析错误解决方法介绍:

一、应用程序本身问题

  Android apk程序解析包出现问题的话,可能是由于你下载的apk程序本身就有问题,程序的压缩包可能在下载过程中被损坏了,建议请重新下载一次。

二、系统版本不支持

  如果重新下载也解决不了Android解析包出现问题的话,很大一个可能就是在于你的手机的配置参数不支持这款软件,举个例子吧,如果一款apk程序的系统版本要求在Android 4.0以上,而你的手机则是Android 2.3系统,就会出现“解析包时出现问题”这样的解析错误。

安卓android手机安装包频繁提示解析错误解决方法2

三、RE管理器设置问题

  进入RE管理器——设置——常规设置——主文件夹选项,有的网友反映如果将其设置成“sdcard\ ”就会出现“解析包出现问题”的错误提示,而如果将其设置“\ ”就可以成功安装,大家也可以试试!

安卓android手机安装包频繁提示解析错误解决方法3

以上就是安卓android手机安装包频繁提示解析错误解决方法的全部内容,遇到这种情况的朋友可以照着以上方法进行尝试!

为了优化Android应用的启动速度,我们在首次初始化时导入静态数据库到Android应用中。本文就来讲讲如何实现这个功能。

一个Android除了要有好的创意和美观的界面,性能也是很关键的部分,本文讨论的就是第一次启动的速度问题。 Android应用的启动过程不能让用户等待太长时间,个人觉得最好控制在3秒之内。一般来说,内容的初始化是影响Android应用第一次启动速度的主要因素之一,尤其是创建数据库并插入一定数量的初始记录,对于这种问题,最好的办法莫过于在首次初始化时导入静态数据库。

 在Android中导入静态数据库很简单,首先将准备好的静态数据库文件放到Android工程的res目录中的raw子目录下面,如果没有这个子目录的话就手动创建该目录,然后在应用的初始化阶段通过类似下面的代码将数据库文件拷贝到特定的目录下面,假设Android应用的包名是com.test,那么大部分情况下该应用默认的数据库文件位于/data/data/com.test/databases目录下面。


 String dbDirPath = "/data/data/com.test/databases";  

File dbDir = new File(dbDirPath);if(!dbDir.exists())

// 如果不存在该目录则创建    

dbDir.mkdir();

// 打开静态数据库文件的输入流  

InputStream is = context.getResources().openRawResource(R.raw.data);

// 打开目标数据库文件的输出流

FileOutputStream os = new FileOutputStream(dbDirPath+"/data.db");

byte[] buffer = newbyte[1024];

int count = 0;

// 将静态数据库文件拷贝到目的地

while ((count = is.read(buffer)) > 0) {  

os.write(buffer, 0, count);  

}

is.close();  

os.close();


以最近完成的一个应用来看,采用导入静态数据库的方式后,第一次启动时间从将近4秒变成了1秒,效果还是很明显的。  


不过,这种方式是假定所有Android设备的应用安装目录是相同的,而且数据库文件的目录都是/data/data/包名/databases,但是Android的文档中并没有明确规定所有设备具有此种目录结构,所以将静态数据库文件拷贝到一个事先定死的目录的做法还是有一定危险性的。更好的做法是使用Android系统提供的API去解决这个问题,总之,我们要避免的就是使用固定目录,下面是更好的拷贝过程:
复制代码

// 打开静态数据库文件的输入流  

InputStream is = context.getResources().openRawResource(R.raw.data);

// 通过Context类来打开目标数据库文件的输出流,这样可以避免将路径写死。  

FileOutputStream os = context.openFileInput("data.db");

byte[] buffer = newbyte[1024];

int count = 0;

// 将静态数据库文件拷贝到目的地

while ((count = is.read(buffer)) > 0) {  

 os.write(buffer, 0, count);

}

is.close();

os.close();




最终的数据库文件将位于/data/data/com.data/files目录下,需要注意的是,使用Context类的openOrCreateDatabase方法或者SQLiteOpenHelper工具类时,不能再传递数据库的名称作为参数,而是要把数据库文件的全路经传递给它们。

Android开发,Serializable,Parcelable

两种都是用于支持序列化、反序列化话操作,两者最大的区别在于存储媒介的不同,Serializable使用IO读写存储在硬盘上,而Parcelable是直接在内存中读写,很明显内存的读写速度通常大于IO读写,所以在Android中通常优先选择Parcelable。

Serializable不是当前关注的焦点,不过可以查看《Java序列化算法透析》这篇文章中实现一个简单的Serializable例子,查看序列化生成的IO文件,并且以16进制读取并一一解释每一个16进制数字的含义。


1、作用

Serializable的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在,Parcelable是通过IBinder通信的消息的载体。

从上面的设计上我们就可以看出优劣了。


2、效率及选择

Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据,而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化
 

3、编程实现

对于Serializable,类只需要实现Serializable接口,并提供一个序列化版本id(serialVersionUID)即可。而Parcelable则需要实现writeToParcel、describeContents函数以及静态的CREATOR变量,实际上就是将如何打包和解包的工作自己来定义,而序列化的这些操作完全由底层实现。

Parcelable的一个实现例子如下

public class MyParcelable implements Parcelable {
     private int mData;
     private String mStr;

     public int describeContents() {
         return 0;
     }

     // 写数据进行保存
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mData);
         out.writeString(mStr);
     }

     // 用来创建自定义的Parcelable的对象
     public static final Parcelable.Creator<MyParcelable> CREATOR
             = new Parcelable.Creator<MyParcelable>() {
         public MyParcelable createFromParcel(Parcel in) {
             return new MyParcelable(in);
         }

         public MyParcelable[] newArray(int size) {
             return new MyParcelable[size];
         }
     };
     
     // 读数据进行恢复
     private MyParcelable(Parcel in) {
         mData = in.readInt();
         mStr = in.readString();
     }
 }

从上面我们可以看出Parcel的写入和读出顺序是一致的。如果元素是list读出时需要先new一个ArrayList传入,否则会报空指针异常。如下:

list = new ArrayList<String>();
in.readStringList(list);

 PS: 在自己使用时,read数据时误将前面int数据当作long读出,结果后面的顺序错乱,报如下异常,当类字段较多时务必保持写入和读取的类型及顺序一致。

11-21 20:14:10.317: E/AndroidRuntime(21114): Caused by: java.lang.RuntimeException: Parcel android.os.Parcel@4126ed60: Unmarshalling unknown type code 3014773 at offset 164
 

4、高级功能上

Serializable序列化不保存静态变量,可以使用Transient关键字对部分字段不进行序列化,也可以覆盖writeObject、readObject方法以实现序列化过程自定义

java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。

Android匿名共享内存对外Android系统的匿名共享内存子系统的主体是以驱动程序的形式实现在内核空间的,同时在应用程序框架层提供了Java调用接口。在Android应用程序框架层,提供了一个MemoryFile接口来封装了匿名共享内存文件的创建和使用,它实现在frameworks/base/core/java/android/os/MemoryFile.java

public MemoryFile(String name, int length) throws IOException {  
   mLength = length;  
   //打开"/dev/ashmem"设备文件  
   mFD = native_open(name, length);  
   if (length > 0) {  
       //将打开的"/dev/ashmem"设备文件映射到进程虚拟地址空间中  
       mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);  
   } else {  
       mAddress = 0;  
   }
}  

native_open函数是一个本地函数,通过JNI实现在C++层,代码位于frameworks\base\core\jni\android_os_MemoryFile.cpp

static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length)  
{  
   //字符串转换  
   const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL);  
   //打开设备文件"/dev/ashmem",并修改设备文件名称及共享内存大小  
   int result = ashmem_create_region(namestr, length);  
   if (name)  
       env->ReleaseStringUTFChars(name, namestr);  
   if (result < 0) {  
       jniThrowException(env, "java/io/IOException", "ashmem_create_region failed");  
       return NULL;  
   }  
   //设备文件句柄转换  
   return jniCreateFileDescriptor(env, result);  
}

函数首先将Java层传过来的你们共享内存名称转换为C++层的字符串,然后调用ashmem_create_region函数创建一个名为dev/ashmem/的匿名共享内存,并且修改该共享内存的名称及大小,然后将创建的匿名共享内存设备文件句柄值返回到Java空间中。函数ashmem_create_region在Android 匿名共享内存C接口分析中有详细分析,该接口函数就是用于创建一块匿名共享内存。

在Java空间构造MemoryFile对象时,首先打开/dev/ashmem设备文件并在内核空间创建一个ashmem_area,接着需要将内核空间分配的共享内存地址映射到进程虚拟地址空间中来,映射过程是通过native_mmap函数来完成的。


static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor,  
       jint length, jint prot)  
{  
   int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);  
   jint result = (jint)mmap(NULL, length, prot, MAP_SHARED, fd, 0);  
   if (!result)  
       jniThrowException(env, "java/io/IOException", "mmap failed");  
   return result;  
}  

该函数直接调用mmap来实现地址空间映射,注意标志位MAP_SHARED,表示该缓冲区以共享方式映射。映射过程是由Ashmem驱动来完成,Android 匿名共享内存驱动源码分析详细分析了Android匿名共享内存的实现过程。在构造MemoryFile对象时完成了匿名共享内存的创建及地址空间的映射过程,将创建的匿名共享内存的大小保存到MemoryFile的成员变量mLength中,成员变量mFD保存创建的匿名共享内存的文件描述符,成员变量mAddress保存匿名共享内存映射到进程地址空间的起始地址。有了这些信息后,就可以直接使用该匿名共享内存了。

匿名共享内存读

对匿名共享内存的读取操作,在Java空间被封装成MemoryInputStream来完成,该类继承于输入流InputStream,并对外提供了read方法,定义如下:

@Override  
public int read() throws IOException {  
   if (mSingleByte == null) {  
       mSingleByte = new byte[1];  
   }  
   int result = read(mSingleByte, 0, 1);  
   if (result != 1) {  
       return -1;  
   }  
   return mSingleByte[0];  
}  
@Override  
public int read(byte buffer[], int offset, int count) throws IOException {  
   if (offset < 0 || count < 0 || offset + count > buffer.length) {  
       // readBytes() also does this check, but we need to do it before  
       // changing count.  
       throw new IndexOutOfBoundsException();  
   }  
   count = Math.min(count, available());  
   if (count < 1) {  
       return -1;  
   }  
   int result = readBytes(buffer, mOffset, offset, count);  
   if (result > 0) {  
       mOffset += result;  
   }  
   return result;  
}  

MemoryInputStream类提供了两个read重载方法,第一个无参read方法调用有参read方法来读取1字节的数据,而有参read方法的数据读取过程是调用MemoryInputStream的外部类MemoryFile的readBytes方法来实现匿名共享内存数据的读取过程。

public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)  
       throws IOException {  
   if (isDeactivated()) {  
       throw new IOException("Can't read from deactivated memory file.");  
   }  
   if (destOffset < 0 || destOffset > buffer.length || count < 0  
           || count > buffer.length - destOffset  
           || srcOffset < 0 || srcOffset > mLength  
           || count > mLength - srcOffset) {  
       throw new IndexOutOfBoundsException();  
   }  
   return native_read(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);  
}  

该函数也仅仅作了一些判断,然后直接调用本地方法native_read在C++空间完成数据读取,在构造MemoryFile对象时,已经打开并映射了dev/ashmem设备文件,因此在这里直接将打开该设备文件得到的文件句柄值传到C++空间,以正确读取指定的匿名共享内存中的内容,mAddress为匿名共享内存映射到进程地址空间中的起始地址。

static jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz,  
       jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,  
       jint count, jboolean unpinned)  
{  
   int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);  
   if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {  
       ashmem_unpin_region(fd, 0, 0);  
       jniThrowException(env, "java/io/IOException", "ashmem region was purged");  
       return -1;  
   }  
   env->SetByteArrayRegion(buffer, destOffset, count, (const jbyte *)address + srcOffset);  
   if (unpinned) {  
       ashmem_unpin_region(fd, 0, 0);  
   }  
   return count;  
}  

匿名共享内存写

将指定数据写入到匿名共享内存中,对匿名共享内存的写操作使用MemoryOutputStream来封装,该类提供了两个重载的write方法,一个用于向匿名共享内存写入多字节数据,另一个则只写入一个字节数据。这里简单介绍多字节数据写入过程:

public void write(byte buffer[], int offset, int count) throws IOException {  
   writeBytes(buffer, offset, mOffset, count);  
   mOffset += count;  
}  
参数buffer是指写入匿名共享内存中的字节数组,offset指定数据buffer开始写的偏移量,参数count指定写入匿名共享内存的字节长度,函数调用MemoryFile的writeBytes函数来完成数据写入。

public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)  
       throws IOException {  
   if (isDeactivated()) {  
       throw new IOException("Can't write to deactivated memory file.");  
   }  
   if (srcOffset < 0 || srcOffset > buffer.length || count < 0  
           || count > buffer.length - srcOffset  
           || destOffset < 0 || destOffset > mLength  
           || count > mLength - destOffset) {  
       throw new IndexOutOfBoundsException();  
   }  
   native_write(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);  
}  


该函数首先检验参数的正确性,然后调用native方法native_write通过JNI转入C++完成数据写入,第一个参数是匿名共享内存的文件描述符,第二个参数是匿名共享内存映射到进程地址空间的基地值,后面三个参数上面已经介绍了,最后一个参数mAllowPurging表示是否允许内存回收

描述了匿名共享内存的写入过程,本质上就是将buffer中指定位置开始的数据拷贝到匿名共享内存指定的偏移位置
frameworks\base\core\jni\android_os_MemoryFile.cpp

static jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz,  
       jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,  
       jint count, jboolean unpinned)  
{  
   int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);  
   if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {  
       ashmem_unpin_region(fd, 0, 0);  
       jniThrowException(env, "java/io/IOException", "ashmem region was purged");  
       return -1;  
   }  
   env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset);  
   if (unpinned) {  
       ashmem_unpin_region(fd, 0, 0);  
   }  
   return count;  
}  

数据写入过程是通过JNI函数GetByteArrayRegion完成数据的拷贝操作。

MemoryFile主要的构造方法 MemoryFile(String name, int length) ,这里第二个参数为文件大小,需要说明的是Android的MemoryFile和传统的mmap还有一点点区别,毕竟是手机,它内部的内存管理方式ashmem会从内核中回收资源。毕竟目前部分低端机型的RAM也比较吃紧。

synchronized boolean  allowPurging(boolean allowPurging)  //允许ashmem清理内存,线程安全同步的方式。

void  close() //关闭,因为在Linux内部mmap占用一个句柄,不用时一定要释放了

InputStream  getInputStream()  返回读取的内容用Java层的InputStream保存

OutputStream  getOutputStream()  把一个OutputSream写入到MemoryFile中

boolean  isPurgingAllowed() //判断是否允许清理

int  length()  //返回内存映射文件大小

下面就是我们熟悉的,读写细节,主要是对字符数组的操作,这里大家要计算好每个文件类型的占用,同时考虑到效率对于自己分配的大小考虑粒度对齐。

int  readBytes(byte[] buffer, int srcOffset, int destOffset, int count)

void  writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)


应用场合:对于I/O需要频繁操作的,主要是和外部存储相关的I/O操作,MemoryFile通过将 NAND或SD卡上的文件,分段映射到内存中进行修改处理,这样就用高速的RAM代替了ROM或SD卡,性能自然提高不少,对于Android手机而言同时还减少了电量消耗。

[!--infotagslink--]

相关文章

  • Spring Cloud 中@FeignClient注解中的contextId属性详解

    这篇文章主要介绍了Spring Cloud 中@FeignClient注解中的contextId属性详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-25
  • 解决Feign切换client到okhttp无法生效的坑(出现原因说明)

    这篇文章主要介绍了解决Feign切换client到okhttp无法生效的坑(出现原因说明),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25
  • 自定义feignClient的常见坑及解决

    这篇文章主要介绍了自定义feignClient的常见坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-20
  • vscode搭建STM32开发环境的详细过程

    这篇文章主要介绍了vscode搭建STM32开发环境的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-02
  • 安卓开发之Intent传递Object与List教程

    下面我们一起来看一篇关于 安卓开发之Intent传递Object与List的例子,希望这个例子能够为各位同学带来帮助。 Intent 不仅可以传单个的值,也可以传对象与数据集合...2016-09-20
  • C#中HttpWebRequest、WebClient、HttpClient的使用详解

    这篇文章主要介绍了C#中HttpWebRequest、WebClient、HttpClient的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • php微信公众账号开发之五个坑(二)

    这篇文章主要为大家详细介绍了php微信公众账号开发之五个坑,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-10-02
  • 如何设计一个安全的API接口详解

    在日常开发中,总会接触到各种接口,前后端数据传输接口,第三方业务平台接口,下面这篇文章主要给大家介绍了关于如何设计一个安全的API接口的相关资料,需要的朋友可以参考下...2021-08-12
  • 详解.NET Core 使用HttpClient SSL请求出错的解决办法

    这篇文章主要介绍了.NET Core 使用HttpClient SSL请求出错的解决办法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-09-22
  • golang在GRPC中设置client的超时时间

    这篇文章主要介绍了golang在GRPC中设置client的超时时间,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-27
  • 微信开发生成带参数的二维码的讲解

    在微信公众号平台开发者那里,在“账号管理”那里,有一项功能是“生成带参数的二维码”,通过这儿生成的二维码,只要通过微信扫一扫之后,会把事件自动推送到微...2016-05-19
  • java HttpClient传输json格式的参数实例讲解

    这篇文章主要介绍了java HttpClient传输json格式的参数实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-22
  • Chrome插件开发系列一:弹窗终结者开发实战

    从这一节开始,我们将从零开始打造我们的chrome插件工具库,第一节我们将讲一下插件开发的基础知识并构建一个简单但却很实用的插件,在构建之前,我们先简单的了解一下插件以及插件开发的基础知识...2020-10-03
  • Cocos2d-x UI开发之CCControlColourPicker控件类使用实例

    这篇文章主要介绍了Cocos2d-x UI开发之CCControlColourPicker控件类使用实例,本文代码中包含大量注释来讲解CCControlColourPicker控件类的使用,需要的朋友可以参考下...2020-04-25
  • SpringCloud @FeignClient参数的用法解析

    这篇文章主要介绍了SpringCloud @FeignClient参数的用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-21
  • C#创建dll类库的图文步骤

    类库让我们的代码可复用,我们只需要在类库中声明变量一次,就能在接下来的过程中无数次地使用,而无需在每次使用前都要声明它。这样一来,就节省了我们的内存空间,需要的朋友可以参考下...2020-06-25
  • Java开发SpringBoot集成接口文档实现示例

    这篇文章主要为大家介绍了Java开发SpringBoot如何集成接口文档的实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步...2021-10-28
  • SpringCloud之@FeignClient()注解的使用方式

    这篇文章主要介绍了SpringCloud之@FeignClient()注解的使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-25
  • Drupal8模块开发之区块和表单教程

    前页我们讲了 Drupal8模块开发之路由、控制器和菜单链接教程 ,现在我们将学习进一步开发Drupal8模块,区块和表单。 上一教程:Drupal8模块开发之路由、控制器和菜单链...2016-11-25
  • C#中在WebClient中使用post发送数据实现方法

    这篇文章主要介绍了C#中在WebClient中使用post发送数据实现方法,需要的朋友可以参考下...2020-06-25