如何在我的应用中优化秒表以减少使用cpu?
我正在使用mainActivity中的asynctask类运行秒表。 doInBackground()方法递增小时,分钟,秒和厘秒(十分之一秒)的值。 onProgressUpdate()方法负责更新显示hrs,mins,sec,centisec的4个imageView。
问题我的问题是秒表根据android studio(50%用户和30%内核使用率)以及我安装的cpu监控应用程序平均使用大约50%+ cpu使用率该设备(2013 HTC one m7)。默认的Android操作系统秒表仅使用大约10%的CPU使用率。如果我使用textViews而不是图像视图,则cpu使用率下降到一半(小于25%)。但它仍然超过10%,我也想保持使用数字的风格。 无论如何缓存图像会有帮助吗? source
我还考虑过使用XML drawables来代替位图,但是我不知道它的效果如何,或者甚至可以创建数字的xml drawables
借给我你的知识stackoverflow
主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:
答案 0 :(得分:1)
您应该使用CountDownTimer
,而不是通过循环刻录CPU和电池 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();
或者您可以使用每次延迟所需时间的Runnable,比方说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);
}
}
};
开始吧:
mHandler.postDealyed(runnable, 0);
您可以使用固定费率的定时器:
new Timer().scheduleAtFixedRate(new TimerTask(){
@Override
public void run(){
publishProgress();
}
},0,1000);
或者您可以使用ScheduledExecutorService来解决您提到的大多数问题。请参阅here和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);
的优化:
getResources().getIdentifier(...
行移出onProgressUpdate,并在onCreate中仅准备10位数。在java中重用资源总是好的,因为当你经常创建和处理它们时,就像这里一样,你将很快完成你的内存,GC将不得不为你释放一些内存。创建对象,特别是垃圾收集它们都需要相当长的时间。通过仅创建一次并重复使用它们,您可以远离所有这些麻烦。
答案 1 :(得分:-3)
似乎连续将imageViews重置为不同的drawable是一个问题。 getResources().getIdentifier()
函数调用也有助于额外的CPU使用和GarbageCleaner(GC)问题。
我创建了一个可以不断引用的可绘制数组,而不是创建一个图像资源数组。我在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)}
然后我使用imageViews
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]);
}
});
内存和CPU现在都非常好并且正常工作。
我不知道为什么使用setImageResource()快速更改imageViews图像会导致cpu,内存和GC出现问题。