【问题标题】:How to update Activity every time the data had been changed in Service每次在服务中更改数据时如何更新活动
【发布时间】:2017-12-12 17:09:18
【问题描述】:

我正在编写我的第一个 Android 应用,它应该计算步数(通过加速度计,源代码来自 http://www.gadgetsaint.com/android/create-pedometer-step-counter-android/

那么我现在有什么:

  1. 带有三个 TextView 字段(步数、奖金、速度)的 MainActivity。
  2. 检测步数并计算距离、奖金和 速度。

此服务是绑定服务,它由三个类组成:MyService、MyServiceBinder 和 MyServiceConnection。我已经按照 Xamarin.Android 文档和示例中的说明完成了它:https://github.com/xamarin/monodroid-samples/tree/master/ApplicationFundamentals/ServiceSamples/BoundServiceDemo

关键是每次我有一个步骤时,我都想在 MainActivity 上实时显示(更新那些文本视图)。而且我不明白如何以适当的方式做到这一点。事件?广播接收器?我对绑定/连接感到困惑,这对我来说是新事物。 请帮我让它工作!任何示例(Java 都可以)都会很有帮助。

这里是源代码(我已经从额外的代码中清理了它)。

MainActivity.cs

public class MainActivity : Activity
{
    //BOUND SERVICE: STEPSERVICE 
    MyServiceConnection myServiceConnection;

    //UI
    internal TextView textBonus, textSteps, textSpeed;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        SetContentView(Resource.Layout.Main);

        textBonus = FindViewById<TextView>(Resource.Id.textViewBonus);
        textStep = FindViewById<TextView>(Resource.Id.textViewDistance);
        textSpeed = FindViewById<TextView>(Resource.Id.textViewSpeed);
    }

    protected override void OnStart()
    {
        base.OnStart();
        if (myServiceConnection == null)
        {
            myServiceConnection = new MyServiceConnection(this);
        }
        DoBindMyService();
    }

    private void DoBindMyService()
    {
        Intent serviceIntent = new Intent(this, typeof(MyService));
        BindService(serviceIntent, myServiceConnection, Bind.AutoCreate);
    }


    protected override void OnDestroy()
    {
        //stop services!
        base.OnDestroy();
    }

    private void UpdateUI()
    {
        RunOnUiThread(() =>
        {
            textBonus.Text = myServiceConnection.Binder.Service.Bonus;              
            textSteps.Text = myServiceConnection.Binder.Service.Steps;
            textSpeed.Text = myServiceConnection.Binder.Service.Speed;
        });
    }
}

MyService.cs

[Service]
public class MyService : Service, IStepListener, ISensorEventListener
{
    //counters
    private int bonus;
    public int Bonus
    {
        get { return bonus; }
        set { bonus = value; }
    }

    private int steps = 0;
    public int StepsT
    {
        get { return steps; }
        set
        {
            steps = value;
        }
    }

    private float speed = 0.0F;
    public float Speed
    {
        get { return speed; }
        set
        {
            speed = value;
        }
    }

    public IBinder Binder { get; private set; }

    public override IBinder OnBind(Intent intent)
    {
        this.Binder = new MyServiceBinder(this);
        return this.Binder;
    }

    public override void OnCreate()
    {
        base.OnCreate();
    }

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        return StartCommandResult.Sticky;
    }

    public void Step(long timeNs)
    {
        Steps++;
        Bonus++;
        Speed++;
    }

    public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
    {
        // We don't want to do anything here.
    }

    public void OnSensorChanged(SensorEvent e)
    {
        simpleStepDetector.UpdateAccel(e.Timestamp, e.Values[0], e.Values[1], e.Values[2]);
    }
}

MyServiceConnection.cs

public class MyServiceConnection : Java.Lang.Object, IServiceConnection
{
    MainActivity mainActivity;

    public MyServiceConnection(MainActivity activity)
    {
        IsConnected = false;
        Binder = null;
        mainActivity = activity;
    }

    public bool IsConnected { get; private set; }
    public MyServiceBinder Binder { get; private set; }

    public void OnServiceConnected(ComponentName name, IBinder service)
    {
        Binder = service as MyServiceBinder;
        IsConnected = this.Binder != null;

        string message = "onSecondServiceConnected - ";

        if (IsConnected)
        {
            message = message + " bound to service " + name.ClassName;
        }
        else
        {
            message = message + " not bound to service " + name.ClassName;
        }

        mainActivity.textSpeed.Text = message;
    }

    public void OnServiceDisconnected(ComponentName name)
    {
        IsConnected = false;
        Binder = null;
    }
}

MyServiceBinder.cs

public class MyServiceBinder : Binder
{
    public MyServiceBinder(MyService service)
    {
        this.Service = service;
    }

    public MyService Service { get; private set; }
}

附言。这是我在这里的第一个问题。如果我做错了什么,请见谅。

【问题讨论】:

  • OnServiceConnected方法中,你可以通过Binder.Service得到MyService实例,然后你就可以得到stepsbonusesspeed字段,这些字段是你自己计算出来的MyService.
  • 使用Messenger
  • 或者你可以使用接口,我认为接口是最好的方式。 Messenger 有点复杂,尽管它可以与 BindService 一起使用。所以我建议你用StartService带接口,很容易更新你的UI。
  • 乔,感谢您的回复!虽然我不明白 StartService 的接口 - 那是什么?有什么例子吗?
  • 对不起,我的意思是你可以使用StartService,在服务中,你可以使用接口与activity进行通信。

标签: c# android xamarin android-activity android-service


【解决方案1】:

有三种方法可以完成。

  • 广播
  • 接口
  • 绑定服务

绑定服务

  • 在您的MyServiceConnection 中添加:

    public MyService myService;
    

    并在您的 OnServiceConnected 方法中将其添加到 Binder = service as MyServiceBinder; 下:

    myService=Binder.Service;
    myService.SetActivity(mainActivity);
    
  • 在你的MyService 类中添加这个(这样你就可以在你的服务中获得MainActivity 实例):

    MainActivity mainActivity;
    public void SetActivity(MainActivity activity) {
    this.mainActivity = activity;
    }
    

    并在您的Step(long timeNs) 方法中添加mainActivity.UpdateUI();,这样您就可以更新您的UI。

  • 在您的MainActivity 中,将private void UpdateUI() 替换为public void UpdateUI()


界面

  • 添加IUpdate接口

    public interface IUpdate
    {
        void Update();
    }
    
  • 在您的MyService 中添加:

    IUpdate update;
    public void SetIUpdate(IUpdate update) {
        this.update = update;
    }
    

    并在您的 Step(long timeNs) 方法中添加 this.update.Update();

  • 在您的MyServiceConnection 类中实现IUpdate 接口,所以它会是这样的:

    public class MyServiceConnection : Java.Lang.Object, IServiceConnection,IUpdate
    {
         MainActivity mainAtivity;
    
        public MyServiceConnection(MainActivity activity)
    {
        IsConnected = false;
        Binder = null;
        mainActivity = activity;
    }
    
    public bool IsConnected { get; private set; }
    public MyServiceBinder Binder { get; private set; }
    public MyService myService;
    
    public void OnServiceConnected(ComponentName name, IBinder service)
    {
        Binder = service as MyServiceBinder;
        myService=Binder.Service;
        myService.SetIUpdate(this);
        //myService.SetActivity(mainActivity);
        IsConnected = this.Binder != null;
    
        string message = "onSecondServiceConnected - ";
    
        if (IsConnected)
        {
            message = message + " bound to service " + name.ClassName;
        }
        else
        {
            message = message + " not bound to service " + name.ClassName;
        }
    
        mainActivity.textSpeed.Text = message;
    }
    
    public void OnServiceDisconnected(ComponentName name)
    {
        IsConnected = false;
        Binder = null;
    }
    
    public void Update()
    {
        mainActivity.UpdateUI();
    }
    }
    

广播

这是你已经知道的。

【讨论】:

  • 乔,你太棒了!非常感谢您提供代码示例。我会尝试这两种方法并对结果发表评论。
  • 所以,正如我所承诺的,我已经尝试了您的建议并决定使用界面。一切正常,谢谢。
  • 祝你好运,我一直都在。
猜你喜欢
  • 1970-01-01
  • 2020-08-08
  • 2019-04-04
  • 1970-01-01
  • 1970-01-01
  • 2020-05-28
  • 2018-08-08
  • 2015-05-29
  • 2022-11-30
相关资源
最近更新 更多