I have a runnable which starts an activity and a handler, which lets the runnable repeat after 5 seconds. However, i implemented a "stop button" which should stop that handler, but somehow it doesn't work.
I would appreciate some help why it doesn't stop the loop.
public class MainActivity extends Activity {
private Button callBtn;
private Button stopBtn;
Handler handler = new Handler();
Runnable redial=new Runnable(){
#Override public void run(){Intent callIntent=new Intent(Intent.ACTION_CALL,Uri.parse("tel:+49888888"));startActivity(callIntent);
}};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
callBtn = (Button) findViewById(R.id.call);
stopBtn = (Button) findViewById(R.id.stop);
// add PhoneStateListener for monitoring
MyPhoneListener phoneListener = new MyPhoneListener();
TelephonyManager telephonyManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
// receive notifications of telephony state changes
telephonyManager.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
callBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
redial.run();
}
});
stopBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
handler.removeCallbacks(redial);
}
});
}
private class MyPhoneListener extends PhoneStateListener {
private boolean onCall = false;
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// phone ringing...
Toast.makeText(MainActivity.this, incomingNumber + " calls you",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// one call exists that is dialing, active, or on hold
Toast.makeText(MainActivity.this, "on call...",
Toast.LENGTH_LONG).show();
//because user answers the incoming call
onCall = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
// in initialization of the class and at the end of phone call
// detect flag from CALL_STATE_OFFHOOK
if (onCall == true) {
Toast.makeText(MainActivity.this, "restart app after call",
Toast.LENGTH_LONG).show();
// restart our application
Intent restart = getBaseContext().getPackageManager().
getLaunchIntentForPackage(getBaseContext().getPackageName());
restart.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(restart);
onCall = false;
handler.postDelayed(redial, 5000);
}
break;
default:
break;
}
}
}
Related
I'm beginner in android dev and i'm creating a pizza clicker game, just like cookie clicker. I created an activity for upgrades and for upgrading you need some amount of pizza like if you have 10 pizzas you can upgrade. If the amount of pizzas is equals the price the button is enabled, if not, the button is not enabled. When I click the button, the amount of pizza is decreased and the button should disable again, but it's not disabling.
Here's the first activity:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
public static int pizza = 0;
public static TextView pizzaContText, helpers;
public static Button add, upgrades, exit;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initialize();
}
private void initialize() {
add = (Button) findViewById(R.id.makePizza);
exit = (Button) findViewById(R.id.exitButton);
upgrades = (Button) findViewById(R.id.upgrades);
pizzaContText = (TextView) findViewById(R.id.pizzas);
helpers = (TextView) findViewById(R.id.helpers);
pizzaContText.setText("Pizzas: " + pizza);
pizzaContText.setTextColor(Color.BLACK);
pizzaContText.setTextSize(40);
helpers.setText("Helpers: " + Upgrades.contHelper);
helpers.setTextSize(20);
helpers.setTextColor(Color.BLACK);
add.setOnClickListener(this);
upgrades.setOnClickListener(this);
exit.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.makePizza:
pizza++;
pizzaContText.setText("Pizzas: " + pizza);
pizzaContText.setTextColor(Color.BLACK);
pizzaContText.setTextSize(40);
break;
case R.id.upgrades:
Intent i = new Intent(getApplicationContext(), Upgrades.class);
startActivity(i);
break;
case R.id.exitButton:
finish();
System.exit(0);
break;
}
}
}
And here's the second activity (the upgrades):
public class Upgrades extends AppCompatActivity implements View.OnClickListener{
public static int contHelper = 0, priceHelper = 10;
Button addHelper, back;
Handler h = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upgrades);
initialize();
if (MainActivity.pizza >= priceHelper){
//ENABLES THE BUTTON
addHelper.setEnabled(true);
} else{
//DISABLE THE BUTTON
addHelper.setEnabled(false);
}
}
private void initialize() {
addHelper = (Button) findViewById(R.id.addHelper);
addHelper.setText("Helper: " + priceHelper + " pizzas");
back = (Button) findViewById(R.id.back);
addHelper.setOnClickListener(this);
back.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.addHelper:
MainActivity.pizza-=priceHelper;
addHelper.setText("Helper: " + priceHelper + " pizzas");
priceHelper+=4;
contHelper++;
//Auto clicks the make pizza button every 1 sec
final Runnable r = new Runnable() {
#Override
public void run() {
MainActivity.add.performClick();
h.postDelayed(this, 1000);
}
};
h.postDelayed(r, 1000);
break;
case R.id.back:
Intent i = new Intent(getApplicationContext(), MainActivity.class);
startActivity(i);
break;
}
}
}
Don't use static objects.. Is the worst thing you could do.. Use bundle to send your variable
Intent activity = new Intent(this, Upgrades.class);
activity.putExtra("pizza", pizza);
startActivity(intent);
And in your Upgrades activity use
Bundle extras = getIntent().getExtras();
int pizza = extras.getInt("pizza");
And check for nulls and that you send the correct things.
I am creating a BLE app that needs to continuously start and stop scanning for predefined intervals. The way I have implemented it is with two runnables that call each other as follows:
private Runnable scan = new Runnable() {
#Override
public void run() {
scanHandler.postDelayed(stopScan, SCAN_PERIOD);
mLEScanner.startScan(filters, settings, mScanCallback);
Log.e("BLE_Scanner", "Start Scan");
}
};
private Runnable stopScan = new Runnable() {
#Override
public void run() {
mLEScanner.stopScan(mScanCallback);
scanHandler.postDelayed(scan, STOP_PERIOD);
Log.e("BLE_Scanner", "Stop Scan");
}
};
I am attempting to start the continuous scan and pause on a button click. The start button starts the process fine but I am having trouble with stopping the scanning.
//scan button functionality
scanButton=(Button)findViewById(R.id.scan_button);
scanButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinner.setVisibility(View.VISIBLE);
scan.run();
}
});
//stop scan button functionality
stopButton=(Button)findViewById(R.id.stop_button);
stopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinner.setVisibility(View.INVISIBLE);
scanHandler.removeCallbacks(scan);
scanHandler.removeCallbacks(stopScan);
}
});
If I press the stop button during the stop interval the scan will stop. However, if I press the stop button while the scan runnable is running it appears to remove the callbacks for the stopScan runnable while leaving the scan runnable continuously running. What I need is for both of the runnables to stop on the button press. To provide more detail, my entire code is provided below. Thanks for the help.
public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter;
private int REQUEST_ENABLE_BT = 1;
private static final long SCAN_PERIOD = 5000;
private static final long STOP_PERIOD = 1000;
private BluetoothLeScanner mLEScanner;
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothGatt mGatt;
private Button scanButton;
private Button stopButton;
//private String proximityUUID = "0000180f-0000-1000-8000-00805f9b34fb";
private ProgressBar spinner;
private Handler scanHandler;
private String[] filterList = {
"D9:ED:5F:FA:0E:02",
"FF:37:3A:25:56:C7",
"F4:57:89:69:93:91"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scanHandler = new Handler();
//determine if device supports BLE
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE Not Supported",
Toast.LENGTH_SHORT).show();
finish();
}
//set up bluetooth manager
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//scan progress bar
spinner=(ProgressBar)findViewById(R.id.progressBar);
spinner.setVisibility(View.GONE);
//scan button functionality
scanButton=(Button)findViewById(R.id.scan_button);
scanButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinner.setVisibility(View.VISIBLE);
scan.run();
}
});
//stop scan button functionality
stopButton=(Button)findViewById(R.id.stop_button);
stopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinner.setVisibility(View.INVISIBLE);
scanHandler.removeCallbacks(scan);
scanHandler.removeCallbacks(stopScan);
}
});
}
#Override
protected void onResume() {
super.onResume();
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
//scan settings
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
//scan filter
//populate the filter list
filters = new ArrayList<ScanFilter>();
for (int i=0; i< filterList.length ; i++) {
ScanFilter filter = new ScanFilter.Builder().setDeviceAddress(filterList[i]).build();
filters.add(filter);
}
}
}
#Override
protected void onPause() {
super.onPause();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
}
}
#Override
protected void onDestroy() {
if (mGatt == null) {
return;
}
mGatt.close();
mGatt = null;
super.onDestroy();
}
//start scan
private Runnable scan = new Runnable() {
#Override
public void run() {
scanHandler.postDelayed(stopScan, SCAN_PERIOD);
mLEScanner.startScan(filters, settings, mScanCallback);
Log.e("BLE_Scanner", "Start Scan");
}
};
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.i("callbackType", String.valueOf(callbackType));
Log.i("result", result.toString());
BluetoothDevice device = result.getDevice();
int mRSSI = result.getRssi();
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
#Override
public void onScanFailed(int errorCode) {
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
//stop scan
private Runnable stopScan = new Runnable() {
#Override
public void run() {
mLEScanner.stopScan(mScanCallback);
scanHandler.postDelayed(scan, STOP_PERIOD);
Log.e("BLE_Scanner", "Stop Scan");
}
};
private static double calculateAccuracy(int txPower, double rssi) {
if (rssi == 0) {
return -1.0; // if we cannot determine accuracy, return -1.
}
double ratio = -rssi*1.0/txPower;
if (ratio < 1.0) {
return Math.pow(ratio,10);
}
else {
double accuracy = (0.89976)*Math.pow(ratio,7.7095) + 0.111;
return accuracy;
}
}
}
I imagine you just want to call startScan immediately on start button press (not in a Runnable, not scheduled through a Handler). The call is asynchronous, so nothing will block, and Android will do all the scanning in another thread. If you then want to schedule a call to stop in the future, then you use the Handler to post a Runnable that calls stopScan at the delay you need.
The button for stopping the scan can also just directly call stopScan() if know that a scan was previously in progress. You might want to use a boolean to gate the call to stopScan only if there was a previous call to startScan().
So, I ended up finding a way to get it to work as intended. I don't know if the way I'm doing things is best practice as I'm new to Android and Java, but this is what worked for me. All I did was call the stopScan method in the stop button after removing the handler callbacks.
//stop scan button functionality
stopButton=(Button)findViewById(R.id.stop_button);
stopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinner.setVisibility(View.INVISIBLE);
scanHandler.removeCallbacksAndMessages(null);
mLEScanner.stopScan(mScanCallback);
}
});
I'm implementing running the service in background and service will be stop and start click on toggle button.Service is start in 1st activity and stop the service in another activity when click on toggle button.When i run the application service is automatically start in 1st activity which i start in onCreate() method in 1st activity and another activity toggle button status is already on status but when i toggle button is going to off service stop but when i back to 1st activity service is again start.Please can any one help me.Here is my code
public class MyService extends Service
{
private static final String TAG = "MyService";
MediaPlayer player;
private final String StrMyService="myservice";
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
player = MediaPlayer.create(this, R.raw.braincandy);
player.setLooping(false); // Set looping
}
#Override
public void onDestroy() {
Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
player.stop();
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
player.start();
}
}
public class Service_Demo extends Activity implements OnClickListener
{
private static final String TAG = "ServicesDemo";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
System.out.println("In OnCreate(");
startService(new Intent(this, MyService.class));
}
}
public class Toggle_Activity extends Activity
{
ToggleButton tgButton;
private boolean isService=false;
private String strService;
public final String service_Prefs="servicePrefs";
private static final String StrMyService = "zdf";
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.toggle);
final SharedPreferences servicePrefs=this.getSharedPreferences("Service_Prefs",MODE_WORLD_READABLE);
strService=servicePrefs.getString(StrMyService , "myservice");
Log.e("",""+strService);
final boolean mBool = servicePrefs.getBoolean("myservice", true);
Log.e("Boolean Value mBool","="+mBool);
Boolean b = mBool;
Log.e("Update pref", b.toString());
tgButton = (ToggleButton)findViewById(R.id.toggleButton);
tgButton.setChecked(mBool);
final boolean mBool1 = servicePrefs.getBoolean("myservice", false);
final Boolean c = mBool1;
Log.e("Update pref", c.toString());
tgButton=(ToggleButton)findViewById(R.id.toggleButton);
tgButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
// TODO Auto-generated method stub
if(tgButton.isChecked())
{
startService(new Intent(Toggle_Activity.this , MyService.class));
System.out.println("Service is started in togglr button");
}
else
{
stopService(new Intent(Toggle_Activity.this,MyService.class));
System.out.println("Service is stopped in togglr button");
}
}
});
}
}
in the first activity, you'd put startService(new Intent(this, MyService.class)) in onresume
from oncreate
I figured this out the best way possible. I basically linked my toggle button and my service together using a shared preference and listeners. I called this shared preference "service_running" and then implemented my listeners in the activity onCreate() method the toggle button is present in (in this case, MainActivity.
In my onCreate() heres what I did:
// set toggle button based on service running
final ToggleButton toggle = (ToggleButton)findViewById(R.id.toggleButton);
toggle.setChecked(serviceRunning(SendService.class));
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged (CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
startSendService();
}
else {
stopSendService();
}
}
});
// set shared pref listener for toggle
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.OnSharedPreferenceChangeListener myPrefListner = new SharedPreferences.OnSharedPreferenceChangeListener(){
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("service_running")) {
toggle.setChecked(prefs.getBoolean("service_running", false));
}
}
};
prefs.registerOnSharedPreferenceChangeListener(myPrefListner);
startSendService() and stopSendService() simply start or stop my service depending on if it is running and has the correct app permissions or not.
Heres the method which checks if a service is running (credit to #geekQ in this thread):
private boolean serviceRunning (Class<?> serviceClass) {
// check if a service class is currently running
ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
And then in my service, in the onStartCommand() I just changed the shared preference to true, and in the onDestroy() I changed it to false.
The only caveat with this is that you have to hide this shared preference from your preference screen, which can be done with:
getPreferenceScreen().removePreference(findPreference("service_running"));
I have a class that implements two interfaces : OnClickListener and Runnable
When the user presses a button I will go in a Switch like this:
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
pd = ProgressDialog.show(this, "Please Wait",
"Generating", false);
Thread t = new Thread(this);
t.start();
break;
}
}
This should start my Run-method, which has an else-statement like this:
else {
Message msg = handler.obtainMessage();
msg.obj = "1";
handler.sendMessage(msg);
}
And my handler method:
private Handler handler = new Handler() {
#SuppressWarnings("unchecked")
#Override
public void handleMessage(Message m) {
pd.dismiss();
if(m.toString().equals("1")) {
Toast.makeText(getApplicationContext(), "Do a scan first", Toast.LENGTH_SHORT).show();
}
}
};
The code runs without any exception, but the Toast is not showed, it should be! I am sure that people will say that I should use an AsyncTask for this, but thats not the answer that I am looking for.
What am I doing wrong here?
You have to retrive the object inside the message:
private Handler handler = new Handler() {
#SuppressWarnings("unchecked")
#Override
public void handleMessage(Message m) {
pd.dismiss();
String message = (String)m.object;
if(message.equals("1")) {
Toast.makeText(getApplicationContext(), "Do a scan first", Toast.LENGTH_SHORT).show();
}
}
};
Is there a way I can stop a toast message programmatically?
Say I have a button which I click to scroll through toast messages, and in the onclick event I wanted to stop all in the queue and just show the new one, how would I do that?
A simplified version of my code is below -
Code:
public class Help extends Activity{
LinearLayout background;
int screenNo = 1;
Toast toast;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.help);
background = (LinearLayout) findViewById(R.id.helpLayout);
ImageButton next = (ImageButton) findViewById(R.id.imageButtonNext);
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
toast.cancel();
showNextScreen();
}});
}
private void showMessageBox(String title, String msg) {
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setTitle(title);
b.setMessage(msg);
b.setPositiveButton("Next", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
showNextScreen();
}});
b.setNegativeButton("Quit Help", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
returnHome();
}});
b.show();
}
private void showNextScreen() {
int time = 7000;
String tstMsg = "error";
switch (screenNo) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
toast.cancel();
returnHome();
break;
default:
break;
}
if(screenNo < 5)
{
toast=Toast.makeText(this, tstMsg, time);
toast.setGravity(Gravity.BOTTOM, 0, 0);
toast.show();
screenNo++;
}
}
}
This is how i achieved this one.
public static Toast toastShow;
public void showToast(Activity actRef, String message) {
if (toastShow == null
|| toastShow.getView().getWindowVisibility() != View.VISIBLE) {
toastShow = Toast.makeText(actRef, message, Toast.LENGTH_SHORT);
toastShow.setGravity(Gravity.CENTER, 0, 0);
toastShow.show();
}
}
define above code in separate class and instantiate that class where you want show message,you are done with it.
Create a custom global object
private Toast toast;
Initialize it in onCreate
toast = Toast.makeText(YOUR_CLASS_NAME.this, "", Toast.LENGTH_SHORT);
Whenever you need to show a Toast
toast.setText("Hi....");
toast.show();
To kill all the message based on requirement onPause or onDestroy
toast.cancel();
You're all free to cancel the Toast object.