私はAndroidのSurfaceviewの実装に不慣れです。android3.0でRDPクライアントアプリケーションを開発しています。ソケットから画像ストリームを取得し、SurfaceviewとThreadを使用してこの画像をサーフェスに描画します。
サーフェスビューのサンプルコード:
class mySurfaceView extends SurfaceView implements SurfaceHolder.Callback
{
private TutorialThread _thread;
Canvas c=null;
public mySurfaceView(Context context)
{
super(context);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
matrix= new Matrix();
m = new float[9];
paint = new Paint();
}
public void surfaceCreated(SurfaceHolder arg0) {
//setWillNotDraw(false) ;
Log.e("surfaceCreated","surfaceCreated");
if(_thread==null ){
Log.e("_thread.created","thread created");
_thread = new TutorialThread(getHolder(),this);
_thread.setRunning(true);
_thread.start();
// <-- added fix
}else {
Log.e("_thread.getState()",_thread.getState()+"");
_thread.setRunning(true); //original code
_thread.start(); //original code
}
}
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.e("surfaceDestroyed","surfaceDestroyed");
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
}
class TutorialThread extends Thread
{
private SurfaceHolder _surfaceHolder;
private mySurfaceView _panel;
private boolean _run = false;
private InputStream is;
private Socket socket;
Bitmap resizeBmp;
public TutorialThread(SurfaceHolder surfaceHolder,mySurfaceView panel)
{
Log.e("TutorialThread","TutorialThread-->Constructor");
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
@Override
public void run()
{
Log.e("TutorialThread","TutorialThread-->run()");
try
{
socket = new Socket("172.19.1.144", 4444);
is = socket.getInputStream();
DataInputStream inputputStream = new DataInputStream(is);
//long time = System.currentTimeMillis();
int i=0;
while (socket.isConnected() )
{
Log.e("tutorial thread","While running");
c = null;
i++;
if(i==10){
System.gc();
i=0;
}
Log.e("BEFORE","BEFORE");
synchronized (_surfaceHolder)
{
Log.e("AFTER","AFTER");
ByteBuffer inputHeaderBuffer = ByteBuffer.allocate(20);
inputHeaderBuffer.order(ByteOrder.LITTLE_ENDIAN);
inputputStream.readFully(inputHeaderBuffer.array());
SurfaceViewPinchZoom.serverWidth=inputHeaderBuffer.getInt();
SurfaceViewPinchZoom.serverHeight=inputHeaderBuffer.getInt();
//Log.e("serverWidth","serverWidth "+ SurfaceViewPinchZoom.serverWidth+"serverHeight===="+SurfaceViewPinchZoom.serverHeight);
SurfaceViewPinchZoom.left=inputHeaderBuffer.getInt();
SurfaceViewPinchZoom.top=inputHeaderBuffer.getInt();
int dataLength = inputHeaderBuffer.getInt();
ByteBuffer imageDataCompress = ByteBuffer.allocate(dataLength);
imageDataCompress.order(ByteOrder.LITTLE_ENDIAN);
inputputStream.readFully(imageDataCompress.array());
byte[] imagedata = new byte[imageDataCompress.remaining()];
imageDataCompress.get(imagedata);
//Decompress the image
//Log.e("imagedata.length::::::::::",imagedata.length+"");
// Create the decompressor and give it the data to compress
Inflater decompressor = new Inflater();
decompressor.setInput(imagedata);
// Create an expandable byte array to hold the decompressed data
ByteArrayOutputStream bos = new ByteArrayOutputStream(imagedata.length);
// Decompress the data
byte[] buf = new byte[1024];
while (!decompressor.finished()) {
try {
int count = decompressor.inflate(buf);
bos.write(buf, 0, count);
} catch (DataFormatException e) {
}
}
try {
bos.close();
} catch (IOException e) {
}
// Get the decompressed data
byte[] decompressedData = bos.toByteArray();
/
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
// Log.e("decompressedData.length::::::::::",decompressedData.length+"");
/*SurfaceViewPinchZoom.*/bmp = BitmapFactory.decodeByteArray(decompressedData, 0,decompressedData.length,options);
options.inDither=true;
/*scaleX=(float)screen_width/bmp.getWidth();
scaleY=(float)screen_height/bmp.getHeight();
matrix.setScale(scaleX, scaleY);*/
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, screen_width, screen_height);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
/*SurfaceViewPinchZoom.*/bmp= BitmapFactory.decodeByteArray(decompressedData, 0,decompressedData.length,options);
bmp=BitmapFactory.decodeByteArray(decompressedData, 0,decompressedData.length,options);
c = _surfaceHolder.lockCanvas();
c.drawBitmap(bmp, matrix, paint);
//draw(c);
//postInvalidate();
onDraw(c);
inputHeaderBuffer.clear();
imageDataCompress.clear();
inputHeaderBuffer = null;
imageDataCompress = null;
imagedata = null;
}
if (c != null)
{
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
catch (ArrayIndexOutOfBoundsException ae)
{
ae.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
finally {
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
private int calculateInSampleSize(Options options, int screen_width,
int screen_height) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > screen_height || width > screen_width) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)screen_height);
} else {
inSampleSize = Math.round((float)width / (float)screen_width);
}
}
return inSampleSize;
}
}
}
問題は
1)ホームボタンを押すsurfaceDestroyed()
と呼び出されthread
て終了します。
ただし、ホームボタンを押してアプリケーションを開いた後、スレッドを続行して画像(ソケットからの入力ストリーム)を更新する必要があります。
2)doubletap
イベントのアクティビティを子アクティビティとして呼び出すと、surfaceDestroyed()
呼び出されThread
て終了します。
子供の活動から戻った後、画像の表示を続ける必要がある場合。
どちらの場合も、スレッドがすでに開始されているため、例外が発生します。java.lang.IllegalThreadStateException:
ホームボタンが押されたり、別の子アクティビティが呼び出されたりせずに同じスレッドを実行する方法を教えてください。
ありがとう&よろしくヤミニ