服务重启后的DeadObjectException

时间:2016-12-06 11:47:24

标签: java android sockets

我的活动已开始使用startService()服务,并且onStart()方法绑定到同一服务。我正在使用Messenger发送一些文本进行服务,然后将服务打开套接字发送到发送此文本的服务器,服务器响应一些文本(此工作正常)。当我尝试使用messenger将响应从服务发送到活动时,会出现问题。当应用程序第一次启动时,即使工作正常,但在应用程序被杀死后(重启服务)并且我正在尝试将响应从服务发送到活动,我得到DeadObjectException。我评论了服务中出现错误的行。

这是我的活动:

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    TextView tvFromServer;
    EditText etSend;
    Button bSend, bStopSocket, bBound, bStopService;
    boolean mRun;
    Intent mIntent;

    /** Messenger for communicating with the service. */
    Messenger mService = null;
    /** Flag indicating whether we have called bind on the service. */
    boolean mBound;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        //SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
        //        .findFragmentById(R.id.map);
        //mapFragment.getMapAsync(this);

        initialize();
        mIntent = new Intent(this, SocketService.class);
        startService(mIntent);

    }

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

        Intent iBind = new Intent(this, SocketService.class);
        iBind.putExtra("messenger", new Messenger(mHandler));
        bindService(iBind, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
            mConnection = null;
            mHandler = null;
        }
    }

    Handler mHandler = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(Message msg) {
            //Log.v("MapsActivity", (String) msg.obj );(String) msg.obj
            tvFromServer.setText(msg.getData().getString("text"));
        }
    };

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


    private void initialize(){
        tvFromServer = (TextView) findViewById(R.id.tv_from_server);
        bStopSocket = (Button) findViewById(R.id.b_stop);
        mRun = false;
        bStopSocket.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mRun = false;
            }
        });

        etSend = (EditText) findViewById(R.id.et_send);
        bSend = (Button) findViewById(R.id.b_send);
        bSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!mBound) return;
                Message msg = Message.obtain(null, 1, etSend.getText().toString());
                try {
                    mService.send(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

        bBound = (Button) findViewById(R.id.b_bound);
        bBound.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!mBound) return;
                Message msg = Message.obtain(null, 1, "Hello from Activity");
                try {
                    mService.send(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }

            }
        });
        bStopService = (Button) findViewById(R.id.b_stop_service);
        bStopService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mBound) {
                    unbindService(mConnection);
                    mBound = false;
                }
                stopService(mIntent);
            }
        });
    }


    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user will be prompted to install
     * it inside the SupportMapFragment. This method will only be triggered once the user has
     * installed Google Play services and returned to the app.
     */
    @Override
    public void onMapReady(GoogleMap googleMap) {
        //mMap = googleMap;

        // Add a marker in Sydney and move the camera
        //LatLng sydney = new LatLng(-34, 151);
        //mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
        //mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
    }

}

服务:

public class SocketService extends Service {
    public SocketService() {
    }

    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;
    public Messenger mMessenger, mUiMessenger;
    PrintWriter out;
    Socket mSocket;
    boolean mRun;
    Thread threa;


    // Handler that receives messages from the thread
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            // Normally we would do some work here, like download a file.
            // For our sample, we just sleep for 5 seconds.
            if(msg.what == 1){
                out.println((String) msg.obj);
            }

        }
    }

    @Override
    public void onCreate() {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
        // Start up the thread running the service.  Note that we create a
        // separate thread because the service normally runs in the process's
        // main thread, which we don't want to block.  We also make it
        // background priority so CPU-intensive work will not disrupt our UI.
        HandlerThread thread = new HandlerThread("SocketService");
        thread.start();

        // Get the HandlerThread's Looper and use it for our Handler
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
        mMessenger = new Messenger(new ServiceHandler(mServiceLooper));
        mRun = false;

        threa = new Thread(new Runnable() {
            @Override
            public void run() {
                socketConnection();

            }
        });
        threa.start();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        mServiceHandler.sendMessage(msg);
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        Bundle extras = intent.getExtras();
        mUiMessenger = (Messenger) extras.get("messenger");
        return mMessenger.getBinder();
    }

    @Override
    public void onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();

    }

    private void socketConnection() {
        mRun = true;
        try{
            mSocket = new Socket("xxx.xxx.xxx.xxx", xxxxx);
            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));

            while(mRun){
                String s = in.readLine();
                Log.v("SocketServiceFromServer", s);
                Bundle bundle = new Bundle();
                bundle.putString("text", s);
                Message msg = Message.obtain(null, 1);
                msg.setData(bundle);
                try {
                    mUiMessenger.send(msg); //DeadObjectException is thrown here after service is restarted
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            mSocket.close();
        }catch(Exception e){
            Log.e("SocketService ", e.toString());
        }
    }
}

logcat的:

![logcat

我的问题是,为什么会抛出这个错误?看起来活动在重启后绑定到服务时不会发送新的messenger对象服务。

1 个答案:

答案 0 :(得分:1)

我有完全相同的问题,我找到了解决方案。我花了4个小时调试代码,搜索互联网并尝试了数百万种不同的方法。解决方案非常简单。删除onCreate中的调用startService。仅使用bindService和unbindService。是的,这很简单......