从尚未从AsyncTask调用的回调调用PublishProgress()

时间:2013-04-26 17:35:57

标签: android callback android-asynctask xamarin.android xamarin

经过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()。这让我很困惑。

我希望自己和我的需求足够清楚。

非常感谢。 基督教

1 个答案:

答案 0 :(得分:0)

抱歉,我迟到了。官方工作是第一位的。 正如@Cheesebaron所建议的那样,我把我的第一个回答分开了。


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
  }
}

HDelegateCallbackThread确保实现最简单的需求。但他们也引入了一些好处。现在可以将一个实现用于多种用途,同时可以使用回调。这些回调也是多个代表。因此可以在链中调用几个动作。