I'm trying to store objects of Android.graphics.Path in internal device memory. Does anyone know how to serialize a android.graphics.Path object? And also, is there any other way of storing a Path object? Thanks.
The way I did it is to identify the methods that I needed from the original Path class and then simply override those methods as follows:
public class CustomPath extends Path implements Serializable {
private static final long serialVersionUID = -5974912367682897467L;
private ArrayList<PathAction> actions = new ArrayList<CustomPath.PathAction>();
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject();
drawThisPath();
}
#Override
public void moveTo(float x, float y) {
actions.add(new ActionMove(x, y));
super.moveTo(x, y);
}
#Override
public void lineTo(float x, float y){
actions.add(new ActionLine(x, y));
super.lineTo(x, y);
}
private void drawThisPath(){
for(PathAction p : actions){
if(p.getType().equals(PathActionType.MOVE_TO)){
super.moveTo(p.getX(), p.getY());
} else if(p.getType().equals(PathActionType.LINE_TO)){
super.lineTo(p.getX(), p.getY());
}
}
}
public interface PathAction {
public enum PathActionType {LINE_TO,MOVE_TO};
public PathActionType getType();
public float getX();
public float getY();
}
public class ActionMove implements PathAction, Serializable{
private static final long serialVersionUID = -7198142191254133295L;
private float x,y;
public ActionMove(float x, float y){
this.x = x;
this.y = y;
}
#Override
public PathActionType getType() {
return PathActionType.MOVE_TO;
}
#Override
public float getX() {
return x;
}
#Override
public float getY() {
return y;
}
}
public class ActionLine implements PathAction, Serializable{
private static final long serialVersionUID = 8307137961494172589L;
private float x,y;
public ActionLine(float x, float y){
this.x = x;
this.y = y;
}
#Override
public PathActionType getType() {
return PathActionType.LINE_TO;
}
#Override
public float getX() {
return x;
}
#Override
public float getY() {
return y;
}
}
}
In my example I need "moveTo" and "lineTo", so in this case I simply hold the drawing information in a list. This list contains the drawing information (what I call "action") needed by Path in order to restore the drawing as it looked like before the object was serialized. Then when I deserialize my objects of type CustomPath i make sure to let the default serialization protocol call "drawThisPath", so the path is redrawn.
I've just managed to solve this. My application is based off the FingerPaintDemo, so makes use of just moveTo and quadTo, but I think you can apply this approach to any Path functions.
First, extend Path as follows:
import android.graphics.Path;
import java.util.ArrayList;
import java.io.Serializable;
public class SerializablePath extends Path implements Serializable {
private ArrayList<float[]> pathPoints;
public SerializablePath() {
super();
pathPoints = new ArrayList<float[]>();
}
public SerializablePath(SerializablePath p) {
super(p);
pathPoints = p.pathPoints;
}
public void addPathPoints(float[] points) {
this.pathPoints.add(points);
}
public void loadPathPointsAsQuadTo() {
float[] initPoints = pathPoints.remove(0);
this.moveTo(initPoints[0], initPoints[1]);
for (float[] pointSet : pathPoints) {
this.quadTo(pointSet[0], pointSet[1], pointSet[2], pointSet[3]);
}
}
}
I don't think I need to paste the implementation code, but if you want to see it let me know. Basically just as you call something like myPath.quadTo(x1, y1, x2, y2), also call myPath.addPathPoints(new float[]{x1, y1, x2, y2}).
Serialize the object to disk as normal, and when you read it back in, just be sure to call myPath.loadPathPointsAsQuadTo().
There is nothing so special for Path Class. Use can serialize any class that implements the Serializable interface..
Serializable interface is a Marker interface. i.e it dont have any method to implement. It just signify that the object can be deflatted to files/Memroies and later can be inflatted to be a live object again
What you do just make a class that extends your android.graphics.Path class and implements the Serializable interface. Then use this class instead of your android.graphics.Path. Then you will be able to apply serialization over it.
And check the following link for a detailed information
http://java.sun.com/developer/technicalArticles/Programming/serialization/
Hope this helps :)
Related
I have a class named MapViewManager, in it I have a method called navigate like below:
public class MapViewManager{
...
public void navigate(double startX, double startY, double toX, double toY, long floorId, boolean flag) {
final FeatureLayer featureLayer = new FeatureLayer("navigate");
mapView.setLayerOffset(featureLayer);
mapView.addLayer(featureLayer);
final NavigateManager navigateManager = new NavigateManager();
if (flag) {
navigateManager.navigation(startX, startY, floorId, toX, toY, floorId);
}else{
navigateManager.clear();
}
navigateManager.setOnNavigateComplete(new NavigateManager.OnNavigateComplete() {
#Override
public void onNavigateComplete(NavigateManager.NavigateState navigateState,
FeatureCollection featureCollection) {
featureLayer.clearFeatures();
featureLayer.addFeatures(featureCollection);
for (int i=0;i<featureCollection.getSize();i++){
Feature feature = featureCollection.getFeature(i);
Coordinate coordinate = feature.getCentroid();
double x = coordinate.getX();
double y = coordinate.getY();
}
}
});
}
}
I want to access the variable named coordinate in onNavigateComplete callback method from outside so that other classes can use the coordinate variable to do something. How can I make it?
Add one more parameter to navigate method.
public class MapViewManager{
...
public void navigate(double startX, double startY, double toX, double toY, long floorId, boolean flag, NavigateManager.OnNavigateComplete navigation) {
final FeatureLayer featureLayer = new FeatureLayer("navigate");
mapView.setLayerOffset(featureLayer);
mapView.addLayer(featureLayer);
final NavigateManager navigateManager = new NavigateManager();
if (flag) {
navigateManager.navigation(startX, startY, floorId, toX, toY, floorId);
}else{
navigateManager.clear();
}
navigateManager.setOnNavigateComplete(navigation);
}
}
Call method from other Class :
new MapViewManager().navigate(other paramter values, new NavigateManager.OnNavigateComplete() {
#Override
public void onNavigateComplete(NavigateManager.NavigateState navigateState,
FeatureCollection featureCollection) {
featureLayer.clearFeatures();
featureLayer.addFeatures(featureCollection);
for (int i=0;i<featureCollection.getSize();i++){
Feature feature = featureCollection.getFeature(i);
Coordinate coordinate = feature.getCentroid();
navigationPoints.add(coordinate);
double x = coordinate.getX();
double y = coordinate.getY();
}
}
});
Now you can access any object anywhere.
You have to make it public by doing this:
Say your activity name is 'Main'
....
Public class Main extends AppCompatActivity{
Coordinate coor;
//in the onNavigationComplete method do this
Coordinate coordinate = //..complete this;
coor = coordinate;
…
…}
I want to connect several classes which are functioning separately but are related.
Lets say I am writing an app in which you can swipe to draw a chart. There are lots of classes in the app which are related and should be connected.
For example three of the classes are:
Swiper - responsible for interpreting the gesture of the user
Points - responsible for handling the points on the chart
ChartDrawer - responsible for drawing the chart on the screen
I want to know is there any design pattern such as a connector which can handle the relation and communication of these classes? Any way i can redesign in a better way or make mind more object oriented?
This is my ChartDraw class which extends a view:
public class ChartDraw extends View implements GestureReceiver {
int chartYPosition;
private int circleColor;
private int circleRadius;
int height;
private float lastPointOnChart;
private int lineColor;
private int lineWidth;
private Paint paint;
private float tempPoint;
int width;
public ChartDraw(Context context) {
super(context);
init();
}
public ChartDraw(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ChartDraw(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
this.lineWidth = 15;
this.circleRadius = 20;
this.lineColor = Color.parseColor("#1976D2");
this.circleColor = Color.parseColor("#536DFE");
this.lastPointOnChart = 0.0f;
this.tempPoint = 0.0f;
this.paint = new Paint();
this.height = getHeight();
this.width = getWidth();
this.chartYPosition = this.height / 2;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.chartYPosition = canvas.getHeight() / 2;
this.paint.setStrokeWidth((float) this.lineWidth);
this.paint.setColor(this.lineColor);
canvas.drawLine(0.0f, (float) this.chartYPosition, this.tempPoint, (float) this.chartYPosition, this.paint);
if (this.tempPoint > 20.0f) {
this.paint.setColor(this.circleColor);
canvas.drawCircle(20.0f, (float) this.chartYPosition, 20.0f, this.paint);
drawTriangle(canvas, this.paint, this.tempPoint, this.chartYPosition);
}
}
private void drawTriangle(Canvas canvas, Paint paint, float startX, int startY) {
Path path = new Path();
path.moveTo(startX, (float) (startY - 20));
path.lineTo(startX, (float) (startY + 20));
path.lineTo(30.0f + startX, (float) startY);
path.lineTo(startX, (float) (startY - 20));
path.close();
canvas.drawPath(path, paint);
}
public void onMoveHorizontal(float dx) {
this.tempPoint = this.lastPointOnChart + dx;
invalidate();
}
public void onMoveVertical(float dy) {
}
public void onMovementStop() {
this.lastPointOnChart = this.tempPoint;
}
}
And this is My SwipeManager which is handling user gesture:
public class SwipeManager implements View.OnTouchListener {
GestureReceiver receiver;
private int activePointer;
private float initX,
initY;
private long startTime,
stopTime;
private boolean resolving = false;
private boolean resolved = false;
private Direction direction;
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (receiver == null) throw new AssertionError("You must register a receiver");
switch (motionEvent.getActionMasked()) {
case ACTION_DOWN:
activePointer = motionEvent.getPointerId(0);
initX = motionEvent.getX(activePointer);
initY = motionEvent.getY(activePointer);
startTime = new Date().getTime();
break;
case ACTION_MOVE:
if (!resolving && !resolved) {
resolving = true;
float x = motionEvent.getX(activePointer);
float y = motionEvent.getY(activePointer);
direction = resolveDirection(x, y);
if (direction != Direction.STILL) {
resolved = true;
resolving = false;
} else {
resolving = false;
resolved = false;
}
break;
}
if (resolved) {
if (direction == Direction.HORIZONTAL)
receiver.onMoveHorizontal(motionEvent.getX(activePointer) - initX);
else receiver.onMoveVertical(motionEvent.getX(activePointer) - initY);
}
break;
case ACTION_UP:
resolved = false;
receiver.onMovementStop();
break;
}
return true;
}
private Direction resolveDirection(float x, float y) {
float dx = x - initX;
float dy = y - initY;
float absDx = Math.abs(dx);
float absDy = Math.abs(dy);
if (absDx > absDy + 10) {
return Direction.HORIZONTAL;
} else if (absDy > absDx + 10) {
return Direction.VERTICAL;
}
return Direction.STILL;
}
public void setReceiver(GestureReceiver receiver) {
this.receiver = receiver;
}
private enum Direction {HORIZONTAL, VERTICAL, STILL;}
}
And i didn't start the Points class because i was not sure about the architecture.
I want this Connector to register all the listeners for the classes and wait for a change and inform the corresponding class of the change, like new point added or swipe started and finished or any other event in the app.
Chain of Responsibility might be what you are looking for.
It is a pattern to tie a series of 'processing objects' in a 'chain' that can handle 'command objects'.
I could see you making command objects that encapsulate the touch events and then get passed through several processors and finally get 'processed' by the 'processing objects' which handle input detection/output generation for that particular 'command object'.
I don't know if this is -ideal-, but it is potentially valid.
Other related patterns to look into might be:
https://en.wikipedia.org/wiki/Command_pattern
https://en.wikipedia.org/wiki/Observer_pattern
https://en.wikipedia.org/wiki/Bridge_pattern
Really what you're looking for here is an MVC-style architecture. Your application should (broadly speaking) be separated into 3 different areas:
the Model, which is completely divorced from your presentation or communication concerns. It provides an API for interaction and can be tested entirely independently with a simple framework such as JUnit.
the View, which is responsible for displaying the Model. It may be that a model can be displayed in different ways - in which case you get a single model and a few different views.
the Controller, which is responsible for making changes to the Model in response to user (or other) input.
The important thing is that the three sets of components are loosely-coupled and that responsibilities are clearly separated. All three should communicated via well defined interfaces (perhaps using the Observer, Command and ChainOfResponsibility patterns). In particular, the Model classes should have no direct knowledge of any of the View or Controller classes.
So, you might have some Model/View classes like this...
public interface ChartListener {
void notifyUpdate();
}
public interface Chart {
void newPoint(Point p);
Collection<Point> thePoints();
void addListener(ChartListener listener);
}
public class ChartModel implements Chart {
private final Collection<Point> points;
private final Collection<ChartListener> listeners;
public Collection<Point> thePoints() {
return Collections.unmodifiableCollection(points);
}
public void newPoint(Point p) {
thePoints.add(p);
listeners.stream().forEach(ChartListener::notifyUpdate);
}
public void addListener(ChartListener cl) {
listeners.append(cl);
}
}
public PieChartViewer implements ChartListener {
// All you colour management or appearance-related concerns is in this class.
private final Chart chart;
public PieChartView(Chart chart) {
this.chart = chart;
// set up all the visuals...
}
public void notifyUpdate() {
for (final Point p:chart.thePoints()) {
// draw a point somehow, lines, dots, etc,
}
}
}
Then you might have multiple different implementations of your View classes, utilising the ChartListener interface.
Your Swipe class seems like a Controller class, which would take a ChartModel implementation and then modify it in response to some input from the user.
I searched for and wide on the internet and I have yet to find an answer. I have an object called GameIcon which extends Sprite. Everything about it is okay except for the texture. Here is my code for the GameIcon class.
package com.xx4everPixelatedxx.gaterunner.sprites;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.xx4everPixelatedxx.gaterunner.GateRunner;
import javax.xml.soap.Text;
/**
* Created by Michael Jan on 8/17/2015.
*/
public class GameIcon extends Sprite {
private int vX = 3;
private int vY = 3;
private int r = 9;
private int rotation;
private Vector3 position;
private Texture texture;
public GameIcon(int x, int y) {
position = new Vector3(x, y, 0);
texture = new Texture(Gdx.files.internal("icon_players/icon1.png"));
setTexture(texture);
}
public void update() {
position.add(vX, vY, 0);
rotation = rotation + r;
rotation = rotation % 360;
setRotation(rotation);
setOriginCenter();
}
public void addPosition(int x, int y) {
position.add(x, y, 0);
setOriginCenter();
}
public void negateVelocityX() {
vX = -vX;
}
public void negateRotation() {
r = -r;
}
public Vector3 getPosition() {
return position;
}
public int getvY() {
return vY;
}
public void setvY(int vY) {
this.vY = vY;
}
public int getvX() {
return vX;
}
public void setvX(int vX) {
this.vX = vX;
}
}
Here is the icon1.png:
https://i.gyazo.com/1d52f5e58b227f08809f6c14ae4c94a4.png
Here is what I am getting:
https://i.gyazo.com/1881a9392955af34de5c55b9b8fac391.png
Note that the rotation of the image and the particles are intended. The problem is that the big square should be the texture (icon1.png), and I do not know how to fix this.
(Not enough reputation to post pictures)
I'm not familiar with LibGDX, but this may have something to do with the fact that you are maybe overwriting TextureRegion.texture. Could you try to user your parent class Sprite(Texture) constructor like this:
...
public class GameIcon extends Sprite {
private int vX = 3;
private int vY = 3;
private int r = 9;
private int rotation;
private Vector3 position;
//private Texture texture;
public GameIcon(int x, int y) {
super(new Texture(Gdx.files.internal("icon_players/icon1.png")))
position = new Vector3(x, y, 0);
}
...
As stated by Tenfour04 in comments, this method works because the parent's constructor applies the width and height of the texture, while setTexture() does not.
I've been using Simple to try to read in my XML file to this class. I really don't know if I've annotated the classes correctly.
I don't know if I need this part:
public Frame()
{
super();
}
public Frame(int num, int x, int y, int width, int height,int offsetx,int offsety, int duration )
{
this.Num = num;
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
this.OffsetX = offsetx;
this.OffsetY = offsety;
this.Duration = duration;]
What does super() do? Do I need getters/setters? Is what I added getters or setters? Do they call themselves automatically or what?
Here's the full class:
public class SpriteAnimationManag
{
// Animation frame class
#Element(name = "Frame")
public class Frame
{
#Element(name = "Num")
public int Num;
#Element(name = "X")
public int X;
#Element(name = "Y")
public int Y;
#Element(name = "Width")
public int Width;
#Element(name = "Height")
public int Height;
#Element(name = "OffSetX")
public int OffsetX;
#Element(name = "OffSetY")
public int OffsetY;
#Element(name = "Duration")
public float Duration;
public Frame()
{
super();
}
public Frame(int num, int x, int y, int width, int height,int offsetx,int offsety, int duration )
{
this.Num = num;
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
this.OffsetX = offsetx;
this.OffsetY = offsety;
this.Duration = duration;
}
}
// Animaiton class to hold the name and frames
public class Animation
{
#Element(name = "Name")
public String Name;
#Element(name = "FrameRate")
public int FrameRate;//may need elementarray or list???
#Element(name = "Loop")
public boolean Loop;
#Element(name = "Pingpong")
public boolean Pingpong;
#ElementArray(name = "Frames")
public Frame[] Frames;
public Animation()
{
super();
}
public Animation(String name, int framerate, boolean loop, boolean pingpong, Frame[] frames)
{
this.Name = name;
this.FrameRate = framerate;
this.Loop = loop;
this.Pingpong = pingpong;
this.Frames = frames;
}
}
// The Sprite Texture stores the Sprite Sheet path.fr
public class SpriteTexture
{
// The Sprite Sheet texture file path
#Element(name = "path")
public String Path;
public SpriteTexture()
{
super();
}
public SpriteTexture(String path)
{
this.Path = path;
}
}
// Aniamtion Set contains the Sprite Texture and Animaitons.
#Root(name = "Animations")
public static class XNAAnimationSet
{
// The sprite texture object
#Element(name = "Texture")
public SpriteTexture SpriteTexture;
// The animation array in the Animation Set
#ElementArray(name = "Animation")
public Animation[] Animations;
public XNAAnimationSet()
{
super();
}
public XNAAnimationSet(SpriteTexture spritetexture, Animation[] animations)
{
this.SpriteTexture = spritetexture;
this.Animations = animations;
}
}
// Sprite Animation Manager class
public final static class SpriteAnimationManager
{
private static final String XNAAnimationSet = null;//was static private static
public static int AnimationCount;
// Read the Sprite Sheet Description information from the description xml file
public static XNAAnimationSet Read(String filename) throws Exception
{
XNAAnimationSet animationSet = new XNAAnimationSet();
Serializer serializer = new Persister();
try {
animationSet = serializer.read(XNAAnimationSet.class, filename );
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
// Count the animations to Animation Count
AnimationCount = animationSet.Animations.length;
return animationSet;
}
}
}
I've been trying to see what's being read by trying to write the class to a file. The file is created but it's empty.
Can someone tell me if I've annotated this correctly? What am I doing wrong?
I was using jaxb there the last day to parse my xml, I'm not sure how similiar it is to the way your doing it but ill mention a few of the things i needed:
firstly, i think i needed a no-arg constructor in my class, which for you would just be -
public Frame(){};
I believe you do need getters, what you've got there arent getters/setters, your just declaring variables, this really is fundamental java stuff so it might be worth a read up on that before you continue.
When you have your getters defined properly, you then put the #XMLElement annotation above each of them, not above your variable declarators.
A getter looks like:
#XMLElement
public string getName(){ return this.Name};
Also id recommend trying to parse one class at a time, you have multiple inner classes here which i'd imagine gets messy when your trying to parse, i think you need to have #RootElement above the class name declarator, so the xml knows what type of object your creating.
Anyway, there's a few things off the top of my head, best of luck with it!
I'm experiencing a nullpointerexception in my android java code in the following code. This is inside AndroidGraphics.java.
public void drawPixmap(Pixmap pixmap, int x, int y) {
canvas.drawBitmap(((AndroidPixmap)pixmap).bitmap, x, y, null);
}
AndroidPixmap.java is here:
package com.badlogic.androidgames.framework.impl;
import android.graphics.Bitmap;
import com.badlogic.androidgames.framework.Graphics.PixmapFormat;
import com.badlogic.androidgames.framework.Pixmap;
public class AndroidPixmap implements Pixmap{
Bitmap bitmap;
PixmapFormat format;
public AndroidPixmap(Bitmap bitmap, PixmapFormat format){
this.bitmap = bitmap;
this.format = format;
}
#Override
public int getWidth(){
return bitmap.getWidth();
}
#Override
public int getHeight(){
return bitmap.getHeight();
}
#Override
public PixmapFormat getFormat(){
return format;
}
#Override
public void dispose(){
bitmap.recycle();
}
}
Is there something wrong with the casting? Any help would be great!
EDIT: This is the pixmap class:
package com.badlogic.androidgames.framework;
import com.badlogic.androidgames.framework.Graphics.PixmapFormat;
public interface Pixmap {
public int getWidth();
public int getHeight();
public PixmapFormat getFormat();
public void dispose();
}
Your AndroidPixmap implements Pixmap, it is not inherited/extended from Pixmap. If you cast to Pixmap, you get the Implementation only, which I assume has bitmap=null.
As you didn't add the Pixmap class to the question, it's quite hard to answer in more detail.
Try this:
public void drawPixmap(AndroidPixmap pixmap, int x, int y) {
canvas.drawBitmap(pixmap.bitmap, x, y, null);
}
Alternatively if you want to keep Pixmap in the signature you can make it an abstract class and extend it instead of an interface.