Java y*/ 公共void addNode(浮点x、浮点y){ Node newNode=新节点(x,y); newNode.ID=graphNodeList.size(); 添加(newNode); newNode=null; } /**从图形中删除节点*/ void deleteNode(int-id){ graphNodeList.remove(id); 删除边缘(id); for(int i=id;i

Java y*/ 公共void addNode(浮点x、浮点y){ Node newNode=新节点(x,y); newNode.ID=graphNodeList.size(); 添加(newNode); newNode=null; } /**从图形中删除节点*/ void deleteNode(int-id){ graphNodeList.remove(id); 删除边缘(id); for(int i=id;i,java,android,multithreading,Java,Android,Multithreading,您遇到的主要问题是多线程编程中的常见问题。在java中,需要解决的两个问题是从一个线程访问图形对象,同时从另一个线程修改图形对象的安全性 另一个问题是,两个线程对图形对象的视图可能不同,必须采取措施让运行时/编译器知道,在某些代码边界之后,图形对象的视图必须同步 这可能有助于研究同步的关键字和内存同步。当然,也可能存在其他解决方案/优化,最好的方法是理解前面提到的多线程问题,并首先采用最直接的解决方案。。。。如果可能的话,以后再处理性能/优化问题。谢谢你的建议。我会研究你说的话。只是想让您知道,

您遇到的主要问题是多线程编程中的常见问题。在java中,需要解决的两个问题是从一个线程访问图形对象,同时从另一个线程修改图形对象的安全性

另一个问题是,两个线程对图形对象的视图可能不同,必须采取措施让运行时/编译器知道,在某些代码边界之后,图形对象的视图必须同步


这可能有助于研究同步的关键字和内存同步。当然,也可能存在其他解决方案/优化,最好的方法是理解前面提到的多线程问题,并首先采用最直接的解决方案。。。。如果可能的话,以后再处理性能/优化问题。

谢谢你的建议。我会研究你说的话。只是想让您知道,这个问题是由touchEvent处理程序中的一个愚蠢错误引起的,与实际的多线程无关。
package com.rares.graphit;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;


public class GraphDrawer extends Activity implements OnTouchListener{

/**Suface Manipulator*/
GraphPainter gp;

/**Graph object*/
public static Graph graph = null;

/**Touch coordinates*/
public static float touchX = 0;
public static float touchY = 0;

/**Drag state*/
public boolean isDragging = false;

/**Drag coordinates*/
public static float dragX = 0;
public static float dragY = 0;


/**Id of the node that is currently selected
 * Is -1 if no node is selected during a touch event*/
public static int currentId = -1; 

/**Id of a node that was selected before and an action between 2 nodes or on a node
 * that needs to be deleted or moved*/
public static int firstId = -1;


@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    /*Set window to fullscreen**/
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

    gp = new GraphPainter(this);
    gp.setOnTouchListener(this);
    graph = new Graph();

    setContentView(gp);


}


@Override
public boolean onTouch(View view, MotionEvent event) {
    // TODO Auto-generated method stub
    switch(event.getAction()){
    case MotionEvent.ACTION_DOWN:
        touchX = event.getX();
        touchY = event.getY();
        currentId = graph.pointIntersectsNode(touchX, touchY);
        break;

    case MotionEvent.ACTION_MOVE:
        dragX = event.getX();
        dragY = event.getY();
        /**Function will return -1 if there is no intersection or node ID if drag start intersects the node*/
        /**Selected node will be red on the screen*/
        if ((dragX - touchX)*(dragX - touchX) + (dragY - touchY)*(dragY - touchY) > Graph.Circle.RADIUS_DEFAULT){
            if(currentId != -1){
                graph.setNodePosition(currentId, dragX, dragY);
            }

            isDragging = true;
        }
        break;

    case MotionEvent.ACTION_UP:
        if(!isDragging){
            if(currentId == -1)
                graph.addNode(touchX, touchY);
            else{
                if(!graph.getGraphNodeList().get(currentId).isSelected){
                    graph.markNodeAsSelected(currentId);




                    if(firstId == -1)
                        firstId = currentId;
                    else{
                        if(graph.isEdge(Math.min(firstId, currentId), Math.max(firstId, currentId))){
                                graph.deleteEdge(Math.min(firstId,currentId),Math.max(firstId, currentId));
                            }
                        graph.addEdge(Math.min(firstId,currentId),Math.max(firstId, currentId));
                        graph.markNodeAsDeselected(currentId);
                        graph.markNodeAsDeselected(firstId);
                        firstId = -1;

                    }
                }
                else{
                    Log.d("IDS", "ID1: " + Integer.toString(currentId) + "\nSelected: " + Integer.toString(firstId));
                    /*graph.markNodeAsDeselected(id1);*/
                    if(firstId == currentId){
                        graph.deleteNode(currentId);
                    }
                    currentId = -1;
                    firstId = -1;
                }
            }
        }
        /*else
            if(id != -1){
                graph.markNodeAsDeselected(id);
                id = -1;
            }*/

        //Reset values
        isDragging = false;
        touchX = touchY = dragX = dragY = 0;
        break;

    }


    return true;
}



@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    gp.resume();
}



@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    gp.pause();
}




}
package com.rares.graphit;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GraphPainter extends SurfaceView implements Runnable {
/**ArrayLists for drawing the elements of the graph*/
ArrayList<Graph.Node> listNode;
ArrayList<Graph.Edge> listEdge;

/**Holder of surface*/
SurfaceHolder holder;

/**Drawing thread*/
Thread drawThread;

/**Canvas for drawing*/

Canvas canvas = null;

/**Bool for running state*/
boolean isRunning = false;

public GraphPainter(Context context){
    super(context);
    holder = getHolder();
    drawThread = new Thread(this);
    isRunning = true;
    drawThread.start();

}

@Override
public void run(){


    while (isRunning) {
        if (holder.getSurface().isValid()) {
            canvas = holder.lockCanvas();
            /**Draw background*/
            canvas.drawRGB(255, 255, 255);

            /**Draw Graph*/
            drawGraph();


            /**Print to screen*/
            holder.unlockCanvasAndPost(canvas);
        }
    }

}


public void drawGraph(){

    /**Draw Egdes*/

    listEdge = GraphDrawer.graph.getGraphEdgeList();
    Log.d("PAINT_EDGES", "Size of listEdge: " + listEdge.size());
    for(int i = 0; i < listEdge.size(); ++i){
        float startX = listNode.get(listEdge.get(i).id1).drawingCircle.x;
        float startY = listNode.get(listEdge.get(i).id1).drawingCircle.y;

        float stopX = listNode.get(listEdge.get(i).id2).drawingCircle.x;
        float stopY = listNode.get(listEdge.get(i).id2).drawingCircle.y;

        Paint linePaint = new Paint();
        linePaint.setColor(Graph.NODE_COLOR_UNSELECTED);
        canvas.drawLine(startX, startY, stopX, stopY, linePaint);
    }

    /**Draw Nodes*/

    listNode = GraphDrawer.graph.getGraphNodeList();
    for(int i = 0; i < listNode.size(); ++i){
        canvas.drawCircle(listNode.get(i).drawingCircle.x, listNode.get(i).drawingCircle.y, listNode.get(i).drawingCircle.R, listNode.get(i).drawingCircle.circlePaint);
    }


    /*clear the arraylists**/
    /*listNode.clear();
    listEdge.clear();*/
}


/**Will be called from GraphDrawer when onPause() will occur*/
public void pause(){
    isRunning = false;

    try {
        drawThread.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    drawThread = null;
}


public void resume(){
    drawThread = new Thread(this);
    isRunning = true;
    drawThread.start();

}

}
package com.rares.graphit;

import java.util.ArrayList;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;




/**Graph structure and manipulator. Momentarily, it will be an unoriented graph*/

public class Graph {


/**Circle for drawing purposes*/
public static class Circle{
    /**Circle Radius setting*/
    public static final float RADIUS_DEFAULT = 30;

    /**Circle coordinates*/
    float x, y;
    float R;

    /**Circle style*/
    Paint circlePaint = null;
    /*Circle default color*/
    public int DEFAULT_COLOR = Color.BLUE;
    public int drawColor;


    /**Creates a circle with the Point as center, r as radius, and the default color
     * of a node*/
    public Circle(float x, float y, float r){
        this.x = x;
        this.y = y;
        this.R = r;

        this.circlePaint = new Paint();
        this.circlePaint.setColor(DEFAULT_COLOR);
        drawColor = DEFAULT_COLOR;
    }


}


/**Graph node structure*/
public static class Node{
    /**For drawing purposes*/
    Circle drawingCircle;

    /**Node ID in the graph*/
    int ID;

    /**Flag that shows wether the node is selected*/
    public boolean isSelected = false;


    public Node(float x, float y){
        this.ID = numberOfNodes;
        drawingCircle = new Circle(x, y, Circle.RADIUS_DEFAULT);


    }

    public void setColor(int color){
        this.drawingCircle.circlePaint.setColor(color);
    }

}

/**Graph edge structure*/
public static class Edge{
    /**Nodes between whom the edge will be drawn
     * id1 - the lower number
     * id2 - the higher number
     * */
    public int id1, id2;

    /**Constructor that will set the nodes of the edge*/
    public Edge(int a, int b){
        if(a > b){
            id1 = b; id2 = a;
        }
        else{
            id1 = a; id2 = b;
        }
    }

}


/**List of vicinity of the graph*/
public static ArrayList<Node> graphNodeList;
/**Current number of nodes*/
public static int numberOfNodes = 0;

/**List of the edges of the graph*/
public static ArrayList<Edge> graphEdgeList;

/**Node default colors*/
public static int NODE_COLOR_UNSELECTED = Color.BLUE;
public static int NODE_COLOR_SELECTED = Color.RED;

/**All elements will be added through addNode() or addEdge() methods*/
public Graph(){
    graphNodeList = new ArrayList<Graph.Node>(0);
    graphEdgeList = new ArrayList<Graph.Edge>(0);
}


/**List of vicinity getter*/
public ArrayList<Node> getGraphNodeList(){
    return graphNodeList;
}

/**List of Edges getter*/
public ArrayList<Edge> getGraphEdgeList(){
    return graphEdgeList;
}


/**Adds a node into the graph, with the canvas coordinates: x and y*/
public void addNode(float x, float y){
    Node newNode = new Node(x, y);
    newNode.ID = graphNodeList.size();
    graphNodeList.add(newNode);
    newNode = null;
}


/**Deletes a node from the graph */
void deleteNode(int id){
    graphNodeList.remove(id);
    deleteEdges(id);
    for(int i = id; i < graphNodeList.size(); ++i){
        int aux = graphNodeList.get(i).ID;

        if(aux != i)
            resetEdgeNodes(aux, i);

        graphNodeList.get(i).ID = i;
    }

}

/**Verifies if a point described by its coordinates intersects one if the nodes on 
 * the screen.
 * Returns the ID of the node if true
 * -1 otherwise*/

public int pointIntersectsNode(float X, float Y){
    for(int i = 0; i < graphNodeList.size(); i++){
        float centerX = graphNodeList.get(i).drawingCircle.x;
        float centerY = graphNodeList.get(i).drawingCircle.y;
        float circleRadius = graphNodeList.get(i).drawingCircle.R;
        if((centerX-X) * (centerX-X) + (centerY-Y)*(centerY-Y) < circleRadius*circleRadius)
            return i;
    }

    return -1;
}


/**Marks node as selected and will paint it the COLOR_SELECTED color*/
public void markNodeAsSelected(int id){
    graphNodeList.get(id).setColor(NODE_COLOR_SELECTED);
    graphNodeList.get(id).isSelected = true;
}


/**Marks the node back as deselected, with its default color*/
public void markNodeAsDeselected(int id) {
    graphNodeList.get(id).drawingCircle.circlePaint.setColor(NODE_COLOR_UNSELECTED);
    graphNodeList.get(id).isSelected = false;
}


/**Sets the position of the node with the id ID at the (X,Y) point*/
public void setNodePosition(int id, float X, float Y) {
    graphNodeList.get(id).drawingCircle.x = X;
    graphNodeList.get(id).drawingCircle.y = Y;


}


/**Adds an edge between two nodes*/
public void addEdge(int id1, int id2){
    Edge edge = new Edge(id1, id2);
    graphEdgeList.add(edge);
}


/**Verifies if an edge between nodes id1 and id2 exists*/
public boolean isEdge(int id1, int id2){
    for(int i = 0; i < graphEdgeList.size(); ++i){
        if(id1 == graphEdgeList.get(i).id1 && id2 == graphEdgeList.get(i).id2)
            return true;
    }
    return false;
}


/**Deletes an edge from the list, by the nodes IDs
 * id1 is the node with the minimum id
 * id2 is the node with the maximum id
 * */
public void deleteEdge(int id1, int id2){
    Log.d("EDGE_DELETE", "Size before a single edge deletion: " + Integer.toString(graphEdgeList.size()));

    for(int i = 0; i < graphEdgeList.size(); ++i)
        if(id1 == graphEdgeList.get(i).id1 && id2 == graphEdgeList.get(i).id2){
            Log.d("EDGE", "EDGE DELETED" + Integer.toString(id1) + " " + Integer.toString(id2));
            graphEdgeList.remove(i);

            Log.d("EDGE_DELETE", "Size after a single edge deletion: " + Integer.toString(graphEdgeList.size()));
            return;
        }

}

/**Deletes the edges which has one of the nodes with its ID set to id*/
public void deleteEdges(int id){
    for(int i = 0; i < graphEdgeList.size(); ++i){
        if(id == graphEdgeList.get(i).id1 || id == graphEdgeList.get(i).id2){
            graphEdgeList.remove(i);
            i--;
        }
    }
}


/**Resets the List of Edges when a node is deleted*/
public void resetEdgeNodes(int oldId, int newId){
    for(int i = 0; i < graphEdgeList.size(); ++i){
        int nodeId1 = graphEdgeList.get(i).id1;
        int nodeId2 = graphEdgeList.get(i).id2;
        if(nodeId1 == oldId){
            graphEdgeList.get(i).id1 = newId;
        }
        else
            if(nodeId2 == oldId){
                graphEdgeList.get(i).id2 = newId;
            }

        /*If the new nodes are nod in order, swap them**/
        if(graphEdgeList.get(i).id1 > graphEdgeList.get(i).id2){
            int aux = graphEdgeList.get(i).id1;
            graphEdgeList.get(i).id1 = graphEdgeList.get(i).id2;
            graphEdgeList.get(i).id2 = aux;
        }
    }

}


}