我编写了一个侦听UDP消息的服务,然后根据UDP消息中解析的消息更改TextView和ImageView。我在尝试使用服务中的公共getParsedMessage
方法时获得NPE,这意味着该服务尚未启动。它在清单中被声明为拼写中的服务,所以我知道这不是问题。这是我的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;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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();
Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage()); //this is the cause of the NPE
mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]);
if(parsedMessage >= 10 && parsedMessage <= 19 && parsedMessage != 0) {
mTextView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
} else {
mBlinkView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
ListenerService.LocalBinder binder = (ListenerService.LocalBinder) service;
mListenerService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
@Override
protected void onStart() {
super.onStart();
//start listener service
Intent listenerServiceIntent = new Intent(MainActivity.this, ListenerService.class);
this.bindService(listenerServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
//unbind from service
if(mBound) {
this.unbindService(mConnection);
mBound = false;
}
}
}
错误发生在第75行,标记在上面(Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage());
)。我在设置和启动服务时遵循了developer.android文档,但是我似乎在多个位置看到了冲突的信息。这是我的ListenerService:
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;
}
static String UDP_BROADCAST = "UDPBroadcast";
//Boolean shouldListenForUDPBroadcast = false;
DatagramSocket socket;
private void listenAndWaitAndThrowIntent(InetAddress broadcastIP, Integer port) throws Exception {
byte[] recvBuf = new byte[15000];
if (socket == null || socket.isClosed()) {
socket = new DatagramSocket(port, broadcastIP);
socket.setBroadcast(true);
}
//socket.setSoTimeout(1000);
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
Log.e("UDP", "Waiting for UDP broadcast");
socket.receive(packet);
String senderIP = packet.getAddress().getHostAddress();
String message = new String(packet.getData()).trim();
Log.e("UDP", "Got UDB broadcast from " + senderIP + ", message: " + message);
broadcastIntent(senderIP, message);
setParsedMessage(message);
socket.close();
}
private void broadcastIntent(String senderIP, String message) {
Intent intent = new Intent(ListenerService.UDP_BROADCAST);
intent.putExtra("sender", senderIP);
intent.putExtra("message", message);
Log.e("UDP", "Message received containing" +message);
sendBroadcast(intent);
}
Thread UDPBroadcastThread;
void startListenForUDPBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
InetAddress broadcastIP = InetAddress.getByName("172.16.238.255"); //172.16.238.42 //192.168.1.255
Integer port = 12001;
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent(broadcastIP, port);
}
//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;
}
void stopListen() {
shouldRestartSocketListen = false;
socket.close();
}
@Override
public void onCreate() {
};
@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;
}
}
我以前一直在使用AsyncTask来获取这些数据,但是,我需要它不断地获取数据并更新TextView
和ImageView
个对象,并且由于ping速度使用了执行此操作的while
导致内存耗尽,因为我假设它在UI线程上运行。 AlertAssignments只是一个Enum,它将图像文件和字符串绑定到序数数组值,这样我就可以根据解析后的消息(TextView
的整数值轻松更改ImageView
和parsedMessage[1]
。原始邮件xxx!!!n!!!xxx
提供parsedMessage[1] = n
)
关于如何解决可能是我的疏忽的任何建议都会很棒,谢谢
答案 0 :(得分:3)
了解Android活动生命周期:
您注意到的一件事是在onCreate()
之前调用onStart()
。这意味着您在实际启动之前尝试访问服务。
我解决这个问题的方法是在onCreate()
中启动您的服务(因此它会在您的活动首次创建时启动),然后读取onResume()
内的值,以便每个时间你的活动回到前台,它会根据服务更新。
您可能还会注意到,如果需要资源,您的应用可能会在onPause()
之前被终止。在那里进行清理是一个好主意,而不是onDestroy()
。
修改强>
如果上述选项不起作用,我怀疑是否存在竞争条件。仅仅因为您在阅读之前启动了服务,并不意味着它已完全配置。值得庆幸的是,您有一个监听器可以告诉您绑定服务的时间。
您可以专门为更新用户界面编写一个单独的方法,并让您的活动仅在服务启动后调用它:
public class MyActivity {
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
ListenerService.LocalBinder binder = (ListenerService.LocalBinder) service;
mListenerService = binder.getService();
mBound = true;
readFromService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
private void readFromService() {
Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage()); //this is the cause of the NPE
mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]);
if(parsedMessage >= 10 && parsedMessage <= 19 && parsedMessage != 0) {
mTextView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
} else {
mBlinkView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
}
}
}