从另一个线程访问上下文 [英] Accessing context from another thread

查看:96
本文介绍了从另一个线程访问上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始迁移某些PC的Java应用程序到Android环境是关于Android平台的一个完整的新手。

I am starting to migrate some PC Java applications to Android environments being a complete newbie concerning Android platform.

我发现了一个问题,当我试图使用的服务的基准为背景的的吐司消息。

I found a problem when I tried to use a Service reference as context for a Toast message.

这是有关部分我的服务的code:

This is the relevant part of my Service code:

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已经停止。

When the scheduled task runs reaching doToast call Android notifies that "Unfortunatelly, myAPP has stopped".

我认为这是与我使用的服务上下文在不同的线程,但我不知道肯定做的事实。

I think it has something to do with the fact I am using the service context in a different thread but I don't know for sure.

你能不能确认,如果是这样的话?什么是正确的方式来运行服务一个计时器,并能够使用它的上下文?如果这是不可能的,我可以得到一个上下文线程,所以我可以生成敬酒用户消息。

Could you confirm if that is the case? What is the right way to run a timer from a service and be able to use its context? If that is not possible, can I get a context for that thread so I can generate Toasts user messages.

推荐答案

这取决于你真正需要的,如果你正计划显示简单的通知,也许,而不是祝酒词,你可以使用Android的通知栏(这是标准的方式向他们展示)。例如,你可以使用:

It depends on what you really need, if you are planning to show simple notifications, maybe instead of toasts you can use Android notification bar (which is the standard way to show them). For example you can use:

  /**
     * 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);
    }

不过,如果你只是想敬酒,你可以从服务向他们展示,你的问题是TimerTask的是在不同的线程的UI线程(在服务正在运行)执行。 后这个code到UI线程就可以直接像这样做:

however, if you just want toasts, you can show them from the service, your problem is that the timertask is being executed in a different thread that the UI thread (where the service is running). to "post" this code to the UI thread you can do it directly with something like this:

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);
    }

<一个href="http://stackoverflow.com/questions/18948251/not-able-to-call-runonuithread-in-a-thread-from-inside-of-a-service">Source

最后,如果你想要的服务和活动之​​间充分互动,你有几种方式:

And finally if you want fully interaction between service and activities, you have several ways:

  1. 使用粘合剂,简单的通信,这是收起你所需要的。
  2. 使用的使者,更复杂的通信。
  3. 如果您只需要对话框,你总是能够推出新的活动的对话框模式。
  4. AIDL ...

文档约1安培; 2 这里和的这里

Documentation about 1 & 2 here and here

  1. 粘合剂: 他们让你绑定不同的对象,在应用程序中直接让他们访问对象本身和它的功能,例如,从机器人DOC:

  1. Binders: They let you bind different objects in your application letting them access directly to the object itself and its functions, example from android doc:

公共类本地服务延伸服务{         //粘合剂给客户端         私人最终的IBinder mBinder =新LocalBinder();         //随机数发生器         私人最终随机mGenerator =新的随机();

public class LocalService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); // Random number generator 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;
        }
    };
}

  • 信使: 更先进的&放大器;复杂的,这样你可以从一个对象发送消息给另一个:

  • Messenger: More advanced & complicated, in this way you can send messages from one object to another:

    公共类MessengerService延伸服务{         / **命令到服​​务,以显示一条消息* /         静态最终诠释MSG_SAY_HELLO = 1;

    public class MessengerService extends Service { /** Command to the service to display a message */ 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;
                }
            }
        }
    

  • 如果你想展示活动,看中的对话框,显示更新,你可以使用常规的活动与这个主题:

    In case you want to show activities as fancy dialogs to show the updates you can use a regular activity with this theme:

    <activity android:theme="@android:style/Theme.Dialog" />
    

    这篇关于从另一个线程访问上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆