Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Service run in background?

One of the functions of the app which I'm building had a record function. I do this by starting a MediaRecorder object in a service:

Intent intent = new Intent(v.getContext(), RecordService.class);
Messenger messenger = new Messenger(handler);
intent.putExtra("COUNT", basic);
intent.putExtra("MESSENGER", messenger);

v.getContext().startService(intent);

//service

//...
mRecorder = new MediaRecorder();
//...

Now I introduced a notification which had to let the user know what the status is of the recording itself because if you go the the home or hit the backbutton, it has to keep recording. Therefore, if you hit the notification, you go back to the app.

That is where I am struggling, if I click the notification, I go back to the app but everything is set to the initial state (Timer is back 00:00:00 and I can hit the record button again instead of the pause button) What I should accomplish is of course that it keeps recording and that I can see the ongoing timer + stop button. note: the Timer is not a service right now.. Any ideas how I should handle this?

EDIT

Suppose I shut the app down, the service is still running. Reopening the app (and thus activity where the service was initially called from) can we do with:

private boolean isMyServiceRunning() {
        ActivityManager manager = (ActivityManager) myContext.getSystemService(Context.ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (MyService.class.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

So I partly have that covered, but, the variables passed from that Service to that activity are now gone. It seems that my Handler in my Activity is not picking them up after reopening that Activity?

private Handler handler = new Handler() {
        public void handleMessage(Message message) {

            //..
            Bundle bundle = message.getData();
            fileName = bundle.getString("FILENAME");
            tvFileName.setText(fileName);


            Log.e("Filename", "transfered: " + fileName);

        };
    };

//EDIT

Fragment:

public class LayoutOne extends Fragment implements OnClickListener {

    //vars
    @Override
    public void onPause() {
        super.onPause();
        if (mRecorder != null) {
            mRecorder.release();
            mRecorder = null;
        }

        if (mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
    }

    private Handler handler = new Handler() {
        public void handleMessage(Message message) {

            int i = message.arg1;
            Bundle bundle = message.getData();
            fileName = bundle.getString("FILENAME");
            tvFileName.setText(fileName);

            Log.e("Handler", "Succesfully transfered: " + (Integer.toString(i)));
            Log.e("Filename", "Succesfully transfered: " + fileName);
        };
    };

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
        case R.id.bRecord:

            if (mStartRecording) {
                mStartRecording = false;
                Intent intent = new Intent(v.getContext(), RecordService.class);

                Messenger messenger = new Messenger(handler);
                intent.putExtra("MESSENGER", messenger);
                v.getContext().startService(intent);


            } else {
                mRecordButton.setText("Record");
                Intent stopIntent = new Intent(v.getContext(),
                        RecordService.class);

                try {
                    v.getContext().stopService(stopIntent);
                } catch (Exception e) {
                    e.printStackTrace();

                }
                mStartRecording = true;
            }

            break;

        case R.id.bStop:
            Intent stopIntent = new Intent(v.getContext(), RecordService.class);
            v.getContext().stopService(stopIntent);
            break;

        }
    }

    public static Fragment newInstance(Context context) {
        LayoutOne f = new LayoutOne();
        return f;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        root = (ViewGroup) inflater.inflate(R.layout.layout_one, null);
        myContext = container.getContext();

        //buttons

        mgr = (NotificationManager) myContext.getSystemService(Context.NOTIFICATION_SERVICE);
        return root;
    }



    public void notifyMe(View v) {
        Notification note = new Notification(R.drawable.ic_launcher,
                getString(R.string.notificationbar), System.currentTimeMillis());
        PendingIntent i = PendingIntent.getActivity(myContext, 0, new Intent(
                myContext, ViewPagerStyle1Activity.class), 0);

        note.setLatestEventInfo(myContext, getString(R.string.app_name),
                getString(R.string.notification), i);
        note.number = ++count;
        note.vibrate = new long[] { 500L, 200L, 200L, 500L };
        note.flags |= Notification.FLAG_AUTO_CANCEL;

        mgr.notify(NOTIFY_ME_ID, note);
    }

    public void clearNotification(View v) {
        mgr.cancel(NOTIFY_ME_ID);
    }

    // /SHARED PREFERENCES SETTINGS///
//…

    private void initiatePopupWindow() {
        //..
    }



    @Override
    public void onResume() {
        super.onResume();
        Intent intent = new Intent(myContext, RecordService.class);
        myContext.startService(intent);
        myContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
             LocalBinder binder = (LocalBinder) service;
                myService = binder.getService();
                //myService.setBound(true);
                initializeUI();

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub

        }
    };

    protected void initializeUI() {
        //..

        }

    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        myContext.unbindService(mServiceConnection);
    }

    @Override
    public void onStop() {
        // TODO Auto-generated method stub
        myContext.unbindService(mServiceConnection);
    }



}

//SERVICE

public class RecordService extends Service {

    //vars

     public class LocalBinder extends Binder {
            RecordService getService() {
                return RecordService.this;
            }
        }

    @Override
    public void onCreate() {
        Log.i("Oncreate", "Service onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Bundle extras = intent.getExtras();
        if (extras != null) {

            messenger = (Messenger) extras.get("MESSENGER");
            count = Integer.toString(extras.getInt("COUNT"));
            try {
                Message message = new Message();
                int arg = 0;
                message.arg1 = arg;

                mFileNamePass=”test”;
                Bundle bundle = new Bundle();
                bundle.putString("FILENAME", mFileNamePass);
                message.setData(bundle);
                messenger.send(message);
            } catch (android.os.RemoteException e1) {
                Log.w(getClass().getName(), "Exception sending message", e1);
            }
        }
        else {
            Log.i("Extras","Didn't find extras");
        }

        Runnable r = new Runnable() {

            @Override
            public void run() {
                checkIfFolderExists();
                String dateFull = calculateDate();
                mFileName = Environment.getExternalStorageDirectory()
                        .getAbsolutePath();
                mFileName += "test.3gp";

                mRecorder = new MediaRecorder();
                mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                mRecorder.setOutputFile(mFileName);
                mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

                try {
                    mRecorder.prepare();
                } catch (IOException e) {
                    Log.e(LOG_TAG, "prepare() failed");
                }

                mRecorder.start();
                Log.i("Service", "Service running");

            }
        };

        Thread t = new Thread(r);
        t.start();
        return RecordService.START_STICKY;
    }

    @Override
    public void onDestroy() {

        Runnable stopRecord = new Runnable() {

            @Override
            public void run() {
                mRecorder.stop();
                mRecorder.release();
                mRecorder = null;

            }

        };
        Thread stopRecordThread = new Thread(stopRecord);
        stopRecordThread.start();
        Log.i("Service", "Service stopped");
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }



}
like image 517
Matthias Vanb Avatar asked Nov 13 '22 09:11

Matthias Vanb


1 Answers

First of all, you don't need to check if your Service is running by some ActivityManager method. If you call startService() && bindService() in your onResume(), Android is smart enough to just bind to the Service if it's already running, and if not, it will create the Service going through it's proper documented lifecycle and then bind to it.

What you could do here is this:

@Override
public void onResume() {
    super.onResume();
    Intent intent = new Intent(this, YourService.class);
    startService(intent);
    bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

Now, lets say your Service is already running and you want to get it's proper values. In the onServiceConnected() method of your ServiceConnection(), you can call a method like initializeUI() when the binding is done:

private ServiceConnection mServiceConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        LocalBinder binder = (LocalBinder) service;
        myService = binder.getService();
        myService.setBound(true);
        initializeUI();
    }

    public void onServiceDisconnected(ComponentName className) {
    }
};

And now, you have the myService variable that points to your Service object which you can call your getters on, like myService.getTimer() and myService.isRecording().

public void initializeUI() {
    timerTextview.setText( myService.getTime() );
    someOtherUiElement.setText( myService.getSomething() );
    if( myService.isRecording() )
        recordButton.setImageResource( R.drawable.pause );
} //etc...

By the way, I don't know if you're also struggling on keeping your Service running when you exit the app If you do, using startService(intent) will keep your Service running as long as Android has enough memory. You MUST have a piece of code in which you can call myService.stopService(), otherwise, the Service will run for a very long time.

like image 191
tolgap Avatar answered Nov 14 '22 22:11

tolgap