经过3年的阅读,这是我在这里的第一篇文章。从来没有必要写一个。这是一个非常好的网站。
我有了扩展原生AsyncTask
类的想法,以支持从RunInBackground()
,OnProgressUpdate()
,OnPreExecute()
和OnPostExecute()
调用的回调。所以我没有必要为每一项任务实现一个新的AsyncTask
后代。
(我必须在Java
中提到一个名为DoInBackground()
的方法,它也存在于Xamarin端口中。但是文档说要覆盖RunInBackground()
。)
目标是实例化AsyncTask
后代,设置所需的回调并执行AsyncTask
。
现在的问题是,我需要从活动中的回调内部调用PublishProgress()
以对更改进度状态做出反应。因此,我必须将此方法的单独回调传递给RunInBackground()
的回调。但是,当我这样做时,会抛出异常。
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: Object reference not set to an instance of an object
但是我无法处理这个,因为我不知道应该需要哪个引用。调试清楚地表明回调是正确的。
活动: Main.cs
using AsyncSpecial = AsyncTaskEnhanced< System.String, System.Int32, System.Int32 >;
[ Activity( Label = "FooBar", MainLauncher = true ) ]
public class Main : Activity
{
protected Int32 RunInBackground( AsyncSpecial.PublishProgressDelegate publishProgressCallback, params String[] arguments )
{
for ( Int32 n = 0; n < arguments.Length; n++ )
{
Console.WriteLine( "Item :: " + arguments[ n ] );
// Won't invoke.
PublishProgressDelegate( n );
// Won't invoke.
DelegateHelper.Invoke( publishProgressCallback, n );
}
return arguments.Length;
}
protected void OnProgressUpdate( Int32 progress )
{
Console.WriteLine( "Progress :: " + progress );
}
protected void OnPreExecute( )
{
Console.WriteLine( "Pre" );
}
protected void OnPostExecute( Int32 result )
{
Console.WriteLine( "Result :: " + result );
}
protected override void OnCreate( Bundle bundle )
{
base.OnCreate( bundle );
this.SetContentView( Resource.Layout.Main );
Button button = this.FindViewById< Button >( Resource.Id.btnOne );
button.Click += ( Object sender, EventArgs eventArgs ) =>
{
AsyncSpecial asyncTask = new AsyncSpecial( );
asyncTask.RunInBackgroundCallback = this.RunInBackground;
asyncTask.OnProgressUpdateCallback = this.OnProgressUpdate;
asyncTask.OnPreExecuteCallback = this.OnPreExecute;
asyncTask.OnPostExecuteCallback = this.OnPostExecute;
asyncTask.Execute( "ItemOne", "ItemTwo" );
};
}
}
类: AsyncTaskEnhanced.cs
public class AsyncTaskEnhanced< TArgument, TProgress, TResult > : AsyncTask< TArgument, TProgress, TResult >
{
public delegate void PublishProgressDelegate( params TProgress[ ] progresses );
public delegate TResult RunInBackgroundDelegate( PublishProgressDelegate publishProgressCallback, params TArgument[ ] arguments );
public delegate void OnProgressUpdateDelegate( TProgress progress );
public delegate void OnPreExecuteDelegate( );
public delegate void OnPostExecuteDelegate( TResult result );
private PublishProgressDelegate publishProgressCallback = null;
public PublishProgressDelegate PublishProgressCallback
{
get
{
return this.publishProgressCallback;
}
set
{
this.publishProgressCallback = value;
}
}
private RunInBackgroundDelegate runInBackgroundCallback = null;
public RunInBackgroundDelegate RunInBackgroundCallback
{
get
{
return this.runInBackgroundCallback;
}
set
{
this.runInBackgroundCallback = value;
}
}
private OnProgressUpdateDelegate onProgressUpdateCallback = null;
public OnProgressUpdateDelegate OnProgressUpdateCallback
{
get
{
return this.onProgressUpdateCallback;
}
set
{
this.onProgressUpdateCallback = value;
}
}
private OnPreExecuteDelegate onPreExecuteCallback = null;
public OnPreExecuteDelegate OnPreExecuteCallback
{
get
{
return this.onPreExecuteCallback;
}
set
{
this.onPreExecuteCallback = value;
}
}
private OnPostExecuteDelegate onPostExecuteCallback = null;
public OnPostExecuteDelegate OnPostExecuteCallback
{
get
{
return this.onPostExecuteCallback;
}
set
{
this.onPostExecuteCallback = value;
}
}
public AsyncTaskEnhanced( IntPtr doNotUse, JniHandleOwnership transfer ) : base( doNotUse, transfer )
{
this.PublishProgressCallback = this.PublishProgress;
}
public AsyncTaskEnhanced( ) : base( )
{
}
protected override TResult RunInBackground( params TArgument[ ] arguments )
{
TResult result = DelegateHelper.Invoke< TResult >( this.RunInBackgroundCallback, this.PublishProgressCallback, arguments );
return result;
}
protected void OnProgressUpdate( TProgress progress )
{
DelegateHelper.Invoke( this.OnProgressUpdateCallback, progress );
}
protected override void OnPreExecute( )
{
DelegateHelper.Invoke( this.OnPreExecuteCallback );
}
protected override void OnPostExecute( TResult result )
{
DelegateHelper.Invoke( this.OnPostExecuteCallback, result );
}
}
分类: DelegateHelper.cs
static public class DelegateHelper
{
static public void Invoke( Delegate callback, params Object[ ] arguments )
{
if ( null != callback )
{
callback.DynamicInvoke( arguments );
}
}
static public TResult Invoke< TResult >( Delegate callback, params Object[ ] arguments )
{
TResult result = default( TResult );
if ( null != callback )
{
result = ( TResult ) callback.DynamicInvoke( arguments );
}
return result;
}
}
顺便说一句:如果我从PublishProgress()
内拨打AsyncTaskEnhanced::RunInBackground()
,则不会调用AsyncTaskEnhanced::OnProgressUpdate()
。这让我很困惑。
我希望自己和我的需求足够清楚。
非常感谢。 基督教
答案 0 :(得分:0)
1
确定。我解决了一个问题。我忘了在PublishProgressCallback
的无争论构造函数中设置AsyncTaskEnhanced
。因此PublishProgress( n )
回调中RunInBackground()
的第一次调用正常运行而没有异常(除了它仍然不调用OnProgressUpdate()
)但DelegateHelper
期间的调用失败了
System.Exception: Failed to convert parameters.
我必须看看它。我的第一印象是它应该起作用,这只是一个我必须弄清楚的简单事情。
2
我没弄清楚,为什么PublishProgress()
没有调用OnPublishProgress()
这似乎是Xamarin端口本身的问题。正如@Cheesebaron进一步建议的那样,我使用了.NET原生的可能性。它们工作得很好,并且AsyncTask
类具有更大的灵活性。
首先是委托助手,用于在没有明确的代码检查的情况下调用回调,如果有任何处理程序附加到委托。
using System;
namespace Library
{
static public class HDelegate
{
#region Methods
static public void Invoke( Delegate callback, params Object[ ] arguments )
{
if ( null != callback )
{
callback.DynamicInvoke( arguments );
}
}
static public TResult Invoke< TResult >( Delegate callback, params Object[ ] arguments )
{
TResult result = default( TResult );
if ( null != callback )
{
result = ( TResult ) callback.DynamicInvoke( arguments );
}
return result;
}
#endregion
}
}
这是AsyncTask
克隆的实现。
using System;
using System.Threading;
namespace Library.Threading
{
public class CallbackThread< TArgument, TProgress, TResult >
{
#region Delegates
public delegate void PublishProgressDelegate( params TProgress[ ] progresses );
public delegate TResult DoInBackgroundDelegate( PublishProgressDelegate publishProgressCallback, params TArgument[ ] arguments );
public delegate void ProgressUpdateDelegate( TProgress progress );
public delegate void PreExecuteDelegate( );
public delegate void PostExecuteDelegate( TResult result );
#endregion
#region Properties
private PublishProgressDelegate publishProgressCallback = null;
protected virtual PublishProgressDelegate PublishProgressCallback
{
get
{
return this.publishProgressCallback;
}
set
{
this.publishProgressCallback = value;
}
}
private DoInBackgroundDelegate doInBackgroundCallback = null;
public virtual DoInBackgroundDelegate DoInBackgroundCallback
{
get
{
return this.doInBackgroundCallback;
}
set
{
this.doInBackgroundCallback = value;
}
}
private ProgressUpdateDelegate progressUpdateCallback = null;
public virtual ProgressUpdateDelegate ProgressUpdateCallback
{
get
{
return this.progressUpdateCallback;
}
set
{
this.progressUpdateCallback = value;
}
}
private PreExecuteDelegate preExecuteCallback = null;
public virtual PreExecuteDelegate PreExecuteCallback
{
get
{
return this.preExecuteCallback;
}
set
{
this.preExecuteCallback = value;
}
}
private PostExecuteDelegate postExecuteCallback = null;
public virtual PostExecuteDelegate PostExecuteCallback
{
get
{
return this.postExecuteCallback;
}
set
{
this.postExecuteCallback = value;
}
}
#endregion
#region Constructors
public CallbackThread( )
{
this.PublishProgressCallback = this.PublishProgress;
}
#endregion
#region Methods
protected virtual void PreExecute( )
{
HDelegate.Invoke( this.PreExecuteCallback );
}
protected virtual TResult DoInBackground( params TArgument[ ] arguments )
{
TResult result = HDelegate.Invoke< TResult >( this.DoInBackgroundCallback, this.PublishProgressCallback, arguments );
return result;
}
protected virtual void PublishProgress( params TProgress[ ] progresses )
{
foreach ( TProgress progress in progresses )
{
this.ProgressUpdate( progress );
}
}
protected virtual void ProgressUpdate( TProgress progress )
{
HDelegate.Invoke( this.ProgressUpdateCallback, progress );
}
protected virtual void PostExecute( TResult result )
{
HDelegate.Invoke( this.PostExecuteCallback, result );
}
public virtual void Execute( params TArgument[ ] arguments )
{
Thread thread = new Thread(( ) =>
{
this.PreExecute( );
TResult result = this.DoInBackground( arguments );
this.PostExecute( result );
} );
thread.Start( );
}
#endregion
}
}
HDelegate
和CallbackThread
确保实现最简单的需求。但他们也引入了一些好处。现在可以将一个实现用于多种用途,同时可以使用回调。这些回调也是多个代表。因此可以在链中调用几个动作。