I have a database filled with records in the following format: . What I want my application to do is select records from an external database, and display those records on the phone screen using a SurfaceView.
Currently, I have an Activity, and a Service responsible for the record-gathering portion of the application. The Activity passes an intent to the Service, and the Service responds by returning the records that need to be displayed. The records are stored in my program as instances of the Data class, and merely have the screen-coordinates of where the element should be drawn in the View (I am just drawing a circle for every record in the DB).
For the sake of brevity, I won't include the service but I will include a skeleton of the Activity class and the Data that I wish to display.
public class Data{
private int x;
private int y;
private int id;
private int shape;
/*
* Getters and setters for class properties
*/
}
public class Displayer extends Activity {
int ht;
int wt;
dataReceiver dreceiver;
public static Map<String, Data> Info;
private LinearLayout linear;
private static final int RADIUS = 20;
Panel panel;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
panel=new Panel(this);
setContentView(panel);
Intent scv = new Intent(this, DataService.class);
startService(scv);
}
/*
* Various other methods to take care of onDestroy, onPause, etc.
*/
public class dataReceiver extends BroadcastReceiver {
//Get new data from intents sent by the Service and store it in Info variable
//Update the Testing Map data-structure in the Panel SurfaceView with new records
panel.setData(Info);
}
}
The problem that I am having pertains to the SurfaceView. I realize that many people are going to suggest that I use just a regular View, but my application involves a lot of elements, so a SurfaceView would be much more suitable for my needs. Below is a skeleton of my SurfaceView class that contains a nested class to manage the threads.
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
private PanelThread _thread;
private Paint circlepaint;
private Paint textpaint;
private static int CircleColor = Color.YELLOW;
private static int TextColor = Color.RED;
private static Map<String, Data> Testing;
public Panel(Context context, Map<String, Data> entries) {
super(context);
getHolder().addCallback(this);
_thread = new PanelThread(getHolder(), this);
setFocusable(true);
textpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textpaint.setStyle(Style.FILL_AND_STROKE);
textpaint.setColor(TextColor);
Testing = new HashMap<String, Data>();
// Log.d("TestingSize",String.valueOf(Testing.size()));
if (!(Testing.isEmpty())) {
Testing.clear();
}
for (Map.Entry<String, Data> e : entries.entrySet()) {
String keyvalue = e.getKey();
Data v = e.getValue();
Panel.Testing.put(keyvalue, v);
}
}
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
_thread = new PanelThread(getHolder(), this);
setFocusable(true);
textpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textpaint.setStyle(Style.FILL_AND_STROKE);
textpaint.setColor(TextColor);
Testing = new HashMap<String, Victims>();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
_thread.setRunning(true);
_thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
/* we have to tell thread to shut down
* & wait for it to finish,
* or else it might touch the Surface
* after we return and explode
*/
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
/*If new records are received
* from the service, they can be updated
* using this method
*/
public void setData(Map<String,Data>Info){
Testing=Info;
}
/*
* Iterate over all contents of Testing List and display them to the screen
*/
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!(Testing.isEmpty())) {
for (Map.Entry<String, Victims> e : Testing.entrySet()) {
Data d = e.getValue();
canvas.drawCircle(d.getX(), d.getY(), 10, circlepaint);
}
}
canvas.save();
canvas.restore();
}
/*
* Nested class to manage the threads for the SurfaceView
*/
class PanelThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
public PanelThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
public SurfaceHolder getSurfaceHolder() {
return _surfaceHolder;
}
@Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}//end of PanelThread
}//end of Panel
The problem that I'm having is that once I make the initial call to the Panel class, I'm going to be getting new records from the service, and consequently, my Info Map data-structure is going to get updated. However, my Panel class just gets stuck in a loop and never receives any new Data objects. All examples of SurfaceViews I've found have involved updating them methods within the SurfaceView class itself (e.g. touching the screen and creating a new image, etc.) Sadly, I'm stumped on this particular problem. Is there a better approach for designing my Activity/SurfaceView interaction? Is an additional View required?