我想通过使用 ParcelFileDescriptor.createPipe() 将 InputStream 从一个 Android 服务“发送”到在不同进程中运行的另一个服务。 ,一个流到流的复制线程和一个 ParcelFileDescriptor,代表管道的读取端,它通过 Binder IPC 提供给其他服务。
我想将给定的 InputStream 发送到接收服务:
public sendInputStream() {
InputStream is = ...; // that's the stream for process/service B
ParcelFileDescriptor pdf = ParcelFileDescriptorUtil.pipeFrom(is);
inputStreamService.inputStream(pdf);
}
ParcelFileDescriptorUtil 是一个辅助类,具有经典的 java.io. 流到流复制线程:
public class ParcelFileDescriptorUtil {
public static ParcelFileDescriptor pipeFrom(InputStream inputStream) throws IOException {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
ParcelFileDescriptor readSide = pipe[0];
ParcelFileDescriptor writeSide = pipe[1];
// start the transfer thread
new TransferThread(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide)).start();
return readSide;
}
static class TransferThread extends Thread {
final InputStream mIn;
final OutputStream mOut;
TransferThread(InputStream in, OutputStream out) {
super("ParcelFileDescriptor Transfer Thread");
mIn = in;
mOut = out;
setDaemon(true);
}
@Override
public void run() {
byte[] buf = new byte[1024];
int len;
try {
while ((len = mIn.read(buf)) > 0) {
mOut.write(buf, 0, len);
}
mOut.flush(); // just to be safe
} catch (IOException e) {
LOG.e("TransferThread", e);
}
finally {
try {
mIn.close();
} catch (IOException e) {
}
try {
mOut.close();
} catch (IOException e) {
}
}
}
}
}
接收服务的.aidl:
package org.exmaple;
interface IInputStreamService {
void inputStream(in ParcelFileDescriptor pfd);
}
进程A调用的接收服务:
public class InputStreamService extends Service {
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IInputStreamService.Stub mBinder = new IInputStreamService.Stub() {
@Override
public void inputStream(ParcelFileDescriptor pfd) throws RemoteException {
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
OutputStream os = ...;
int len;
byte[] buf = new byte[1024];
try {
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
} catch (IOException e) {
// this catches the exception shown below
}
}
};
但是 inputStream() 中的 in.read() 总是抛出一个 IOException
java.io.IOException: read failed: EBADF (Bad file number)
at libcore.io.IoBridge.read(IoBridge.java:442)
at java.io.FileInputStream.read(FileInputStream.java:179)
at java.io.InputStream.read(InputStream.java:163)
似乎 EBADF errno 是在文件描述符关闭时由 read() 设置的。但我不知道是什么原因造成的,也不知道如何解决。
是的,我知道也可以使用 ConentProvider。但它不应该也适用于我的方法吗?有没有其他方法可以将 InputStream 流传递给 Android 中的不同服务?
旁注:CommonsWare 创建了一个类似的 project using a ContentProvider (相关 SO 问题 1 , 2 )。这是我从中获得大部分方法想法的地方
最佳答案
看起来原因是 ParcelFileDescriptor 是服务方法的参数。如果该服务确实返回 ParcelFileDescriptor,它将按预期工作。
public void sendInputStream() {
InputStream is = ...; // that's the stream for process/service B
ParcelFileDescriptor pfd = inputStreamService.inputStream();
OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
int len;
byte[] buf = new byte[1024];
try {
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
} catch (IOException e) {
} finally {
try { is.close(); } catch (IOException e1) {}
try { os.close(); } catch (IOException e1) {}
}
}
接收服务的.aidl:
package org.exmaple;
interface IInputStreamService {
ParcelFileDescriptor inputStream();
}
进程A调用的接收服务:
public class InputStreamService extends Service {
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IInputStreamService.Stub mBinder = new IInputStreamService.Stub() {
@Override
public void ParcelFileDescriptor inputStream() throws RemoteException {
// one can read the contents of the Processes A's InputStream
// from the following OutputStream
OutputStream os = ...;
ParcelFileDescriptor pfd = ParcelFileDescriptorUtil.pipeTo(os);
return pfd;
}
};
ParcelFileDescriptorUtil 是一个辅助类,具有经典的 java.io. 流到流复制线程。 现在我们必须使用 pipeTo() 方法。
public class ParcelFileDescriptorUtil {
public static ParcelFileDescriptor pipeTo(OutputStream outputStream) throws IOException {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
ParcelFileDescriptor readSide = pipe[0];
ParcelFileDescriptor writeSide = pipe[1];
// start the transfer thread
new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(readSide), outputStream).start();
return writeSide;
}
static class TransferThread extends Thread {
final InputStream mIn;
final OutputStream mOut;
TransferThread(InputStream in, OutputStream out) {
super("ParcelFileDescriptor Transfer Thread");
mIn = in;
mOut = out;
setDaemon(true);
}
@Override
public void run() {
byte[] buf = new byte[1024];
int len;
try {
while ((len = mIn.read(buf)) > 0) {
mOut.write(buf, 0, len);
}
mOut.flush(); // just to be safe
} catch (IOException e) {
LOG.e("TransferThread", e);
}
finally {
try {
mIn.close();
} catch (IOException e) {
}
try {
mOut.close();
} catch (IOException e) {
}
}
}
}
}
这允许您跨进程边界传输 InputStreams,一个缺点是流到流的复制涉及一些 CPU 时间。
关于android - 使用 ParcelFileDescriptor.createPipe() 将 InputStream 传输到另一个服务(跨进程边界)失败,返回 "EBADF (Bad file number)",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18212152/
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案