+++++++++++++欢迎讨论和交流++++++++++++++++++++++
引入:
我在公司负责了一个阅读器上的笔记软件,可以供用户签字,画画,涂鸦,以及再次修改画画的功能,在内部可以新增页面和删除页面等众多操作供用户选择。
/*
* Copyright (C) 2007 The Android Open Source Project
* Copyright (C) 2011-2014 Freescale Semiconductor, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.handwriting;
import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.util.Log;
import java.util.Timer;
import java.util.TimerTask;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.Iterator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class HandWriting extends Activity {
private static final int CLEAR_MENU_ID = Menu.FIRST;
private static final int SLOW_MENU_ID = Menu.FIRST + 1;
private static final int FAST_MENU_ID = Menu.FIRST + 2;
private final static String TAG = "HandWriting";
private Paint mPaint;
/** The view responsible for drawing the window. */
MyView mView;
public static void fast_draw_set(boolean on_off) {
try {
FileOutputStream fileOutputStream = new FileOutputStream("/proc/epdc_fb/fast_vsync");
if (on_off == true)
fileOutputStream.write("cinread 1".getBytes());
else
fileOutputStream.write("cinread 0".getBytes());
fileOutputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.w(TAG,"Oncreate ==================");
// Create and attach the view that is responsible for painting.
mView = new MyView(this);
setContentView(mView);
mView.requestFocus();
/* TimerTask task = new TimerTask(){
public void run(){
//execute the task
mView.postInvalidate(mView.EINK_AUTO_MODE_REGIONAL | mView.EINK_WAIT_MODE_WAIT | mView.EINK_WAVEFORM_MODE_AUTO | mView.EINK_UPDATE_MODE_FULL);
//mView.postinvalidate();
}
};
Timer timer = new Timer();
timer.schedule(task, 1000*2); */
}
@Override
public void onResume() {
super.onResume();
fast_draw_set(true); //开启高帧率模式,适合画画,手写
}
@Override
public void onPause() {
super.onPause();
fast_draw_set(false); //关闭高帧率模式
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, CLEAR_MENU_ID, 0, "Clear").setShortcut('3', 'c');
menu.add(0, SLOW_MENU_ID, 0, "Slow").setShortcut('4', 's');
menu.add(0, FAST_MENU_ID, 0, "Fast").setShortcut('5', 'f');
mView.invalidate(mView.EINK_UPDATE_MODE_FULL);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
switch (item.getItemId()) {
case CLEAR_MENU_ID:
mView.clear();
return true;
case FAST_MENU_ID:
mView.setUpdateType(0);
return true;
case SLOW_MENU_ID:
mView.setUpdateType(1);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
mView.onTrackballEvent(event);
return true;
}
/*
@Override
protected void onPause() {
mView.onPause();
super.onPause();
}
@Override
protected void onResume() {
mView.onResume();
super.onResume();
}
*/
public class MyView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private int mLastX, mLastY;
private final Rect mRect = new Rect();
private final Rect mlastRect = new Rect();
boolean mUpdateFlag = false;
boolean mStartFlag = false;
boolean mFirstPointFlag = true;
boolean mNewRegionFlag = true;
private int mCurX;
private int mCurY;
private float mCurSize;
private int mCurWidth;
private TimerTask mTimerTask = null;
private Timer mTimer = null;
private int mWidth;
private int mHight;
private int first = 0;
private int mEvent = 0; //0 touch event; 1 trackball
private int mUpdateType = 0; //0 fast type; 1 slow type;
/** Used as a pulse to gradually fade the contents of the window. */
private static final int UPDATE_MSG = 1;
/** How often to fade the contents of the window (in ms). */
private static final int UPDATE_DELAY = 10;
/*update mode for handwriting in eink*/
private static final int UPDATE_MODE_PARTIAL = EINK_WAIT_MODE_NOWAIT | EINK_WAVEFORM_MODE_ANIM | EINK_UPDATE_MODE_PARTIAL;
private static final int UPDATE_MODE_PARTIAL2 = EINK_WAIT_MODE_NOWAIT | EINK_WAVEFORM_MODE_DU |EINK_UPDATE_MODE_PARTIAL;
// private static final int UPDATE_MODE_PARTIAL = EINK_AUTO_MODE_REGIONAL| EINK_WAIT_MODE_NOWAIT | EINK_WAVEFORM_MODE_DU | EINK_UPDATE_MODE_PARTIAL;
//private static final int UPDATE_MODE_PARTIAL = EINK_WAIT_MODE_NOWAIT | EINK_WAVEFORM_MODE_ANIM;
//private static final int UPDATE_MODE_FULL = EINK_AUTO_MODE_REGIONAL| EINK_WAIT_MODE_WAIT | EINK_WAVEFORM_MODE_AUTO | EINK_UPDATE_MODE_FULL;
private static final int UPDATE_MODE_FULL = EINK_AUTO_MODE_REGIONAL | EINK_WAIT_MODE_WAIT | EINK_WAVEFORM_MODE_AUTO | EINK_UPDATE_MODE_FULL;
public MyView(Context c) {
super(c);
mPaint = new Paint();
mPaint.setAntiAlias(false);
mPaint.setDither(false);
mPaint.setColor(0xff000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(10);
mPath = new Path();
mRect.left = 0;
mRect.top = 0;
mRect.right = 0;
mRect.bottom = 0;
mlastRect.left = 0;
mlastRect.top = 0;
mlastRect.right = 0;
mlastRect.bottom = 0;
mFirstPointFlag = true;
mHight = 0;
mWidth = 0;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
int curW = mBitmap != null ? mBitmap.getWidth() : 0;
int curH = mBitmap != null ? mBitmap.getHeight() : 0;
if (curW >= w && curH >= h) {
return;
}
if (curW < w) curW = w;
if (curH < h) curH = h;
mHight = curH;
mWidth = curW;
Bitmap newBitmap = Bitmap.createBitmap(curW, curH, Bitmap.Config.ARGB_8888);
Canvas newCanvas = new Canvas();
newCanvas.setBitmap(newBitmap);
if (mBitmap != null) {
newCanvas.drawBitmap(mBitmap, 0, 0, null);
}
mBitmap = newBitmap;
mCanvas = newCanvas;
mCanvas.drawColor(0xFFFFFFFF);
}
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
//canvas.drawPath(mPath, mPaint);
canvas.drawBitmap(mBitmap, 0, 0, null);
//canvas.drawPath(mPath, mPaint);
}
public void onPause() {
// Override if necessary
mBitmap.eraseColor(0xFFFFFFFF);
//invalidate(UPDATE_MODE_FULL );
}
public void clear() {
if (mCanvas != null) {
// Log.i(TAG, ("clear() start\n"));
mPath.reset();
mBitmap.eraseColor(0xFFFFFFFF);
invalidate(UPDATE_MODE_FULL );
mUpdateFlag = false;
mRect.left = 0;
mRect.top = 0;
mRect.right = 0;
mRect.bottom = 0;
mlastRect.left = 0;
mlastRect.top = 0;
mlastRect.right = 0;
mlastRect.bottom = 0;
mEvent =0;
mFirstPointFlag = true;
mNewRegionFlag = true;
}
}
public void setUpdateType(int type)
{
switch (type) {
case 0:
mUpdateType = 0;
break;
case 1:
mUpdateType = 1;
break;
default:
mUpdateType = 0;
break;
}
}
public synchronized void update() {
if (mCanvas != null) {
int left = mRect.left ;
int top = mRect.top ;
int right = mRect.right ;
int bottom = mRect.bottom ;
if(left <0) left =0;
if(top <0) top =0;
if(right <0) right =0;
if(bottom <0) bottom =0;
/*
if(mNewRegionFlag == true)
{
if( mEvent == 1 )
{
//Log.i(TAG, ("end update 1\n"));
mUpdateFlag = false;
}
}else
*/
{
// Log.i(TAG, ("left=" + left +" top="+ top +" right="+ right+ " bottom="+ bottom +""));
mCanvas.drawPath(mPath, mPaint);
invalidate(left, top, right, bottom , EINK_WAIT_MODE_NOWAIT | EINK_WAVEFORM_MODE_DU |EINK_UPDATE_MODE_PARTIAL);
mNewRegionFlag = true;
}
}
}
/**
* Start up the pulse to update the screen, clearing any existing pulse to
* ensure that we don't have multiple pulses running at a time.
*/
void startUpdating() {
mStartFlag = true;
mUpdateFlag = true;
mHandler.removeMessages(UPDATE_MSG);
mHandler.sendMessageDelayed(mHandler.obtainMessage(UPDATE_MSG), 0);
}
/**
* Stop the pulse to fade the screen.
*/
void stopUpdating() {
mHandler.removeMessages(UPDATE_MSG);
}
private Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
// Upon receiving the update pulse, we have the view perform a
// update and then enqueue a new message to pulse at the desired
// next time.
case UPDATE_MSG: {
update();
if(mUpdateFlag == false)
{
// Log.i(TAG, ("end update 2\n"));
stopUpdating();
}else
{
mHandler.sendMessageDelayed(mHandler.obtainMessage(UPDATE_MSG),0);
}
break;
}
default:
super.handleMessage(msg);
}
}
};
@Override
public boolean onTouchEvent(MotionEvent event) {
mEvent = 0;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startUpdating();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
mUpdateFlag = false;
break;
}
int N = event.getHistorySize();
//Log.i(TAG, "event.getHistorySize" + N );
for (int i=0; i<N; i++) {
drawPoint(event.`(i),
event.getHistoricalY(i),
event.getHistoricalPressure(i),
event.getHistoricalSize(i));
}
drawPoint(event.getX(), event.getY(),
event.getPressure(), event.getSize());
return true;
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
mEvent = 1;
if(mUpdateFlag == false)
{
Log.i(TAG, ("start update \n"));
startUpdating();
}
int N = event.getHistorySize();
int baseX = mCurX;
int baseY = mCurY;
final float scaleX = event.getXPrecision();
final float scaleY = event.getYPrecision();
for (int i=0; i<N; i++) {
drawPoint(baseX+event.getHistoricalX(i)*scaleX,
baseY+event.getHistoricalY(i)*scaleY,
event.getHistoricalPressure(i),
event.getHistoricalSize(i));
update();
}
drawPoint(baseX+event.getX()*scaleX, baseY+event.getY()*scaleY,
event.getPressure(), event.getSize());
update();
return true;
}
private synchronized void drawPoint(float x, float y, float pressure, float size) {
// Log.i(TAG, ("drawPoint() start \n"));
int oldleft = mRect.left ;
int oldtop = mRect.top ;
int oldright = mRect.right ;
int oldbottom = mRect.bottom ;
int newleft = 0 ;
int newtop = 0 ;
int newright = 0 ;
int newbottom = 0 ;
int targetleft = 0 ;
int targettop = 0 ;
int targetright = 0 ;
int targetbottom = 0 ;
mCurX = (int)x;
mCurY = (int)y;
if(mCurY > mHight) mCurY = mHight;
if(mCurY < 0 ) mCurY = 0;
if(mCurX > mWidth) mCurX = mWidth;
if(mCurX < 0 ) mCurX = 0;
mCurSize = size;
mCurWidth = (int)(mCurSize*(getWidth()/3));
if (mCurWidth < 1) mCurWidth = 1;
if ( mCanvas != null) {
newleft = mCurX-mCurWidth-2;
newtop = mCurY-mCurWidth-2;
newright = mCurX+mCurWidth+2;
newbottom = mCurY+mCurWidth+2;
if(mFirstPointFlag == true)
{
mFirstPointFlag=false;
oldleft = newleft;
oldtop = newtop ;
oldright = newright;
oldbottom = newbottom;
mPath.reset();
mPath.moveTo(mCurX, mCurY);
mNewRegionFlag = false;
}else
{
if(mNewRegionFlag==true)
{
if( mStartFlag== true && mEvent== 0)
{
mStartFlag = false;
oldleft = newleft;
oldtop = newtop ;
oldright = newright;
oldbottom = newbottom;
mPath.reset();
mPath.moveTo(mCurX, mCurY);
}
else
{
oldleft = mlastRect.left;
oldtop = mlastRect.top ;
oldright = mlastRect.right;
oldbottom = mlastRect.bottom;
}
mNewRegionFlag = false;
}
}
mlastRect.left = newleft;
mlastRect.top = newtop;
mlastRect.right = newright;
mlastRect.bottom = newbottom;
{
mPath.lineTo(mCurX, mCurY);
if(oldleft < newleft) targetleft = oldleft;
else targetleft = newleft;
if(oldtop < newtop) targettop = oldtop;
else targettop = newtop;
if(oldright < newright) targetright = newright;
else targetright = oldright;
if(oldbottom < newbottom) targetbottom = newbottom;
else targetbottom = oldbottom;
}
mRect.set(targetleft, targettop, targetright, targetbottom);
}
// Log.i(TAG, ("drawPoint() end \n"));
}
}
}
新建页面我只是做了保存当前页面,清空画布的逻辑,但是addNote后,笔记画的速度变慢了,然后我在MyView中的Handler机制中打印日志,输出的日志前后两次相比较,有差不多一倍之差,(我的上上篇有截图)但是总时长是对的,所以我开始想从Handler这里出发去解决他,后来问了好多人,也包括查各种stackoverflow论坛寻求答案;只有下面一些作参考
1.handler机制有可能随着CPU的荷载而变化
2.跟死循环一样
3.addNote后经可能的释放掉一些资源
然后想了半天,最后觉得应该是跟资源有关,用DDMS和AS分析了一下CPU和内存,然后便想到了试试结束当前activity,从而释放更多的资源,让下次绘制的时候又是最初的状态,而能够恢复其原有的速度呢?
开始在网上搜索activity的自我reset,结果不出所料,被我找到了。
public static void restartActivity(Activity act){
Intent intent=new Intent();
intent.setClass(act, act.getClass());
act.startActivity(intent);
act.finish();
}
我也做了一些扩展,比如传过来的path和name什么的,以及type区分是否是新建空白的等等,然后增加2个变量,一个position用来控制页码,一个boolean值用来控制删除。。。。。。。。。。。
最后解决了,速度跟之前的一样快,两次日志一样,帧率上来了
写下来,记录一下,以后留作纪念