Nikola010 Nikola010 - 7 months ago 18
Java Question

New to Android programming: Program does not respond

I am new to android programming, and i have started some small programs to learn. This program for drawing works until i draw many lines (i don't know how many but about 10-20) and that number depends on how fast am i drawing it (faster drawing less lines to get stuck). When i start debug and stop program when it stop responding it leads me to this line:

private native void nativePollOnce(long ptr, int timeoutMillis); /non-static for callbacks/


Dont know what it is and is that what freezes program, however here is my program:

Drawing.java

package com.appl.nikola.drawing;

import android.graphics.Color;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Drawing extends AppCompatActivity implements View.OnTouchListener, SurfaceHolder.Callback {

public static SurfaceView surfaceView;
public static SurfaceHolder surfaceHolder;
Thread t1;
public static Coordinates cordinates;
public static List<Coordinates> listOfDrawing;
int staCrta;
public static Paint p;
public static boolean isItOK;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawing);
//Definisem surfaceView
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceView.setOnTouchListener(this);
//Definisem surfaceHolder
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
//Definisem listu crtanja
listOfDrawing = new ArrayList<Coordinates>();
//Coordinates = {vrsta objekta:1-linija, 2-rucno, 3- pravougaonik, x1, y1, x2, y2}
cordinates = new Coordinates();
staCrta = 1;
cordinates.x1 = 5;
cordinates.x2 = 5;
cordinates.y1 = 6;
cordinates.y2 = 6;
cordinates.vrstaCrtanja = 1;

listOfDrawing.add(new Coordinates(cordinates.vrstaCrtanja,cordinates.x1,cordinates.y1,cordinates.y1,cordinates.y2));
cordinates.x1 = 7;
cordinates.x2 = 7;
cordinates.y1 = 8;
cordinates.y2 = 8;
cordinates.vrstaCrtanja = 1;
listOfDrawing.add(new Coordinates(cordinates.vrstaCrtanja,cordinates.x1,cordinates.y1,cordinates.y1,cordinates.y2));
//Definisem Paint: boja debljina
p = new Paint();
p.setColor(Color.YELLOW);
p.setStrokeWidth(3);
}

@Override
public boolean onTouch(View v, MotionEvent event) {

switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
switch (staCrta){
case 1:
cordinates.vrstaCrtanja = 1;
cordinates.x1 = event.getX();
cordinates.y1 = event.getY();
Log.d("Log1","Touch down");
break;
case 2:

break;
case 3:

break;
}
break;
case MotionEvent.ACTION_UP:
switch (staCrta){
case 1:
cordinates.x2 = event.getX();
cordinates.y2 = event.getY();
listOfDrawing.add(new Coordinates(cordinates.vrstaCrtanja,cordinates.x1,cordinates.y1,cordinates.x2,cordinates.y2));
Log.d("Log1", "Touch up");
break;
case 2:

break;
case 3:

break;
}
break;
case MotionEvent.ACTION_MOVE:

switch (staCrta){
case 1:

break;
case 2:

break;
case 3:

break;
}
break;
}
return true;
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
//Kada je surfaceView definisi i kreiraj thread t1
isItOK = true;
t1 = new Thread(new DrawingSurfaceLayout());
t1.start();
Log.d("Log1", "SurfaceCreated");
Log.d("Log1",Boolean.toString(isItOK));
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isItOK = false;
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t1 = null;
Log.d("Log1","Thread Stopped");
}



}


DrawingSurfaceLayout.java

package com.appl.nikola.drawing;

import android.graphics.Canvas;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

/**
* Created by Nikola on 4/25/2016.
*/
public class DrawingSurfaceLayout implements Runnable {
Canvas c;
Drawing drawing;
public DrawingSurfaceLayout() {
drawing = new Drawing();

}

@Override
public void run() {

try{
Log.d("Log1","run");
Log.d("Log1",Boolean.toString(drawing.isItOK));
while(drawing.isItOK){
if(!drawing.surfaceHolder.getSurface().isValid()){
Log.d("Log1","Surface not valid");
continue;
}

c = drawing.surfaceHolder.lockCanvas();
c.drawRGB(0, 0, 255);
List<Coordinates> listOfDrawing;
listOfDrawing = new ArrayList<Coordinates>();
listOfDrawing = drawing.listOfDrawing;
for(Coordinates x: listOfDrawing){
if(x.vrstaCrtanja == 1){//Linija
c.drawLine(x.x1,x.y1,x.x2,x.y2,drawing.p);
}
}
drawing.surfaceHolder.unlockCanvasAndPost(c);

}
}
catch (Exception e){
e.printStackTrace();
}
}


}


Coordinates.java

package com.appl.nikola.drawing;

/**
* Created by Nikola on 4/25/2016.
*/
public class Coordinates {
float vrstaCrtanja;
float x1;
float y1;
float x2;
float y2;
public Coordinates() {

}
public Coordinates(float vrstaCrtanja, float x1, float y1, float x2, float y2) {
this.vrstaCrtanja = vrstaCrtanja;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}


activity_drawing.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.appl.nikola.drawing.Drawing"
android:weightSum="100"
android:orientation="vertical">

<SurfaceView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="95"
android:id="@+id/surfaceView"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="5"
android:id="@+id/bMenu"/>

</LinearLayout>


Edit:

On request here is what pops out when i reproduce error

04-25 21:52:21.091: W/System.err(2488): java.util.ConcurrentModificationException
04-25 21:52:21.093: W/System.err(2488): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
04-25 21:52:21.093: W/System.err(2488): at com.appl.nikola.drawing.DrawingSurfaceLayout.run(DrawingSurfaceLayout.java:37)
04-25 21:52:21.093: W/System.err(2488): at java.lang.Thread.run(Thread.java:818)


Yea and when i hit home button this pops out (home when app freezes)

04-25 21:57:07.227: I/ActivityManager(1533): START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.android.launcher3/.Launcher (has extras)} from uid 1000 on display 0
04-25 21:57:07.243: D/(1533): HostConnection::get() New Host Connection established 0x9e2eb9a0, tid 1570
04-25 21:57:07.255: E/EGL_emulation(1187): tid 1187: eglCreateSyncKHR(1294): error 0x3004 (EGL_BAD_ATTRIBUTE)
04-25 21:57:07.305: I/InputDispatcher(1533): Dropping event because there is no touchable window at (195, 525).
04-25 21:57:07.357: W/EGL_emulation(2262): eglSurfaceAttrib not implemented
04-25 21:57:07.357: W/OpenGLRenderer(2262): Failed to set EGL_SWAP_BEHAVIOR on surface 0xa31bf620, error=EGL_SUCCESS
04-25 21:57:07.936: W/OpenGLRenderer(2262): Incorrectly called buildLayer on View: ShortcutAndWidgetContainer, destroying layer...
04-25 21:57:07.936: W/OpenGLRenderer(2262): Incorrectly called buildLayer on View: ShortcutAndWidgetContainer, destroying layer...

Answer

In DrawingSurfaceLayout in run() method you are tring to access to drawing.listOfDrawing while another thread is populating it. You can avoid this problem using an iterator. Replace this:

for(Coordinates x: listOfDrawing){
                if(x.vrstaCrtanja == 1){//Linija
                    c.drawLine(x.x1,x.y1,x.x2,x.y2,drawing.p);
                }
            }

with this:

for (Iterator<Coordinates> it = listOfDrawing.iterator(); it.hasNext();){
                Coordinates x = it.next();
                if (x.vrstaCrtanja == 1) {
                     it.drawLine(x.x1,x.y1,x.x2,x.y2,drawing.p);
                }
            }

It should work (I can't test).

Comments