3

I want to clear the clipboard after 60 seconds of putting a text onto the Android clipboard.

I tried the handler postDelayed below. Problem is when the activity is killed or the app goes to background (home button clicked), this function does not execute. How can I make sure to call the function when app is in background?

    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
           //Clear clipboard
        }
    }, 60000);
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
LAX_DEV
  • 2,111
  • 3
  • 19
  • 29
  • 6
    Possible duplicate of [How to execute background task when Android app is closed / set to background?](https://stackoverflow.com/questions/39507506/how-to-execute-background-task-when-android-app-is-closed-set-to-background) – Paco Abato Jun 03 '18 at 07:41
  • @PacoAbato thanks for pointing in right direction. I found google had a service firebase jobdispatcher (https://github.com/firebase/firebase-jobdispatcher-android). – LAX_DEV Jun 03 '18 at 08:52
  • @hellomtyj your use case is very simple and could be easily done through a 'Service` as I pointed out in my answer. Otherwise, if you prefer a job handling library, I've updated my answer with the one I strongly suggest. – GoRoS Jun 03 '18 at 09:49

1 Answers1

1

Since your Activity doesn't persist after the app is killed, you must go for a Service class. There're some circumstances where it may also be killed, but in a normal basis it will persist in most cases (otherwise check foreground services).

This approach should work:

Java

public class TestClipboardServiceActivity extends Activity {
    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startService(new Intent(this, MyClipboardService.class));

        // Forced the app to be destroyed intentionally.
        finish();
    }
}

/**
 * Clipboard Service. It will clear the clipboard after 60 seconds.
 */
public class MyClipboardService extends Service {

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyClipboardService", "Received start id " + startId + ": " + intent);

        // Remember, this is executed in the main thread.
        new Handler().postDelayed(new Runnable() {
            @Override public void run() {
                clearClipboard();
            }
        }, 6000);

        return START_STICKY;
    }


    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    private final IBinder mBinder = new LocalBinder();

    /**
     * Clears the clipboard.
     */
    private void clearClipboard() {
        ClipboardManager myClipboard =
            (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
        if (myClipboard != null) {
            myClipboard.setPrimaryClip(ClipData.newPlainText(null, "");
        }
    }
}

Kotlin

class TestClipboardServiceActivity : Activity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    startService(Intent(this, MyClipboardService::class.java))

    // Forced the app to be destroyed intentionally.
    finish()
  }
}

/**
 * Clipboard Service. It will clear the clipboard after 60 seconds.
 */
class MyClipboardService : Service() {

  private val mBinder = LocalBinder()

  inner class LocalBinder : Binder() {
    internal val service: MyClipboardService
      get() = this@MyClipboardService
  }

  override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
    Log.i("MyClipboardService", "Received start id $startId: $intent")

    // Remember, this is executed in the main thread.
    Handler().postDelayed(this::clearClipboard, 60000)

    return START_STICKY
  }

  override fun onBind(intent: Intent) = mBinder

  /**
   * Clears the clipboard.
   */
  private fun clearClipboard() {
    val myClipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    myClipboard.primaryClip = ClipData.newPlainText(null, "")
  }
}

On the other hand, if you prefer to use a custom library to handle jobs, I'll strongly suggest android-job from Evernote. It internally even uses the recent WorkManager class and the library contains several scheduling variants, apart from compatibility for many Android API and the lack of Google Play Services library. In your case you could take a look at the setExact(long exactInMs) method, providing an offset when the job should run from when the job was scheduled.

GoRoS
  • 5,183
  • 2
  • 43
  • 66