如何将字符串从UDP侦听服务传递给MainActivity?

时间:2017-07-19 18:06:25

标签: java android

我有一个服务侦听绑定到MainActivity(这是应用程序中唯一的活动)的UDP数据包。该服务在其自己的线程上运行,我可以在logcat中看到UDP消息以及解析的消息。我创建了setParsedMessage()public getParsedMessage()以获取已解析的字符串并将其发送到我的主要活动,以便更改TextViewImageView,具体取决于解析的消息,但由于某种原因它似乎没有检索String。我在Developer.Android网站上阅读了这个方法,但是我也看到过使用Handler代替这个方法。这是我的代码:

MainActivity

public class MainActivity extends Activity {

AlertAssignments mAlertAssignments;



Button startListeningButton;

boolean started;
int counter;
boolean mBound = false;
Context context;
ListenerService mListenerService;

TextView mTextView;
TextView mBlinkView;
ImageView mImageView;


private StartListening _StartListeningTask;
String messageFromService = "";




@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //start listener service
    Intent listenerServiceIntent = new Intent(MainActivity.this, ListenerService.class);
    this.bindService(listenerServiceIntent, mConnection, Context.BIND_AUTO_CREATE);

    mImageView = (ImageView) findViewById(R.id.image_view);
    mTextView = (TextView) findViewById(R.id.alert_text);
    mBlinkView = (TextView) findViewById(R.id.blinking_text);
    Animation mAnimation = new AlphaAnimation(0.0f, 1.0f);
    mAnimation.setDuration(50);
    mAnimation.setStartOffset(20);
    mAnimation.setRepeatCount(Animation.INFINITE);
    mAnimation.setRepeatMode(Animation.REVERSE);
    mBlinkView.startAnimation(mAnimation); //animation value
    mAlertAssignments = new AlertAssignments();

}
private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className, IBinder service) {
        ListenerService.LocalBinder binder = (ListenerService.LocalBinder) service;
        mListenerService = binder.getService();
        mBound = true;
        if(mBound) {
            Log.e("UDP", "Service has been bound successfully");
        }
        else {
            Log.e("UDP", "Service has not been bound");
        }

        readFromService();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mBound = false;
    }
};

@Override
protected void onStart() {
    super.onStart();

}


@Override
protected void onStop() {
    super.onStop();
    //unbind from service
    if(mBound) {
        this.unbindService(mConnection);
        mBound = false;
    }

}

private void readFromService() {
    try {
        Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage());
        mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]);

        if(parsedMessage >= 10 && parsedMessage <= 19 && parsedMessage != 0) {
            mTextView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
        } else {
            mBlinkView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
        }
    } catch(NumberFormatException e) {
        e.printStackTrace();
    }

}


}

我读过这样的公共吸气剂:
Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage());
允许我访问mListenerService.getParsedMessage的字符串值,但我猜这可能仅适用于已启动的服务,而不适用于绑定服务。

AlertAssignments是一个简单的枚举,它使用序数数组将图像和字符串绑定到值,因此mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage])会将ImageView设置为图像。最后,这是服务:

public class ListenerService extends Service{
public String the_alarm_S;
public String parsedMessage = "";
private final IBinder mBinder = new LocalBinder();


public class LocalBinder extends Binder {
    ListenerService getService() {
        return ListenerService.this;
    }
}

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

DatagramSocket socket;

Thread UDPBroadcastThread;

void startListenForUDPBroadcast() {
    UDPBroadcastThread = new Thread(new Runnable() {
        public void run() {
            try {
                while (shouldRestartSocketListen) {
                    try {
                        socket = new DatagramSocket(12001);
                        socket.setReuseAddress(true);
                        String message = "";

                        byte[] recvBuf = new byte[1024];
                        DatagramPacket packet = new DatagramPacket(recvBuf, 1024);
                        Log.e("UDP", "Waiting for UDP broadcast");
                        try {
                            socket.receive(packet);
                            Log.e("UDP", "Received Packet");
                        } catch (IOException e) {
                            e.printStackTrace();

                        }
                        message = new String(packet.getData());

                        Log.e("UDP", "Got UDB broadcast message: " + message);

                        setParsedMessage(message);

                        if(socket != null) {
                            socket.close();
                        }
                    } catch (SocketException e) {
                        e.printStackTrace();
                    }
                }
                //if (!shouldListenForUDPBroadcast) throw new ThreadDeath();
            } catch (Exception e) {
                Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage());
            }
        }
    });
    UDPBroadcastThread.start();
}

private Boolean shouldRestartSocketListen = true;

private void setParsedMessage(String messageContents) {
    the_alarm_S = messageContents;
    String parseMessage[] = the_alarm_S.split("!!!");
    Log.e("UDP", "Parsed message with value " + parseMessage[1]);
    parsedMessage = parseMessage[1];

}
public String getParsedMessage() {
    return parsedMessage;
}

private void stopListen() {
    shouldRestartSocketListen = false;
    if(socket != null) {
        socket.close();
    }
}

@Override
public void onCreate() {
    startListenForUDPBroadcast();
}

@Override
public void onDestroy() {
    stopListen();
}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    shouldRestartSocketListen = true;
    startListenForUDPBroadcast();
    Log.i("UDP", "Service started");
    return START_STICKY;
}
}

有人可以给我一个最简单的方法,将String从服务中获取到主要活动,或者如果我已经拥有它,我在使用它时出错了吗? 我希望避免将Service重写为IntentService,除非绝对有必要这样做,因为这是一个相对简单的对象传递给MainActivity

由于

2 个答案:

答案 0 :(得分:1)

您可以尝试订阅该服务。我的意思是通过服务调用的一些接口来通知活动有关更改,这是我刚测试的一个例子:

订阅者界面

public interface ServiceSubscriber {
  void messageCallback(String message);
}

使用订阅者订阅服务

public class TestService extends Service {

    ArrayList<ServiceSubscriber> subscribers = new ArrayList<>();
    private TestBinder testBinder = new TestBinder();

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(){
            @Override
            public void run() {
                while(true){
                    //this is where you are receiving UDP packets
                    doStuff();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return testBinder;
    }

    private void doStuff() {
        System.out.println("Service is doing stuff!");
        //loop through your subscribers and notify them of your changes
        //a loop here isn't very costly, if there aren't many subscribers
        for (ServiceSubscriber subscriber : subscribers) {
            subscriber.messageCallback("I'm doing stuff");
        }

    }

    public class TestBinder extends Binder {

        public TestService getService() {
            return TestService.this;
        }
    }

    public void subscribeToMessages(ServiceSubscriber subscriber) {
        subscribers.add(subscriber);
    }


    public void unSubscribeToMessages(ServiceSubscriber subscriber) {
        subscribers.remove(subscriber);
    }
}

现在通常的Binding Activity,您可以在其中定义使用Message Callback执行的操作:

public class MainActivity extends AppCompatActivity {
    private TestService testService;
    private Subscriber subscriber;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onStart() {
        super.onStart();

        bindService(new Intent(this, TestService.class),serviceConnection, Context.BIND_AUTO_CREATE);
    }

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            testService = ((TestService.TestBinder)service).getService();
            subscriber = new ServiceSubscriber() {
                @Override
                public void messageCallback(String message) {
                    //I'm just printing out the message received 
                    //Be careful if you need to do UI stuff to use a 
                    //Handler
                    System.out.println(message);
                }
            }
            testService.subscribeToMessages(subscriber );
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

}

当然不要忘记取消订阅。

如果您使用处理程序

执行此操作,则更新UI通常不会破坏您的应用程序
 //activity fields
    Handler handler



//in activity constructor
handler = new Handler();

//update UI by calling
handler.post(new Runnable(){
  @Override
  public void run(){ 
    //update the UI here
  }
编辑:我忘了保留订阅者的引用,稍后取消订阅。已从匿名实例更改为字段。

答案 1 :(得分:0)

为您的服务类制作以下方法:

private void sendMessage() {
   Intent intent = new Intent("message");
   intent.putExtra("message", your_message);
   LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

并将以下代码放在您的活动类中:

 @Override
public void onResume() {
  super.onResume();

  LocalBroadcastManager.getInstance(this)
                       .registerReceiver(mMessageReceiver,
                                         new IntentFilter("message"));
}

private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
        String yourMessage = intent.getIntExtra("message",-1);
  }
};

@Override
protected void onPause() {
  LocalBroadcastManager.getInstance(this)
                       .unregisterReceiver(mMessageReceiver);
  super.onPause();
}
  

注意:-1表示默认值