我开始将一些PC Java应用程序迁移到Android环境,这是一个关于Android平台的完整新手。
当我尝试使用服务引用作为Toast消息的上下文时,我发现了一个问题。
这是我的服务代码的相关部分:
public class ServicePFPE extends Service {
Timer messageSimulator;
TimerTask messagePoll;
private class MessageReceptionTask extends TimerTask
{
public MessageReceptionTask(Context c) {
context = c;
}
@Override
public void run() {
String shownText = "Message received!! on " + (new Date(System.currentTimeMillis())).toString();
//doToast(shownText, context); //THIS LINE MAKES THE APP CRASH!
System.out.println(shownText); //But I can do this
}
private Context context;
}
public ServicePFPE() {
super();
messageSimulator = new Timer();
messagePoll = new MessageReceptionTask(this);
}
@Override
public IBinder onBind(Intent intent)
{
doToast("Service: onBind");
return null;
}
...
...
...
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
doToast("Service: onStartCommand");
messageSimulator.schedule(messagePoll, 5000, 5000);
return super.onStartCommand(intent, flags, startId);
}
...
...
...
private void doToast(String msg) { doToast(msg, this); }
private void doToast(String msg, Context con) {
Toast.makeText(con,msg,Toast.LENGTH_SHORT).show();
}
}
当计划任务运行到达 doToast 时,Android会通知“不幸的是,myAPP已停止”。
我认为这与我在不同线程中使用服务上下文的事实有关,但我不确定。
您能否确认是否属实?从服务运行计时器并使用其上下文的正确方法是什么?如果那是不可能的,我可以获得该线程的上下文,以便我可以生成Toasts用户消息。
答案 0 :(得分:1)
这取决于你真正需要什么,如果你打算显示简单的通知,也许你可以使用Android通知栏(这是显示它们的标准方式)而不是祝酒词。例如,您可以使用:
/**
* Show a notification while this service is running.
*/
private void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.local_service_started);
NotificationManager mNM;
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.stat_sample, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, LocalServiceActivities.Controller.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.local_service_label),
text, contentIntent);
// Send the notification.
mNM.notify(NOTIFICATION, notification);
}
但是,如果你只是想要敬酒,你可以从服务中显示它们,你的问题是时间任务是在UI线程(服务运行的地方)的不同线程中执行的。要将此代码“发布”到UI线程,您可以使用以下内容直接执行此操作:
Handler handler;
@Override
public void onCreate() {
// Handler will get associated with the current thread,
// which is the main thread.
handler = new Handler();
super.onCreate();
}
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
最后,如果你想要在服务和活动之间进行充分的互动,你有几种方法:
粘合剂: 它们允许您绑定应用程序中的不同对象,让它们直接访问对象本身及其功能,例如来自android doc:
public class LocalService extends Service { //给客户的Binder 私人决赛IBinder mBinder = new LocalBinder(); //随机数生成器 private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
信使: 更高级的&复杂,通过这种方式,您可以将消息从一个对象发送到另一个对象:
公共类MessengerService扩展Service { / **命令服务显示消息* / static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
如果您想将活动显示为花哨的对话框以显示更新,您可以使用此主题的常规活动:
<activity android:theme="@android:style/Theme.Dialog" />
答案 1 :(得分:0)
任何与UI相关的代码都应该使用RunOnUiThread方法在UI线程上运行。
答案 2 :(得分:0)
你应该像这样设置一个全局上下文:
public static Activity currentActivity=null;
并在运行主活动或运行服务集上下文的任何活动之后:
MainActivity.currentActivity = this;
之后在吐司中使用此上下文:
Toast.makeText(MainActivity.currentActivity," text", Toast.LENGTH_LONG);
希望使用完整