我正忙于编写一个应用程序,用户需要捕获大量图像,然后将它们与一些文本数据打包在一起,然后将它们上传到本地服务器。我想通过Intent Service在Android平台上实现上传,但我找不到一个好的Xamarin Forms PCL示例来向我展示如何。
这是我初始化Intent以传递给IntentService的方法:
public async Task<bool> UploadAsync(Uri serviceAddress,
CaptureEntity capture,
List<ImageEntity> images)
{
try
{
Intent uploadIntent = new Intent();
uploadIntent.PutExtra("serviceAddress", serviceAddress.ToString());
uploadIntent.PutExtra("captureId", capture.WorkflowId.ToString());
StartService(uploadIntent);
return true;
}
catch (Exception exc)
{
App.logger.LogError(DateTime.Now, "Uploader", exc.ToString());
throw exc;
}
}
这是IntentService本身。
[Service]
public class ServiceIntent : IntentService
{
public ServiceIntent() : base("ServiceIntent")
{
}
//[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
return base.OnStartCommand(intent, flags, startId);
}
public override void OnCreate()
{
base.OnCreate();
}
protected override void OnHandleIntent(Intent intent)
{
Uri serviceAddress = new Uri(intent.GetStringExtra("serviceAddress"));
Guid captureId = Guid.Parse(intent.GetStringExtra("captureId"));
CaptureEntity capture = new DatabaseConnection_Android().CreateConnection().Query<CaptureEntity>("SELECT * FROM [CaptureEntity]").Single(c => c.WorkflowId == captureId);
var images = new DatabaseConnection_Android().CreateConnection().Query<ImageEntity>("SELECT * FROM [ImageEntity]").Where(i => i.CaptureEntityId == capture.Id);
try
{
MultipartFormDataContent content = new MultipartFormDataContent();
StringContent strContent = new StringContent(
capture.XmlData,
Encoding.UTF8,
"text/xml");
IImageHandler handler = new ImageHandler_Droid();
HttpRequestMessage request = new HttpRequestMessage();
request.Headers.Add("workflow", capture.WorkflowId.ToString());
request.Method = HttpMethod.Post;
request.RequestUri = serviceAddress;
foreach (var image in images)
{
byte[] imageByte = handler.ReadAllBytes(image.ImagePath);
ByteArrayContent byteContent = new ByteArrayContent(imageByte);
byteContent.Headers.Add("Content-Type", "image/jpeg");
content.Add(byteContent, "file", image.ImageName);
}
content.Add(strContent, "text/xml");
request.Content = content;
using (HttpClient client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(180);
var response = client.SendAsync(
request,
HttpCompletionOption.ResponseContentRead).Result;
var readResponse = response.Content.ReadAsStringAsync().Result;
if (readResponse == "File uploaded.")
MessagingCenter.Send<CaptureEntity, string>(
capture,
"Completed",
"Success");
else if (readResponse.Contains("An error has occurred."))
MessagingCenter.Send<CaptureEntity, string>(
capture,
"Uploader",
String.Format(CultureInfo.InvariantCulture,
"Failed: {0}",
readResponse));
else
MessagingCenter.Send<CaptureEntity, string>(
capture,
"Uploader",
String.Format(CultureInfo.InvariantCulture,
"Failed: {0}",
readResponse));
}
}
catch (WebException webExc)
{
MessagingCenter.Send<string, string>("Uploader", "Failed",
String.Format(CultureInfo.InvariantCulture,
"{0} upload failed.\n{1}",
capture.DisplayName,
webExc.Message));
}
catch (TimeoutException timeExc)
{
MessagingCenter.Send<string, string>("Uploader", "Failed",
String.Format(CultureInfo.InvariantCulture,
"{0} upload failed.\n{1}",
capture.DisplayName,
timeExc.Message));
}
catch (Exception exc)
{
MessagingCenter.Send<string, string>("Uploader", "Failed",
String.Format(CultureInfo.InvariantCulture,
"{0} upload failed.\n{1}",
capture.DisplayName,
exc.Message));
}
}
}
任何人都可以告诉我我做错了什么,因为当我想要启动服务时出现以下错误:
Java.Lang.NullPointerException:尝试在空对象引用上调用虚方法'android.content.ComponentName android.content.Context.startService(android.content.Intent)'
答案 0 :(得分:1)
在Intent
声明中,您需要告诉您要拨打的服务
这样的事情:
var uploadIntent = new Intent(this, typeof(ServiceIntent));
注意:this
代表Context
。
<强>更新强>
正如评论中所提到的,您的接口实现无法从Activity
类派生。要访问Context
以便能够调用StartService
方法并创建Intent
,您可以通过两种方式进行操作:
使用Xamarin.Forms.Forms.Context
:
public async Task<bool> UploadAsync(Uri serviceAddress,
CaptureEntity capture,
List<ImageEntity> images)
{
try
{
var context = Xamarin.Forms.Forms.Context;
var uploadIntent = new Intent(context, typeof(ServiceIntent));
uploadIntent.PutExtra("serviceAddress", serviceAddress.ToString());
uploadIntent.PutExtra("captureId", capture.WorkflowId.ToString());
context.StartService(uploadIntent);
return true;
}
catch (Exception exc)
{
App.logger.LogError(DateTime.Now, "Uploader", exc.ToString());
throw exc;
}
}
如果您使用的是最新版本的Xamarin.Forms,则不推荐使用此全局上下文,而是建议您使用本地上下文。您仍然可以使用它,但在将来的XF更新中,您的应用可能会中断。
使用 CurrentActivity plugin:
public async Task<bool> UploadAsync(Uri serviceAddress,
CaptureEntity capture,
List<ImageEntity> images)
{
try
{
var context = CrossCurrentActivity.Current.Activity;
var uploadIntent = new Intent(context, typeof(ServiceIntent));
uploadIntent.PutExtra("serviceAddress", serviceAddress.ToString());
uploadIntent.PutExtra("captureId", capture.WorkflowId.ToString());
context.StartService(uploadIntent);
return true;
}
catch (Exception exc)
{
App.logger.LogError(DateTime.Now, "Uploader", exc.ToString());
throw exc;
}
}
这个插件可以从块中安装,设置非常简单。基本上,它允许您访问当前活动,您可以将其用作上下文来调用IntentService
希望这会有所帮助.-
答案 1 :(得分:0)
IntentService是服务的基类,可根据需要处理异步请求(表示为Intents)。客户端通过startService(Intent)调用发送请求;服务根据需要启动,使用工作线程依次处理每个Intent,并在工作失败时自行停止。
在Android中,我们通常使用IntentService
来执行异步操作。众所周知,线程也用于做异步操作。 IntentService
和Thread
IntentService
之间的差异是Service
,属于Android组件。因此,IntentService
的优先级高于Thread.
例如,ActivityA
有一个IntentService
,而ActivityB
有一个Thread
,IntentService
和{{} 1}}正在运行,Thread
和ActivityA
都是背景ActivityB
。现在,如果您的手机系统没有额外资源,您的Activity
将首先被杀死。
Java.Lang.NullPointerException:尝试在空对象引用上调用虚方法'android.content.ComponentName android.content.Context.startService(android.content.Intent)'
这意味着您应该使用ActivityB
来调用android.content.Context
方法。在Android中,有三种StartService
。 Application,Activity和Service。因此,您可以直接在这三个类中调用Context
方法。如果您不在这三个课程中,则需要将StartService
传递给您的课程,然后使用Context
致电Context
。
我为此类的继承添加了Activity。
如果你这样做,你的班级将是StartService
,你需要在你的课堂上注册它,为你的班级添加布局,它应该有生命周期,等等。它不会是什么你想上课。在Android中,Activity是一个Component,而不是普通的类,因此除非您希望您的类成为Activity,否则不能继承它。
我为你做了demo,