我有一个服务侦听绑定到MainActivity
(这是应用程序中唯一的活动)的UDP数据包。该服务在其自己的线程上运行,我可以在logcat中看到UDP消息以及解析的消息。我创建了setParsedMessage()
和public getParsedMessage()
以获取已解析的字符串并将其发送到我的主要活动,以便更改TextView
和ImageView
,具体取决于解析的消息,但由于某种原因它似乎没有检索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
由于
答案 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表示默认值