秒表使用drawables而不是文本。如何优化cpu使用?

时间:2016-02-02 06:51:39

标签: android performance android-asynctask imageview

如何在我的应用中优化秒表以减少使用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%,我也想保持使用数字的风格。 image 无论如何缓存图像会有帮助吗? 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

2 个答案:

答案 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来解决您提到的大多数问题。请参阅herehere

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);

的优化:

  • 将4 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出现问题。