I want to know how to execute adb commands from within my code. For e.g I want to push a file inside the adb shell and I write this:
package org.example.adbshell;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Process process;
try {
process = Runtime.getRuntime().exec("adb push C:/Users/Savio/Desktop/savio.xml /storage/sdcard0/");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
}
I should be able to see the savio.xml inside the /storage/sdcard0 folder. But for some reason I am unable to see the file. I am guessing that the command is not getting executed. What am I doing wrong here?
There are three type of command
System command // In this case below code is working. like mv/edit/cp/cd etc
Non routed command
Rooted command // You need to routed device.
Try this
Process process Runtime.getRuntime().exec("your command");
//or
Process process Runtime.getRuntime().exec("/path/your_command");
Its work for me of copying file :
Process process Runtime.getRuntime().exec("/system/bin/mv my_file_path");
You can read output data with the help of process object
// Use buffer reader for the same.
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
There is no ADB command on Android's side. ADB is a part of Android SDK only and is always run on computer not on Android.
Also, Android knows nothing about C:/Users/Savio/Desktop/savio.xml as it is not a file in its filesystem.
You should rather implement desktop application with HTTP (or similar) server and use it to download and upload files from Android to PC. You can start with NanoHTTP, a lightweight HTTP implementation.
Or you can use server for communication between Android and computer and run ADB command on that computer based upon request from Android.
Related
I have a javafx project that I am preparing for distributions. The project works perfectly from the debugger inside NetBeans. I am working on Linux.
But when I run the project from the jar file, there is one function in all the others that does not work. This function is supposed to open the settings file on a button click and alter some values from true to false.
I have changed the settings file's location and tried around google, but all to no avail.
I am still quite a newbie to java, fx, netbeans and java (not so much programming) and making my first experiences.
Any idea why this happens?
#FXML
private void openSettingsFile(ActionEvent event) throws IOException {
// this test works ....
ProcessBuilder processBuilder = new ProcessBuilder("terminal");
processBuilder.start();
// this part only replaces the values when I use the debugger ..
Path path = Paths.get("src/desktop_launcher/Settings.java");
Charset charset = StandardCharsets.UTF_8;
String content = new String(Files.readAllBytes(path));
content = content.replaceAll(" \"true\"" , " \"false\"");
Files.write(path, content.getBytes(charset));
Your approach (which, as far as I understand it, is to try to programmatically change the source file that generates the properties file) will not work at deployment time for a number of reasons.
The first is that the source files are generally not available at runtime: your jar file contains the class files and other resources required to run the application, but typically not the source code (and it's not desirable to include it in the application, in general).
Secondly, you are trying to locate this file from a relative path passed to Paths.get(..). This will resolve relative to the working directory, which is essentially arbitrary (basically "where the application was run from"). So even if the source code were available at runtime, this would not be a reliable way to find it. (My guess is that your debugger runs with the working directory fortuitously set to the parent directory of src, but when you run the jar file the most likely location of the working directory is the directory in which the jar file is located. But that is just a guess: it really depends on the configuration of your IDE, debugger, etc etc.)
Thirdly, and probably most importantly, even if the code does find the source file and rewrite it, that's all it will do. Next time you execute the application from the jar file, it won't magically know there is a new version of the source code that has to be compiled and then the resulting class file(s) incorporated into the jar file. So you would have to also include code to compile the new version of your source code (where will you get a compiler? AFAIK not all Java runtimes will include a compiler) and then programmatically insert the new class file(s) into the jar file (how do you even figure out where the jar file is: that is certainly non-trivial and I don't think it can be done in a reliable manner). What if the current user doesn't have permissions to write the directory containing the jar (which is a pretty common scenario..)?
The usual way to load and save startup configuration values is to use the java.util.Properties API. You need an external location to store the properties file, that you can be certain exists on the user's computer: a convenient way to do this is to create an application-specific directory in the user's home directory. The user's home directory can be accessed via System.getProperty("user.home"); (The system property user.home is one of those that is guaranteed to exist.).
I would recommend using a separate class to manage the configuration properties. For example:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Properties;
public class PropertiesAccessor {
private static final Path USER_HOME = Paths.get(System.getProperty("user.home"));
private Properties props ;
private Path path ;
public PropertiesAccessor(String relativePath) {
path = USER_HOME.resolve(relativePath);
props = new Properties();
if (Files.exists(path)) {
try {
props.load(Files.newBufferedReader(path));
} catch (IOException exc) {
System.err.println("Warning: could not load properties file. Using defaults.");
exc.printStackTrace(System.err);
loadDefaults();
}
} else {
loadDefaults();
}
}
public Boolean getBooleanValue(String key) {
String value = props.getProperty(key);
return value == null ? null : Boolean.valueOf(value) ;
}
public void updateBooleanValue(String key, boolean value) {
props.setProperty(key, Boolean.toString(value));
}
public void writeProperties() throws IOException {
if (! Files.exists(path)) {
Files.createDirectories(path.getParent());
Files.createFile(path);
}
props.store(Files.newBufferedWriter(path), "Properties updated "+LocalDateTime.now());
}
private final void loadDefaults() {
// in real life, you might keep a default properties file bundled with
// the application and read that here, e.g.
// props.load(getClass().getResourceAsStream("/default-startup.properties"));
props.setProperty("config.value1", "true");
props.setProperty("config.value2", "false");
}
}
And now you can use this in your application. Just load the properties in the init() method and save them back in the stop() method. Note that executing this will create a directory called .myApp in your home directory, and a file called startup.properties inside it.
import java.io.IOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class StartupPropertiesExample extends Application {
private PropertiesAccessor config ;
private CheckBox value1 ;
private CheckBox value2 ;
#Override
public void init() {
config = new PropertiesAccessor(".myApp/startup.properties");
}
#Override
public void start(Stage primaryStage) {
value1 = new CheckBox("Value 1");
value2 = new CheckBox("Value 2");
value1.setSelected(config.getBooleanValue("config.value1"));
value2.setSelected(config.getBooleanValue("config.value2"));
Button exit = new Button("Exit");
exit.setOnAction(e -> Platform.exit());
VBox root = new VBox(10, value1, value2, exit);
root.setPadding(new Insets(10));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void stop() {
config.updateBooleanValue("config.value1", value1.isSelected());
config.updateBooleanValue("config.value2", value2.isSelected());
try {
config.writeProperties();
} catch (IOException exc) {
System.err.println("Warning: could not save properties");
exc.printStackTrace(System.err);
}
}
public static void main(String[] args) {
launch(args);
}
}
In my Swing application I needed support for rendering html. So I embedded a JavaFX WebView in my Swing application. Now on some html pages I use the new html5 -Tag to play a video. This works perfectly on Windows and Linux. But on MacOS I only hear the sound and see a black video frame and the time track in the bottom.
Here is an SSCCE I got from github. I just changed the url to one that contains a html5 video-tag example. Would be great, if you MacOS users could try it and tell me if the same happens on you computer. And of course any idea to fix this is appreciated.
SSCCE:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.sun.javafx.application.PlatformImpl;
/**
* SwingFXWebView
*/
public class JavaFXTest extends JPanel
{
private Stage stage;
private WebView browser;
private JFXPanel jfxPanel;
private JButton swingButton;
private WebEngine webEngine;
private Object geo;
public JavaFXTest()
{
this.initComponents();
}
public static void main(final String... args)
{
// Run this later:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
final JFrame frame = new JFrame();
frame.getContentPane().add(new JavaFXTest());
frame.setMinimumSize(new Dimension(640, 480));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
private void initComponents()
{
this.jfxPanel = new JFXPanel();
this.createScene();
this.setLayout(new BorderLayout());
this.add(this.jfxPanel, BorderLayout.CENTER);
this.swingButton = new JButton();
this.swingButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(final ActionEvent e)
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
JavaFXTest.this.webEngine.reload();
}
});
}
});
this.swingButton.setText("Reload");
this.add(this.swingButton, BorderLayout.SOUTH);
}
/**
* createScene Note: Key is that Scene needs to be created and run on
* "FX user thread" NOT on the AWT-EventQueue Thread
*/
private void createScene()
{
PlatformImpl.startup(new Runnable()
{
#Override
public void run()
{
JavaFXTest.this.stage = new Stage();
JavaFXTest.this.stage.setTitle("Hello Java FX");
JavaFXTest.this.stage.setResizable(true);
final Group root = new Group();
final Scene scene = new Scene(root, 80, 20);
JavaFXTest.this.stage.setScene(scene);
// Set up the embedded browser:
JavaFXTest.this.browser = new WebView();
JavaFXTest.this.webEngine = JavaFXTest.this.browser.getEngine();
JavaFXTest.this.webEngine.load("http://camendesign.com/code/video_for_everybody/test.html");
final ObservableList<Node> children = root.getChildren();
children.add(JavaFXTest.this.browser);
JavaFXTest.this.jfxPanel.setScene(scene);
}
});
}
}
Here is a semi-answer, which might help:
The oracle website states:"At this time, Online Installation and Java Update features are not available for 64-bit architectures"
For me this caused lots of problems, because Java seems up to date, but actually isn't. On some machines I could solve the actual issue by just manually updating the Java 64bit VM. On Mac however, the video still isn't playing, only sound.
The 64bit/32bit issue gets even worse, since a double click on a jar might start it in the 64bit JVM, but via console it is started in 32bit JVM. So if you do a "java -version" in console, the output might be "1.7.0 u45 32-bit", but as soon as you start the jar via double click it is started in an outdated 64bit JVM.
So if you ever run in an JavaFX issue (especially with UnsatisfiedLinkError) and you have a 64bit computer, just install the latest 64bit java and hope that it solves the problem.
I am trying to learn some JavaFx these days. I set up a simple MVC and it works well until I click the button to invoke click envet. It throws java.lang.NullPointerException. I think the problem is that the instance variable "controller" is not initialized after GUI launched. But I do initialize it in the main method. Below is view class and what I did in the main method.
package javafxdemogui;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author Jason
*/
public class DemoView extends Application {
private TextArea inputText;
private TextArea outputText;
private DemoController controller;
#Override
public void start(Stage primaryStage) {
BorderPane borderPane = new BorderPane();
this.inputText = new TextArea();
this.outputText = new TextArea();
this.inputText.setWrapText(true);
this.outputText.setWrapText(true);
this.outputText.setEditable(false);
borderPane.setTop(inputText);
HBox hbox = new HBox();
hbox.setSpacing(10);
Button resetBtn = new Button("reset");
Button copyInputBtn = new Button("copyInput");
hbox.getChildren().addAll(resetBtn, copyInputBtn);
hbox.setAlignment(Pos.CENTER);
borderPane.setCenter(hbox);
borderPane.setBottom(outputText);
resetBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
controller.processResetEvent();
}
});
copyInputBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
controller.processCopyEvent(inputText.getText());
}
});
Scene scene = new Scene(borderPane, 600, 400);
primaryStage.setTitle("JavaFXDemoGUI");
primaryStage.setScene(scene);
primaryStage.show();
}
public void registerObserver(DemoController controller) {
this.controller = controller;
}
/**
* Updates input display based on String provided as argument.
*
* #param input new value of input display
*/
public void updateInputDisplay(String input) {
this.inputText.setText(input);
}
/**
* Updates output display based on String provided as argument.
*
* #param output new value of output display
*/
public void updateOutputDisplay(String output) {
this.outputText.setText(output);
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* #param args the command line arguments
*/
public void viewLaunch(String[] args) {
launch(args);
}
}
And What I did in the main method....
public static void main(String[] args) {
/*
* Create instances of the model, view, and controller objects, and
* initialize them; view needs to know about controller, and controller
* needs to know about model and view
*/
DemoModel model = new DemoModel();
DemoView view = new DemoView();
DemoController controller = new DemoController(model, view);
view.registerObserver(controller);
view.viewLaunch(args);
}
I advise placing the main() method in your application class and not doing anything in main but launching the application.
I haven't tried it, but I'd be willing to bet that when Application.launch is invoked, that it generates a new instance of your application class, so effectively all of the code you have written in main before the launch is ignored.
I know that for a while, for Java 8 the Oracle team were considering not invoking main on startup for launching a JavaFX application (not sure what the eventual outcome of that was though, perhaps they still invoke the main method).
What you really should do instead is handle all of your initialization in the init or start methods of your application. Also note (in JavaFX 2.2) that if you do stuff in init there are some restrictions on JavaFX objects which can be instantiated (as you are not yet on the JavaFX application thread), for example you can't create Tooltips or WebViews off the JavaFX application thread. For this reason most of the JavaFX applications you see end up creating their UI on the JavaFX application thread at the front of the start method.
Also, a good approach is to shelve any long running tasks which can be done off of the JavaFX application thread (such as reading a database into something like your DemoModel) off to a JavaFX concurrent task, that way you can get progress feedback and messages from that long running task back to your UI to update an initialization status (if your framework requires that level of sophistication).
JavaFx is supposed to be easily integrated in an SWT application (see here: http://docs.oracle.com/javafx/2/swt_interoperability/jfxpub-swt_interoperability.htm) and both toolkits use the same threading model.
However things get strange, when I open a dialog containing an FxCanvas which contains a JavaFx ComboBox. If I open the combo box popup menu and then close the dialog, the popup menu stays open. If I now move the mouse onto the popup a null pointer exception is thrown within javafx. When doing this within a larger application all JavaFx GUIs remain broken until the application is restarted.
Any ways to work around this?
Example code below: Close the dialog with 'Ok' or the window close button. Exit the application with 'Cancel'
package test;
import javafx.embed.swt.FXCanvas;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class TestFx {
static class MyDialog extends Dialog {
Parent w;
public MyDialog(Shell parent,Parent n) {
super(parent);
this.w = n;
setShellStyle(SWT.RESIZE| SWT.BORDER | SWT.TITLE |SWT.CLOSE );
}
#Override
public void cancelPressed() {
System.exit(0);
}
#Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
container.setLayout(new FillLayout());
FXCanvas fxCanvas = new FXCanvas(container, SWT.NONE);
Scene scene = new Scene(w);
fxCanvas.setScene(scene);
return container;
}
}
private static Parent createScene() {
StackPane pane = new StackPane();
pane.setPadding(new Insets(10));
ComboBox<String> c = new ComboBox<String>();
c.getItems().addAll("Test1","Test2");
pane.getChildren().add(c);
return pane;
}
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
while (true) {
MyDialog d = new MyDialog(shell,createScene());
d.open();
}
}
}
Exception:
java.lang.NullPointerException
at com.sun.javafx.tk.quantum.GlassScene.sceneChanged(GlassScene.java:290)
at com.sun.javafx.tk.quantum.ViewScene.sceneChanged(ViewScene.java:156)
at com.sun.javafx.tk.quantum.PopupScene.sceneChanged(PopupScene.java:30)
at com.sun.javafx.tk.quantum.GlassScene.markDirty(GlassScene.java:157)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2214)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:363)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
at com.sun.javafx.tk.quantum.QuantumToolkit$9.run(QuantumToolkit.java:329)
at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2546)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3756)
at org.eclipse.jface.window.Window.runEventLoop(Window.java:825)
at org.eclipse.jface.window.Window.open(Window.java:801)
at test.TestFx.main(TestFx.java:55)
At work we're developing some applications using JavaFX, on top of and old Swing platform and we also have found this issue.
Apparently it is caused by some issues on JFXPanel which is not correctly propagating some window events (focus, iconifying, etc) to the FX framework. The issue affects not only the ComboBox component, but every component that uses a PopupWindow (Menu, Tooltip, etc), specially when using Swing's JInternalFrame.
So, when a Popup is displaying and the window is minimized or closed, the Popup does not hide, causing the FX thread to crash if you try subsequently to interact with it.
The workaround mentioned above works, but only for ComboBox, as Menu and Tooltip does not inherit from the Node class, so didn't work for us :(
I developed another workaround which resolved the problem for all components that display popups, which basically forces all popups to close whenever a JFXPanel loses focus:
private static void initFX(final JFXPanel jfxPanel) {
final TestFxPanel parent = new TestFxPanel();
final Scene scene = new Scene(parent);
jfxPanel.setScene(scene);
jfxPanel.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(final FocusEvent e) {
System.out.println(jfxPanel.getName() + ": FocusLost");
runFocusPatch(scene);
}
});
}
static void runFocusPatch(final Scene scene) {
Platform.runLater(new Runnable() {
#Override
public void run() {
System.out.println("Running patch");
final Iterator<Window> winIter = scene.getWindow().impl_getWindows();
while (winIter.hasNext()) {
final Window t = winIter.next();
if (t instanceof PopupWindow) {
System.out.println("Got a popup");
Platform.runLater(new Runnable() {
#Override
public void run() {
((PopupWindow) t).hide();
}
});
}
}
}
});
}
I confirm that the issue is NOT present in 8.0. Sadly we are not allowed to java 8 in production software as its still in beta stage.
best regards.
I found a workaround when using Java7: Override the close method in Dialog to hide the combo box popups:
#Override
public boolean close() {
Set<Node> nodes = w.lookupAll("#");
for (Node n : nodes)
if (n instanceof ComboBox)
((ComboBox)n).hide();
return super.close();
}
The trouble is discussed here : javafx-jira.kenai.com/browse/RT-30991
Developer has said, that the issue is fixed in JavaFX-8
I'm trying to create an Android application that shows the current time. I want to update time on my Activity with the Timer, but the TextView is not updating, so just one time is always on the screen. Here is my code:
package com.example.androidtemp;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.example.androidtemp.R;
public class ActivityTime extends Activity
{
SimpleDateFormat sdf;
String time;
TextView tvTime;
String TAG = "States";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity_time);
sdf = new SimpleDateFormat("HH:mm:ss");
time = sdf.format(new Date(System.currentTimeMillis()));
tvTime = (TextView) findViewById(R.id.tvTime);
Timer timer = new Timer();
TimerTask task = new TimerTask()
{
#Override
public void run()
{
// TODO Auto-generated method stub
timerMethod();
}
};
try
{
timer.schedule(task, 0, 1000);
}
catch (IllegalStateException e)
{
// TODO: handle exception
e.printStackTrace();
Log.e(TAG, "The Timer has been canceled, or if the task has been scheduled or canceled.");
}
}
protected void timerMethod()
{
// TODO Auto-generated method stub
this.runOnUiThread(changeTime);
}
private final Runnable changeTime = new Runnable()
{
public void run()
{
// TODO Auto-generated method stub
//Log.d(TAG, "Changing time.");
sdf.format(new Date(System.currentTimeMillis()));
tvTime.setText(time);
}
};
}
Does anyone have solution for this problem?
I would recommend you to use DigitalClock or TextClock (you can use 'include' in the layout xml and layout / layout-v17 to use a different component depending of the OS version) if you just want to show the time.
If you want to have more control, I would recommend you using a Handler or an ExecutorService instead of a Timer. Java Timer vs ExecutorService?
If you want to fix your code as it is, just modify the value of the variable 'time' ;)
Use a handler since it can access the views of your application. The views of your application belong to the main thread already so creating another thread to access them usually doesn't work. If am not wrong, handlers use messages to communicate with the main thread and its components. Use this where you have your thread definition instead:
Handler handler = new Handler();
handler.removeCallbacks(runnable);
handler.postDelayed(runnable, 1000);
and add this to your runnable definition
handler.postDelayed(runnable, 1000);
This last statement removes any instance of runnable awaiting execution when a new on is added. Kind of like clearing a queue.