当我将应用程序适配Android Oreo时,渲染动画时CPU使用率会提高10%〜20%。但是,在Android 8.0(例如7.1.1、7.0和6.0)之前,渲染动画时该应用的CPU使用率约为0.3%。
我将此行添加到清单的应用程序标记中
<application android:hardwareAccelerated="true" ...>
但是它并没有任何改善。
请给我一些如何解决此问题的建议。
public class AnimView extends FrameLayout {
private static final String TAG = "AnimView";
private TextView mCenterText;
private TextView mCenterUnit;
private Context mContext;
private long totalSize = 0;
private long totalCount = 0;
private View mRoot;
private OnAnimListener mOnAnimListener;
public AnimView(Context context) {
this(context, null);
}
public AnimView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public void setOnAnimListener(OnAnimListener listener) {
mOnAnimListener = listener;
}
private void initView(Context context) {
mContext = context;
inflate(mContext, R.layout.anim, this);
mRoot = findViewById(R.id.anim_layout);
mCenterText = (TextView) findViewById(R.id.anim_text);
mCenterText.setTypeface(UIUtil.getHelveticaNeueLTProFonts(mContext));
mCenterUnit = (TextView) findViewById(R.id.anim_text_unit);
}
public void setTotalSize(long size, long count) {
totalSize = size;
totalCount = count;
}
public void setAnimBackgroundColor(int color) {
mRoot.setBackgroundColor(color);
}
public void startAnim(final OuterSpaceView pointView) {
long value;
if (totalSize > 0) {
value = totalSize;
} else {
value = totalCount;
}
final ValueAnimator animator = ValueAnimator.ofFloat(value, 0);
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float v = (Float) animation.getAnimatedValue();
setCenterSize(v.longValue());
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if(totalSize > 0) {
setCenterText("0.0");
}else {
setCenterText("0");
}
mCenterText.requestLayout();
pointView.setVisibility(View.GONE);
if (mOnAnimListener != null) {
mOnAnimListener.onAnimFinish();
}
animator.cancel();
}
});
mCenterText.post(new Runnable() {
@Override
public void run() {
animator.start();
}
});
}
private void setCenterSize(long size) {
if(totalSize > 0) {
if (size == 0) {
setCenterText("0.0");
setCenterUnit("B");
} else {
String[] formatSizeSource = CommonUtils.getFormatSizeSource(size);
setCenterText(formatSizeSource[0]);
setCenterUnit(formatSizeSource[1]);
}
}else {
setCenterText(String.valueOf(size));
setCenterUnit(getResources().getString(R.string.sysclear_unit_kuan));
}
if (mOnAnimListener != null) {
mOnAnimListener.onCenterSize(size);
}
}
private void setCenterText(CharSequence text) {
mCenterText.setText(text);
mCenterText.setContentDescription(text);
}
private void setCenterUnit(CharSequence text) {
mCenterUnit.setText(text);
mCenterUnit.setContentDescription(text);
}
public static interface OnAnimListener {
void onAnimFinish();
void onCenterSize(long size);
}
}
和pointView代码:
interface Ball {
int getQuadrant();
Point getPosition();
int getDistance();
double getPercentage();
int getRadius();
int getAlpha();
void next();
boolean isFinished();
}
public class OuterSpaceView extends View {
public static final String TAG = "OuterSpaceView";
private static final int MIN_BALL_COUNT = 4;
private static final int MAX_BALL_COUNT = 9;
List<Ball> mBallList = new ArrayList<Ball>();
private boolean mInit = false;
private int mWidth;
private int mHeight;
private Point mCenter = new Point();
private boolean mInOrOut = true;
private int[] mBallDistribution = new int[5];
private long mLastAddBallTime = 0;
public OuterSpaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!mInit) {
mInit = true;
mWidth = getWidth();
mHeight = getHeight();
mCenter.x = getWidth() / 2;
mCenter.y = getHeight() / 2;
mBallDistribution[0] = Integer.MAX_VALUE;
Arrays.fill(mBallDistribution, 1, mBallDistribution.length, 0);
int maxDistance = (int) Math.sqrt(Math.pow(mWidth, 2) + Math.pow(mHeight, 2));
FlyBallBase.setMaxDistance(maxDistance);
}
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
for (Ball ball : mBallList) {
int x = ball.getPosition().x;
int y = ball.getPosition().y;
int r = ball.getRadius();
int alpha = ball.getAlpha();
paint.setAlpha(alpha);
canvas.drawCircle(x, y, r, paint);
}
next();
invalidate();
}
private void next() {
int needNewBall = calculateNeedBall();
for (int i = 0; i < needNewBall; i++) {
addNewBall();
}
for (Ball ball : mBallList) {
ball.next();
}
removeFinishedBall();
}
public void setFlyDirection(boolean inOrOut) {
mInOrOut = inOrOut;
}
public void clear() {
mBallDistribution[0] = Integer.MAX_VALUE;
Arrays.fill(mBallDistribution, 1, mBallDistribution.length, 0);
mBallList.clear();
}
boolean mUnTouchable;
public void setUnTouchable(boolean value){
mUnTouchable = value;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mUnTouchable;
}
private Map<String, Integer> generateRandomPos() {
int minCount = Integer.MAX_VALUE;
int distributionIndex = 0;
for (int i = 0; i < mBallDistribution.length; i++) {
if (mBallDistribution[i] < minCount) {
minCount = mBallDistribution[i];
distributionIndex = i;
}
}
boolean horizonOrVertical = Math.random() > 0.5;
int x = 0;
int y = 0;
switch (distributionIndex) {
case 1:
if (horizonOrVertical) {
x = mWidth / 2 + (int) (mWidth * Math.random());
y = -mHeight / 2 + (int) (mHeight / 2 * Math.random());
} else {
x = mWidth + (int) (mWidth / 2 * Math.random());
y = -mHeight / 2 + (int) (mHeight * Math.random());
}
break;
case 2:
if (horizonOrVertical) {
x = -mWidth / 2 + (int) (mWidth * Math.random());
y = -mHeight / 2 + (int) (mHeight / 2 * Math.random());
} else {
x = -mWidth / 2 + (int) (mWidth / 2 * Math.random());
y = -mHeight / 2 + (int) (mHeight * Math.random());
}
break;
case 3:
if (horizonOrVertical) {
x = -mWidth / 2 + (int) (mWidth * Math.random());
y = mHeight + (int) (mHeight / 2 * Math.random());
} else {
x = -mWidth / 2 + (int) (mWidth / 2 * Math.random());
y = mHeight / 2 + (int) (mHeight * Math.random());
}
break;
case 4:
if (horizonOrVertical) {
x = mWidth / 2 + (int) (mWidth * Math.random());
y = mHeight + (int) (mHeight / 2 * Math.random());
} else {
x = mWidth + (int) (mWidth / 2 * Math.random());
y = mHeight / 2 + (int) (mHeight * Math.random());
}
break;
default:
break;
}
HashMap<String, Integer> xy = new HashMap<String, Integer>(2);
xy.put("x", x);
xy.put("y", y);
return xy;
}
private void addNewBall() {
Map<String, Integer> pos = generateRandomPos();
int x = pos.get("x");
int y = pos.get("y");
Point newPoint = new Point(x, y);
int quadrant = posToQuadrant((newPoint.x + mCenter.x) / 2, (newPoint.y + mCenter.y) / 2);
Ball newBall = null;
if (mInOrOut) {
newBall = new FlyIn(newPoint, mCenter, quadrant);
} else {
newBall = new FlyOut(mCenter, newPoint, quadrant);
}
mBallList.add(newBall);
mBallDistribution[newBall.getQuadrant()]++;
}
private void removeFinishedBall() {
for (int i = 0; i < mBallList.size(); i++) {
Ball ball = mBallList.get(i);
if (ball.isFinished()) {
int x = ball.getPosition().x;
int y = ball.getPosition().y;
mBallDistribution[ball.getQuadrant()]--;
mBallList.remove(i);
}
}
}
private int calculateNeedBall() {
if (mBallList.size() == 0) {
return 1;
}
if (SystemClock.elapsedRealtime() - mLastAddBallTime > 150) {
mLastAddBallTime = SystemClock.elapsedRealtime();
return 1;
}
return 0;
}
/**
* . mWidth
* . / \
* . |------------2--------------------1-----------|
* . | | |
* . / 2 2 2 1 1
* . | | |
* .mHeight |------------3--------------------1-----------|
* . | | |
* . \ 3 3 4 4 4
* . | | |
* . |------------3--------------------4-----------|
*/
private int posToQuadrant(int x, int y) {
if (x > mCenter.x && y <= mCenter.y) {
return 1;
} else if (x <= mCenter.x && y < mCenter.y) {
return 2;
} else if (x < mCenter.x && y >= mCenter.y) {
return 3;
} else if (x >= mCenter.x && y > mCenter.y) {
return 4;
} else {
return 0;
}
}
public void setBallRadius(int min, int max) {
FlyBallBase.setBallRadius(min, max);
}
}
abstract class FlyBallBase implements Ball {
protected static final int MIN_OPACITY = 30;
protected static final int MAX_OPACITY = 130;
protected static int sMinRadius;
protected static int sMaxRadius;
protected static int sMaxDistance;
protected Point from, to;
protected Point pos;
protected int quadrant;
protected int distance;
protected int distanceX, distanceY;
protected int totalDistance;
protected int totalDistanceX, totalDistanceY;
protected double totalDistanceProportion; // `distance` / `totalDistance`
protected double maxDistanceProportion; // `distance` / `sMaxDistance`
protected int frameCount = 0;
public FlyBallBase(Point from, Point to, int quadrant) {
this.from = new Point(from);
this.to = new Point(to);
pos = new Point(from);
this.quadrant = quadrant;
distance = distanceX = distanceY = 0;
totalDistanceX = to.x - from.x;
totalDistanceY = to.y - from.y;
totalDistance = (int) Math.sqrt(Math.pow(totalDistanceX, 2) + Math.pow(totalDistanceY, 2));
totalDistanceProportion = maxDistanceProportion = 0.0;
}
public static void setBallRadius(int min, int max) {
sMinRadius = min;
sMaxRadius = max;
}
public static void setMaxDistance(int maxDistance) {
sMaxDistance = maxDistance;
}
@Override
public int getQuadrant() {
return quadrant;
}
@Override
public Point getPosition() {
return pos;
}
@Override
public int getDistance() {
return distance;
}
@Override
public double getPercentage() {
return totalDistanceProportion;
}
@Override
public void next() {
distanceX = pos.x - from.x;
distanceY = pos.y - from.y;
distance = (int) Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2));
totalDistanceProportion = (double) distance / totalDistance;
maxDistanceProportion = (double) distance / sMaxDistance;
frameCount++;
}
@Override
public boolean isFinished() {
return pos.x == to.x && pos.y == to.y;
}
}
class FlyIn extends FlyBallBase {
public FlyIn(Point from, Point to, int quadrant) {
super(from, to, quadrant);
}
@Override
public int getRadius() {
return sMinRadius + (int) ((sMaxRadius - sMinRadius) * (1.0 - totalDistanceProportion));
}
@Override
public int getAlpha() {
return (int) Math.max(MIN_OPACITY, (MAX_OPACITY * (1.0 - totalDistanceProportion)));
}
@Override
public void next() {
super.next();
if (Math.abs(to.x - pos.x) <= 80 && Math.abs(to.y - pos.y) <= 50) {
pos.x = to.x;
pos.y = to.y;
} else {
double incPercentage = 1.0 - Math.pow(0.95, frameCount);
int incX = (int) (totalDistanceX * incPercentage);
int incY = (int) (totalDistanceY * incPercentage);
pos.x = from.x + incX;
pos.y = from.y + incY;
}
}
}
class FlyOut extends FlyBallBase {
public FlyOut(Point from, Point to, int quadrant) {
super(from, to, quadrant);
}
@Override
public int getRadius() {
// return (int) (sMaxRadius * totalDistanceProportion);
return sMinRadius + (int) ((sMaxRadius - sMinRadius) * totalDistanceProportion);
}
@Override
public int getAlpha() {
return (int) Math.max(MIN_OPACITY, (MAX_OPACITY * (1.0 - totalDistanceProportion)));
// return (int) (MAX_OPACITY * totalDistanceProportion);
}
@Override
public void next() {
super.next();
if (Math.abs(to.x - pos.x) <= 80 && Math.abs(to.y - pos.y) <= 50) {
pos.x = to.x;
pos.y = to.y;
} else {
double incPercentage = 1.0 - Math.pow(0.98, frameCount);
int incX = (int) (totalDistanceX * incPercentage);
int incY = (int) (totalDistanceY * incPercentage);
pos.x = from.x + incX;
pos.y = from.y + incY;
}
}
}
然后,当我将动画刷新率调整为1帧/ 2秒时,我尝试降低CPU使用率,将CPU使用率从5%〜15%降低到0.12%〜4%...因此,Google是否真的使用更多cpu功能在Android Oreo中推广渲染动画?