TLDR; Run a method that updates the UI on a dedicated thread from a OnCallBack function that is updated every few milliseconds!!
I'm getting a live stream video using Vitamio library and displaying it on a SurfaceView This is done by the MediaPlayer of the library.
However, I need to split the screen for VR experience. If MediaPlayer had a method to display the video on 2 SurfaceViews then I would not have had such a problem. Unfortunately, it doesn't.
Therefore, I figured that the live stream video runs on the SurfaceView in first half of the screen and I display each frame image Bitmap to an ImageView which occupies the second half of the screen.
This is working but not good... The problem is that copying the image is too much work and that's why the ImageView is laggy.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="#+id/surfaceview_livestream"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginBottom="#dimen/activity_vertical_margin"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_weight="1" />
<ImageView
android:id="#+id/imageview_livestream"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginBottom="#dimen/activity_vertical_margin"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_weight="1"
android:contentDescription="#string/live_stream" />
</LinearLayout>
public class LiveStreamManager implements MediaPlayer.OnBufferingUpdate {
// some irrelevant code
public void initLiveStream() {
io.vov.vitamio.MediaPlayer mediaPlayer = new io.vov.vitamio.MediaPlayer();
mediaPlayer.setDisplay(mainActivity.getSurfaceView());
// other irrelevant code...
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
Bitmap frame = mp.getCurrentFrame();
if (frame != null) {
mainActivity.setFrame(frame);
}
}
}
public MainActivity extends Activity {
// some code...
// I want this to run on a dedicated thread
public void setFrame(Bitmap frame) {
imageviewLiveStream.setImageBitmap(frame);
}
}
try using rxJava:
Observable.interval(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.handlerThread())
.map(t -> {
// do rendering here (on single render thread
return 'rendered images'
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe( t -> {
// set bitmaps here
});
Rendering will be one on separate thread (create scheduler in advance ) every 10 milliseconds, then results will be processed on main thread.
I am very new to Android SDK so that question may be very simple.
I try to make am app that shows the current time. I know how to get the current time but i somehow need to update the time. So i try putting a while/if statement that updates the time outside onCreate() and inside main Activity class but 4 errors pop up saying "unexpected end of Decleration.
I cant really find a way to solve this so any help would be much appreciated.
I get the idea that a longer example will be more useful for you.
Make a layout for the application, call the file activity_main.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.timedemo.MainActivity">
<TextView
android:id="#+id/textClock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignTop="#+id/textView" />
</LinearLayout>
Make a file called MainActivity.java, make it extends Activity (or something else that extends Activity)
Init your layout in the onCreate method.
Use a handler to run code at a delayed time, instead of halting the thread.
public class MainActivity extends AppCompatActivity {
//Handler can be used to send Runnables (code to run) to a specific Thread.
//In this case the UI-thread.
Handler handler = new Handler();
//TextView variable defined in Class-scope.
TextView myTextClock;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Load the layout from activity_main.xml into this Activity.
setContentView(R.layout.activity_main);
//Find the textclock that is mentioned in the activity_main.xml
//Use the ID to find the right View.
//As you can see in the xml-file, the id is 'textClock'.
//Looks like this in the XML --> <TextView android:id="#+id/textClock" />
myTextClock = (TextView) this.findViewById(R.id.textClock);
//Tell the Handler to execute this code at an interval.
handler.postDelayed(codeToRun, 1000);
}
//The runnable contains the code that will be run every second.
Runnable codeToRun = new Runnable() {
#Override
public void run() {
updateTime();
}
};
public void updateTime(){
//Code to update the Clock on the UI-thread
//see: http://developer.android.com/reference/java/text/SimpleDateFormat.html
DateFormat sdf = DateFormat.getDateTimeInstance();
myTextClock.setText(sdf.format(new Date()));
//Make sure it runs the next time too.
handler.postDelayed(codeToRun, 1000);
}
}
Hope this helps you get on the right path.
I'd suggest you use ScheduledThreadPoolExecutor class instead of a while loop. There is an example in this tutorial on how to create a clock app. It can be useful as a starting point.
class ClockTask implements Runnable {
#Override
public void run() {
updateClock();
}
}
ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
se.scheduleAtFixedRate(new ClockTask(), 0, 1000, TimeUnit.MICROSECONDS);
I'm not sure how you plan to make this, but keep in mind that you do not stall the Main Thread. So avoid a construction like this:
while(true){ Thread.sleep(1000); updateTime(); }
A better approach would to use Handler, for example:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
updateTime();
}
}, 1000);
http://developer.android.com/reference/android/os/Handler.html#postDelayed(java.lang.Runnable,%20long)
Hope this helps ;-)
How can i optimize my stopwatch in my app to use less cpu?
I am running a stopwatch using an asynctask class in the mainActivity. The doInBackground() method increments the values for the hours, minutes, seconds and centiseconds(10th of a second). The onProgressUpdate() method is responsible for updating 4 imageViews that display the hrs, mins, sec, centisec.
The problem i have is that the stopwatch uses about on average 50%+ cpu usage according to android studio(50% user and 30% kernel usage) and a cpu monitoring app that i installed on the device (2013 HTC one m7). The default android operating system stopwatch uses only about 10% cpu usage. If i use textViews instead of image views the cpu usage drop to half (less than 25%). But it is still more than 10% and i also i want to keep the style of digits im using.
Would caching the images help in anyway? source
I have also considered using XML drawables for the digits instead of bitmaps, but i don't know how effective this will be or if its even possible to create xml drawables of the digits
Lend me your knowledge stackoverflow
main XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#763768"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.example.aroboius.stopwatch.MainActivity"
tools:showIn="#layout/activity_main">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/hoursImage"
android:layout_marginRight="20dp"
android:src="#drawable/digit00" />
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/minutesImage"
android:layout_marginRight="20dp"
android:src="#drawable/digit00" />
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/secondsImage"
android:layout_marginRight="20dp"
android:src="#drawable/digit00" />
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/centiSecondsImage"
android:src="#drawable/digit00" />
</LinearLayout>
MainActivity
public class MainActivity extends AppCompatActivity {
ImageView hoursIMG, minutesIMG, secondsIMG, centiSecondsIMG;
TextView hoursText, minutesText, secondsText, centicsecondsText;
int centiseconds, seconds, minutes, hours ;
long startMS , endMS , elapsed ;
boolean timerRunning;
String [] digit = {"digit00","digit01","digit02","digit03","digit04","digit05","digit06","digit07","digit08","digit09", "digit10", "digit11","digit12","digit13","digit14","digit15","digit16","digit17","digit18","digit19","digit20", "digit21","digit22","digit23","digit24","digit25","digit26","digit27","digit28","digit29","digit30","digit31",
"digit32","digit33","digit34","digit35","digit36","digit37","digit38","digit39","digit40","digit41","digit42","digit43","digit44","digit45","digit46","digit47","digit48","digit49","digit50","digit51","digit52","digit53",
"digit54","digit55","digit56","digit57","digit58","digit59","digit60","digit61","digit62","digit63","digit64","digit65","digit66","digit67","digit68","digit69","digit70","digit71","digit72","digit73","digit74","digit75",
"digit76","digit77","digit78","digit79","digit80","digit81","digit82","digit83","digit84","digit85","digit86","digit87","digit88","digit89", "digit90","digit91","digit92","digit93","digit94","digit95","digit96","digit97","digit98","digit99"} ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//initializing values
centiseconds = 0; seconds = 0; minutes = 0; hours = 0;
startMS = 0; endMS = 0; elapsed = 0;
hoursIMG = (ImageView) findViewById(R.id.hoursImage);
minutesIMG = (ImageView) findViewById(R.id.minutesImage);
secondsIMG = (ImageView) findViewById(R.id.secondsImage);
centiSecondsIMG = (ImageView) findViewById(R.id.centiSecondsImage);
//start asynctask/stopwatch
timerRunning = true; new asyncTask().execute();
}
class asyncTask extends AsyncTask<Void, Void, Void> {
//initialize a variable to the current system time
#Override
protected void onPreExecute() {
startMS = System.currentTimeMillis();
}
#Override
protected Void doInBackground(Void... params) {
//timerRunning a varible to stop/start the timer
while (timerRunning) {
//initialize a 2nd variable to the current system time
endMS = System.currentTimeMillis();
//get the difference between the 2 time variables
elapsed = endMS - startMS;
//once it is greater than or equal to 100ms increment the centis, mins, secs, hrs
if (elapsed >= 100) {
//reset the starting variable to repeat the process. it also compensating if elapses is greater than 100ms
startMS = endMS - (elapsed - 100);
centiseconds++;
if (centiseconds > 9) {
centiseconds = 0;
seconds++;
if (seconds > 59) {
seconds = 0;
minutes++;
if (minutes > 59) {
minutes = 0;
hours++;
}
}
}
//call method to update the images
publishProgress();
}
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
//get resource IDs for images that represent the values of hrs, mins, secs using the string array created earlier
int hourResID = getResources().getIdentifier(digit[hours], "drawable", getPackageName());
int minResID= getResources().getIdentifier(digit[minutes], "drawable", getPackageName());
int secResID= getResources().getIdentifier(digit [seconds], "drawable", getPackageName());
int csecResID= getResources().getIdentifier(digit[centiseconds], "drawable", getPackageName());
//set images of imageViews
centiSecondsIMG.setImageResource(csecResID);
secondsIMG.setImageResource(secResID);
minutesIMG.setImageResource(minResID);
hoursIMG.setImageResource(hourResID);
}
}
}
1:
Instead of burning your CPU and battery with a loop, you should use a CountDownTimer
new CountDownTimer(30000, 1000) { // 30sec, tick each second
public void onTick(long millisUntilFinished) {
publishProgress();
// mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
Or you can use a Runnable that you delay every time by the desired amount of time, let's say 200ms:
final static long REFRESH_RATE = 200L;
Handler mHandler = new Handler();
private final Runnable mRunnable = new Runnable() {
#Override
public void run() {
if (mStarted) {
long seconds = (System.currentTimeMillis() - t) / 1000;
statusBar.setText(String.format("%02d:%02d", seconds / 60, seconds % 60));
// cancel previous messages if they exist
handler.removeCallbacks(mRunnable);
handler.postDelayed(runnable, REFRESH_RATE);
}
}
};
start it:
mHandler.postDealyed(runnable, 0);
You can use a Timer with fixed rate:
new Timer().scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
publishProgress();
}
},0,1000);
Or you can use a ScheduledExecutorService, that will fix most of the problems you mentioned. See here and here.
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(1);
long lastSecondDisplayed = 0;
ScheduledFuture scheduledFuture =
scheduledExecutorService.schedule(new Callable() {
public Object call() throws Exception {
long now = System.currentTimeMillis() / 1000;
// add this optimisation, so you don't calculate and
// for sure don't refresh your UI (even slower)
// if it's not needed:
if (lastSecondDisplayed != now) {
lastSecondDisplayed = now;
// calculate whatever you want
publishProgress();
}
return "Called!";
}
}, 1, TimeUnit.SECONDS);
Optimisations:
move the 4 getResources().getIdentifier(... lines out of onProgressUpdate and prepare the 10 digits only once in onCreate.
It is always good to reuse resources in java, because when you're creating and disposing them frequently, like here, you'll finish your memory quite fast and the GC will have to free some memory for you. Both creating the objects, and especially garbage-collecting them takes a fair amount of time. By creating them only once and reusing them you keep yourself far from all this trouble.
It seems it was a problem with continuously resetting the imageViews to different drawables. The getResources().getIdentifier() function calls also somewhat contributed to extra cpu usage and GarbageCleaner(GC) problems.
Instead of creating an image resource array I created a drawable array that I can continually reference. I created it in onCreate().
final Drawable[] drawable = {ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit00),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit01),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit02),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit03),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit04),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit05),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit06),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit07),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit08),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit09),
ContextCompat.getDrawable(getApplicationContext(), R.drawable.digit10)}
Then I set the images on the imageViews using the Drawable
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
centiSecondsIMG.setImageDrawable(drawable[centiseconds]);
secondsIMG.setImageDrawable(drawable[seconds]);
minutesIMG.setImageDrawable(drawable[minutes]);
hoursIMG.setImageDrawable(drawable[hours]);
}
});
Memory and cpu are now all perfectly fine and working normally.
i sitll dont know why changing the imageViews images rapidly using setImageResource() caused problems with cpu,memory and GC.
I'm making an application and a certain part in my application I store a list of prices along with the time that the prices last for (they do not all last the same amount of time). So a price lasts a certain time then once that price's time is up it changes to another price (this part changes the UI or basically it updates a textview with the new price). So what I need is a timer that sets the timer again with the new time length and once it's done make the UI change. For instance say that each of the pairs represent the price amount and the time (in seconds): { {$2.53,1.4s}, {$4.57,4.45s}, {$1.23,3.6s}...}
So when the timer starts off the textview displays $2.53 and the timer lasts 1.4s and then it should grab the next price $4.57 and be set again but this time for 4.45s. This process continues on and on until the game is finished. I was thinking of using the CountDownTimer and resetting itself once the onFinish() method is called (I haven't verified if this idea works yet). Are there any other ideas?
You can use a countdown timer and onFinish method you call back the function and it starts another timer:
private void startWheatPrices(long gameTime)
{
//other stuff executed
StartWheatTimer(GameTimeDifference);//starts the timer for the first time
}
private void StartWheatTimer(long TimerAmount)
{
WheatTimer = new CountDownTimer(TimerAmount, 10) {
public void onTick(long millisUntilFinished)
{
}
public void onFinish()
{
//other stuff executed
WheatPricesTV.setText(Float.toString(PriceList.get(0).get(WheatPriceIndex).price));//price is changed
if(InGameplayMode)
StartWheatTimer(convertToMilliseconds(PriceList.get(0).get(WheatPriceIndex).timeLength));//call back the function to start the timer again
}
}.start();
}
i have a simple Application about writing the sentence which is shown when the application starts.The only Problem is, i need the application to calculate the time it took the user to write the sentence .. like when you touch "Submit" Button , the Toast message will say " Thats Right ! , It took you 3.2 Second" As Example .
I heard you can set a timer to start on when specific action occurs ... and you can order it to stop .
So let's say The Timer will start when you start the app and it will stop when you touch "Submit" button , and give a toast message like above calculating the exact time it took you to write the sentience after starting the App ! *
Here is the App Code hope it helps : *
Button w;
TextView t;
EditText e;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
w = (Button) findViewById(R.id.Write);
t= (TextView) findViewById(R.id.FTS);
e = (EditText) findViewById(R.id.Text);
w.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String check1 = t.getText().toString();
String check2 = e.getText().toString();
if (check1.equals(check2))
Toast.makeText(MainActivity.this,"You Wrote it Right !!!",Toast.LENGTH_LONG).show();
else if (check2.equals(""))
Toast.makeText(MainActivity.this,"It's Empty",Toast.LENGTH_LONG).show();
else
Toast.makeText(MainActivity.this,"You wrote it wrong,try again !",Toast.LENGTH_LONG);
I'm Totally new to Android so I really don't know how to do it , Thanks for your Time .*
you can use the Timer class to start a timer session. Follow the steps:
1- define a global variable of the Timer and a variable to count the time like:
private Timer t;
private int TimeCounter = 0;
2- then when the activity starts, so in onCreate add the following: P.S: what I did is I have a textView to show the timing while he is writing the sentence. so if you dont want that you can delete the tvTimer part in the following code
t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() {
public void run() {
tvTimer.setText(String.valueOf(TimeCounter)); // you can set it to a textView to show it to the user to see the time passing while he is writing.
TimeCounter++;
}
});
}
}, 1000, 1000); // 1000 means start from 1 sec, and the second 1000 is do the loop each 1 sec.
then when the button is clicked, stop the timing and show the timeCounter varaible in the Toast.
t.cancel();//stopping the timer when ready to stop.
Toast.makeText(this, "The time taken is "+ String.valueOf(TimeCounter), Toast.LENGTH_LONG).show();
P.S: You have to deal with converting the seconds into minutes because the number could extends to 360 secs so you need to convert it to 6 minutes. you can do it in the t.schedualeAtFixedRate or after you done you can convert it and show it in the toast
hope you found this useful. please give me a feedback if it worked for you.
Let me direct your attention to the Chronometer Widget on the Dev Page
Also here's a flavor of what you will get by using the Chronometer Widget (skip to 8:30)
Video of Chronometer Widget
XML
<Chronometer
android:id="#+id/chronometer1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Java
((Chronometer) findViewById(R.id.chronometer1)).start();
((Chronometer) findViewById(R.id.chronometer1)).stop();