I'm working on a watch face and its up and running but when I put it on my 360 it becomes slow to respond to interactions.
I should note that the screen wakes when a notification is received but not when one turns their wrist to look at the time.
Last thing I did was move code out of doWork and into CountDownRunner. Below is my code:
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.text.format.Time;
import android.support.wearable.view.WatchViewStub;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Date;
public class ClockActivity extends Activity {
private TextView mTextView;
private Handler mHandler = new Handler();
private ImageView img;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock);
Runnable runnable = new CountDownRunner();
Thread myThread = new Thread(runnable);
myThread.start();
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
}
});
}
class CountDownRunner implements Runnable{
public void run() {
while(!Thread.currentThread().isInterrupted()){
try {
Date dt = new Date();
int hours = dt.getHours();
int minutes = dt.getMinutes();
int seconds = dt.getSeconds();
String curTime = hours + ":" + minutes + ":" + seconds;
img=(ImageView)findViewById(R.id.hand_second);
RotateAnimation rotateAnimation = new RotateAnimation((seconds-1)*6, seconds*6,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setDuration(1000);
rotateAnimation.setFillAfter(true);
img.startAnimation(rotateAnimation);
runOnUiThread(new Runnable() {
public void run() {
try{
}catch (Exception e) {
}
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}catch(Exception e){
}
}
}
}
}
You should not implement Runnable to change time on your wearable. Use BroadcastReceiver (Intent.ACTION_TIME_TICK, Intent.ACTION_TIMEZONE_CHANGED, Intent.ACTION_TIME_CHANGED) and receive a "tick" when time change (consumes less battery power and CPU).
Moreover, you must managed screen states (screen dim, screen awake, etc.)
Here is a great exemple of Watchface for Android Wear: http://www.binpress.com/tutorial/how-to-create-a-custom-android-wear-watch-face/120
And a last tips, you can manage seconds for your watchface only when your wearable is awake (like postdaleyed but must be killed when your wearable go back to sleep mode).
Related
I have created an android studio project that contains a countdown until Christmas. I use two images to create the background and the outline for the countdown timer. I have made the application look nice and I was wondering if there is any way to set the project as my phone's background and if it is possible how to do it. The code below is how I set the timer and give it its value. Is there anything I need to change to make this possible?
package com.example.holidaycountdown;
import android.app.WallpaperManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private TextView txtTimerDay, txtTimerHour, txtTimerMinute, txtTimerSecond;
private TextView tvEvent;
private Handler handler;
private Runnable runnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtTimerDay = (TextView) findViewById(R.id.txtTimerDay);
txtTimerHour = (TextView) findViewById(R.id.txtTimerHour);
txtTimerMinute = (TextView) findViewById(R.id.txtTimerMinute);
txtTimerSecond = (TextView) findViewById(R.id.txtTimerSecond);
tvEvent = (TextView) findViewById(R.id.tvhappyevent);
countDownStart();
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setWallpaper();
}
});
}
private void setWallpaper() {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.wallpaper);
WallpaperManager manager = WallpaperManager.getInstance(getApplicationContext());
try{
manager.setBitmap(bitmap);
Toast.makeText(this, "Wallpaper set!", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Toast.makeText(this, "Error!", Toast.LENGTH_SHORT).show();
}
}
public void countDownStart() {
handler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
handler.postDelayed(this, 1000);
try {
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd");
// Please here set your event date//YYYY-MM-DD
Date futureDate = dateFormat.parse("2020-12-25");
Date currentDate = new Date();
if (!currentDate.after(futureDate)) {
long diff = futureDate.getTime()
- currentDate.getTime();
long days = diff / (24 * 60 * 60 * 1000);
diff -= days * (24 * 60 * 60 * 1000);
long hours = diff / (60 * 60 * 1000);
diff -= hours * (60 * 60 * 1000);
long minutes = diff / (60 * 1000);
diff -= minutes * (60 * 1000);
long seconds = diff / 1000;
txtTimerDay.setText("" + String.format("%02d", days));
txtTimerHour.setText("" + String.format("%02d", hours));
txtTimerMinute.setText(""
+ String.format("%02d", minutes));
txtTimerSecond.setText(""
+ String.format("%02d", seconds));
} else {
tvEvent.setVisibility(View.VISIBLE);
tvEvent.setText("The event started!");
textViewGone();
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
handler.postDelayed(runnable, 1 * 1000);
}
public void textViewGone() {
findViewById(R.id.LinearLayout10).setVisibility(View.GONE);
findViewById(R.id.LinearLayout11).setVisibility(View.GONE);
findViewById(R.id.LinearLayout12).setVisibility(View.GONE);
findViewById(R.id.LinearLayout13).setVisibility(View.GONE);
findViewById(R.id.textView1).setVisibility(View.GONE);
findViewById(R.id.textView2).setVisibility(View.GONE);
}
}
Seems like you need to create an app widget for your application(App Widgets are miniature application views that can be embedded in other applications (such as the Home screen) and receive periodic updates).
Here is a useful tutorial
Google's tutorial
I want to create a program that mark a place on the google map and every second from when I push the "Start" button the marker would jump a km to a random direction until I push the "Stop" button.
I want the marker to jump, wait a second, jump, wait a second and so on... Until I push the "Stop" button.
When I am using the "while" loop the program stuck even before the showing of the "Stop" button.
But if I don't use the loop it's working good. Can you help me please?
This is my code:
import androidx.annotation.DrawableRes;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.Projection;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import java.util.Random;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private double currLat = 32.671677;
private double currLng = 35.195678;
private Marker _marker;
private boolean _stopBWasNotPressed = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// 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);
}
// Setting the icon instead of the default marker.
private BitmapDescriptor bitmapDescriptorFromVector(Context context, #DrawableRes int vectorDrawableResourceId) {
Drawable background = ContextCompat.getDrawable(context, R.drawable.car_icon);
background.setBounds(0, 0, background.getIntrinsicWidth(), background.getIntrinsicHeight());
Drawable vectorDrawable = ContextCompat.getDrawable(context, vectorDrawableResourceId);
vectorDrawable.setBounds(40, 20, vectorDrawable.getIntrinsicWidth() + 40, vectorDrawable.getIntrinsicHeight() + 20);
Bitmap bitmap = Bitmap.createBitmap(background.getIntrinsicWidth(), background.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
background.draw(canvas);
vectorDrawable.draw(canvas);
return BitmapDescriptorFactory.fromBitmap(bitmap);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Hide the Stop button.
Button stopB = (Button) findViewById(R.id.stopB);
stopB.setVisibility(View.GONE);
// Hide the Reset button.
Button resetB = (Button) findViewById(R.id.resetB);
resetB.setVisibility(View.GONE);
// Add a marker in my home and move the camera.
LatLng home = new LatLng(currLat, currLng);
_marker = mMap.addMarker(new MarkerOptions().position(home).icon(bitmapDescriptorFromVector(this, R.drawable.car_icon)));
mMap.moveCamera(CameraUpdateFactory.newLatLng(home));
// Show the Start button.
Button startB = (Button) findViewById(R.id.startB);
startB.setVisibility(View.VISIBLE);
startB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Hide the Start button.
Button startB = (Button) findViewById(R.id.startB);
startB.setVisibility(View.GONE);
// Show the Stop button.
final Button stopB = (Button) findViewById(R.id.stopB);
stopB.setVisibility(View.VISIBLE);
while (_stopBWasNotPressed) {
// Making the program wait a second until it moving the marker again.
new Handler().postDelayed(new Runnable() {
public void run() {
startMoving();
}
}, 1000); // 1 second.
}
}
});
}
// This func generates a random number to use as a direction.
public int generateRandomDirection(){
final int min = 1;
final int max = 4;
final int random = new Random().nextInt((max - min) + 1) + min;
return random;
}
// This func makes the new location and sends it to the animateMarker func.
public void startMoving(){
int directionNumber = generateRandomDirection();
final LatLng toPos;
switch(directionNumber) {
case 1:
toPos = new LatLng((currLat + 0.01), currLng); // North.
_marker.setPosition(toPos);
break;
case 2:
toPos = new LatLng((currLat - 0.01), currLng); // South.
_marker.setPosition(toPos);
break;
case 3:
toPos = new LatLng(currLat, (currLng + 0.01)); // East.
_marker.setPosition(toPos);
break;
default:
toPos = new LatLng(currLat, (currLng - 0.01)); // West.
_marker.setPosition(toPos);
break;
}
}
public void stopButtonClick(View view) {
_stopBWasNotPressed = false; // Stops the while loop.
// Hide the Stop button.
Button stopB = (Button) findViewById(R.id.stopB);
stopB.setVisibility(View.GONE);
// Show the Reset button.
final Button resetB = (Button) findViewById(R.id.resetB);
resetB.setVisibility(View.VISIBLE);
resetB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
_marker.setVisible(false);
currLat = 32.671677;
currLng = 35.195678;
onMapReady(mMap);
}
});
}
}
I searched a bit and I found that I can't use the while loop and the delay function together so I changed it to this:
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
while (_stopBWasNotPressed) {
try {
Thread.sleep(1000); // Making the program wait a second until it continues.
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
startMoving();
}
});
}
}
};
Thread myThread = new Thread(runnable); // Creating a thread for the marker movement.
myThread.start();
I am a bit of a keen novice at Android! I have a snippet of code for timer I want to use in my app however it works when the button is clicked and I want it to work when I open the activity that it is on. I have tried so many solutions but cannot get it to operate. Would really appreciate any help, I have tried putting an if statement in, I have tried using the onStart, and putting it the OnCreate all with no joy. The closest I can get is that it just starts with "Time Up!" in the field.
import android.app.Activity;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity
{
Button buttonStartTime;
TextView textViewShowTime;
CountDownTimer countDownTimer;
long totalTimeCountInMilliseconds;
long timeBlinkInMilliseconds;
boolean blink;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getReferenceOfViews ();
setActionListeners ();
totalTimeCountInMilliseconds = 60 * 1000;
timeBlinkInMilliseconds = 30 * 1000;
}
private void setActionListeners() {
buttonStartTime.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
textViewShowTime.setTextAppearance(getApplicationContext(), R.style.normalText);
countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
#Override
public void onTick(long leftTimeInMilliseconds) {
long seconds = leftTimeInMilliseconds / 1000;
if ( leftTimeInMilliseconds < timeBlinkInMilliseconds ) {
textViewShowTime.setTextAppearance(getApplicationContext(), R.style.blinkText);
if ( blink ) {
textViewShowTime.setVisibility(View.VISIBLE);
} else {
textViewShowTime.setVisibility(View.INVISIBLE);
}
blink = !blink;
}
textViewShowTime.setText(String.format("%02d", seconds / 60) + ":" + String.format("%02d", seconds % 60));
}
#Override
public void onFinish()
textViewShowTime.setText("Time up!");
textViewShowTime.setVisibility(View.VISIBLE);
}
}.start();
}
}
);
}
private void getReferenceOfViews() {
buttonStartTime = (Button) findViewById(R.id.btnStartTime);
textViewShowTime = (TextView) findViewById(R.id.tvTimeCount);
}
}
You can modify your onResume() as :
#Override
public void onResume(){
buttonStartTime.performClick();
super.onResume();
}
You should make buttonStartTime a global variable for the class.
I'm trying display a timer on my app with a Thread calculating the elapsed time and a Handler to modify the view.
I know that Android doesn't allow other threads that the UI Thread to modify a view, so I use the Handler to do this.
But it seems that it was not effective, because I still have the "android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
What should I do ?
(Oh, and the code is bellow if this might help)
package com.hangin.arround.emergency;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockActivity;
public class MainActivity extends SherlockActivity {
private static final String TAG = "MainActivity";
private TextView elapsedTime;
private Button startButton;
private Button stopButton;
private boolean shouldContinue = false;
private Handler mHandler;
private Runnable runnable;
private static final int MESSAGE_ELAPSED_TIME = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Creating the action bar, initializing my views and stuff
// Creating the Handler
mHandler = new Handler() {
#SuppressLint("SimpleDateFormat")
#Override
public void handleMessage(Message msg){
super.handleMessage(msg);
switch(msg.what) {
case MESSAGE_ELAPSED_TIME :
// Converting from milliseconds to a String
DateFormat formatter = new SimpleDateFormat("hh:mm:ss.SSS");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(msg.arg1);
String elapsedTimeString = formatter.format(calendar.getTime());
elapsedTime.setText(elapsedTimeString);
break;
default:
break;
}
}
};
// Creating the Runnable
runnable = new Runnable(){
#Override
public void run() {
int startTime, actualTime;
startTime = (int) System.currentTimeMillis();
Log.d(TAG, "startTime = " + startTime);
while(shouldContinue) {
// Calcul du temps écoulé
actualTime = (int)System.currentTimeMillis() - startTime;
Log.d(TAG, "actualTime = " + actualTime);
// Creating the message sent to the Handler
Message elapsedTimeMessage = new Message();
elapsedTimeMessage.what = MESSAGE_ELAPSED_TIME;
elapsedTimeMessage.arg1 = (int) actualTime;
// Sending the message
mHandler.handleMessage(elapsedTimeMessage);
}
}
};
// Adding the OnClickListeners on startButton and stopButton
startButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
// Launching Thread
(new Thread(runnable)).start();
shouldContinue = true;
}
});
stopButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
// Stopping the thread
shouldContinue = false;
}
});
}
}
Change
Message elapsedTimeMessage = new Message();
elapsedTimeMessage.what = MESSAGE_ELAPSED_TIME;
elapsedTimeMessage.arg1 = (int) actualTime;
// Sending the message
mHandler.handleMessage(elapsedTimeMessage);
to
Message.obtain(mHandler, MESSAGE_ELAPSED_TIME, (int) actualTime, 0).sendToTarget();
From the API docs, it seems handleMessage is something called later in the handling process and shouldn't be invoked directly.
In order to have the message processed on the thread where the handler was created, you need to call sendMessage
You should change mHandler.handleMessage(elapsedTimeMessage);
with mHandler.sendMessage(elapsedTimeMessage);
When press button first sound active. Then press that button again it will stop and second sound active My code is OK?
package com.Randomsentence;
import java.util.Random;
import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class Randomsentence extends Activity {
boolean showRandom = false;
TextView txt;
int time = 30;
int random;
public String[] myString;
Button bt1;
boolean check = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txt=(TextView)findViewById(R.id.txt);
bt1 = (Button)findViewById(R.id.bt1);
Medaiplayer mp = new Medaiplayer();
Mediaplayer mp2 = new Mediaplayer();
bt1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
showRandom = !showRandom;
t = new Thread() {
public void run() {
try {
while(showRandom){
mp = MediaPlayer.create(getApplicationContext(), R.raw.AudioFile1);
mp.setLooping(true);
mp.start();
mp2.reset();
mp2.prepare();
sleep(1000);
handler.sendMessage(handler.obtainMessage());
}
mp.reset();
mp.prepare();
mp2 = MediaPlayer.create(getApplicationContext(), R.raw.AudioFile2);
mp2.setLooping(true);
mp2.start();
}catch(Exception ex){
ex.printStackTrace();
}
}
};
t.start();
}
});
}
// our handler
Handler handler = new Handler() {
public void handleMessage(Message msg) {//display each item in a single line
{
Random rgenerator = new Random();
Resources res = getResources();
myString = res.getStringArray(R.array.myArray);
String q = myString[rgenerator.nextInt(myString.length)];
txt.setText(q);
}
}
};
}
Add the line:
mp.setLooping(true);
Then set false when you want to stop it looping.
Your code has several errors. Typos, cases,
ex.: Medaiplayer should be MediaPlayer
This alone would be enough to cause the error. Also, declaring your variables outside the method is a good idea.