Implementing Parcelable for a custom 2D array - android

In order to pass my 2D array in a new activity, I came up with the approach to wrap it and implement the Parcelable interface. Unfortunately, when I use Intent.getParcelableExtra i get java.lang.NullPointerException, which means that I am most certainly not implementing the interface right. Below is my Updated code
public class MazeMapParcelable implements Parcelable
{
private Cell[][] mazeMap;
public MazeMapParcelable(Cell[][] mazeMap)
{
this.mazeMap = mazeMap;
}
public Cell[][] getMazeMap()
{
return this.mazeMap;
}
public static final Parcelable.Creator<MazeMapParcelable> CREATOR
= new Creator<MazeMapParcelable>() {
public MazeMapParcelable createFromParcel(Parcel in)
{
return new MazeMapParcelable(in);
}
public MazeMapParcelable[] newArray(int size)
{
return new MazeMapParcelable[size];
}
};
public void writeToParcel(Parcel dest, int flags)
{
int width = mazeMap.length;
dest.writeInt(width);
int height = mazeMap[1].length;
dest.writeInt(height);
for(int i=0;i<width;i++)
{
for(int j=0;j<height;j++)
{
dest.writeInt(mazeMap[i][j].getCordX());
dest.writeInt(mazeMap[i][j].getCordY());
dest.writeByte((byte) (mazeMap[i][j].getNorthWall() ? 1 : 0));
dest.writeByte((byte) (mazeMap[i][j].getSouthWall() ? 1 : 0));
dest.writeByte((byte) (mazeMap[i][j].getEastWall() ? 1 : 0));
dest.writeByte((byte) (mazeMap[i][j].getWestWall() ? 1 : 0));
}
}
}
public int describeContents()
{
return 0;
}
public MazeMapParcelable[] newArray(int size)
{
return new MazeMapParcelable[size];
}
private MazeMapParcelable(Parcel in)
{
int width = in.readInt();
int height = in.readInt();
Cell[][] recreatedMazeMap = new Cell[width][height];
for(int i=0;i<width;i++)
{
for(int j=0;j<height;j++)
{
int cordX = in.readInt();
int cordY = in.readInt();
boolean northWall = in.readByte() != 0;
boolean southWall = in.readByte() != 0;
boolean westWall = in.readByte() != 0;
boolean eastWall = in.readByte() != 0;
Cell currCell = new Cell(cordX,cordY,northWall,southWall,westWall,eastWall);
recreatedMazeMap[i][j] = currCell;
}
}
mazeMap = recreatedMazeMap;
}
Note that my Cell class members are:
protected int x;
protected int y;
private boolean northWall;
private boolean southWall;
private boolean westWall;
private boolean eastWall;
private boolean bomb;
private boolean deadEnd;
Update I no longer get Null pointer exception, but my data are not written properly as they should. (parceableMazeMap[0][0] != originalMazeMap[0][0])

Perhaps you want to look into using writeTypedArray(). If you implement Parcelable in your Cell object, you can use writeTypedArray() to save them to the Parcel.
When the parcelable is attempting to recreate your instance, it calls this constructor:
private MazeMapParcelable(Parcel in){
...
}
But you've never actually initialized your array at this point. So it will still be in this state (which is null):
private Cell[][] mazeMap;
Since mazeMap at this state is not initialized, it will have no length. So this code will not give you the values you expect:
int width = this.mazeMap.length;
int height = this.mazeMap[1].length;
Try writing the width & height values as the first items in the parcelable, and then reading them when you're recreating the parcelable.

Related

Android measure view visible area

I have been searching a lot of similar answer from here, but none can work accurately. I want to calculate the visible area of a custom view, the view can be blocked by the screen edge, or block by the edge of scroll view, let see the picture below:
As above, black color is my screen, red color is my custom view and scroll up a bit, I want to measure area of B.
As above, black color is my screen, red color is my custom view, blue color is scroll view. Custom view is child of the scroll view and it is scroll up a bit. I want to measure area of B.
1) I have tried, View.getWindowVisibleDisplayFrame, View.getLocalVisibleRect, View.getGlobalVisibleRect, but none of it work accurately. First glance they looks good, but when I scroll my view disappear from screen, somehow, it show me the full height and width of the view, which the view is not even displayed within the screen.
2) I tried View.getLocationOnScreen() and getLocationInWindow() to calculate the offset manually, get XY coordination and plus/minus the view's (and screen) height and width, but found it not easy too, because the top of screen always have extra menu bar or etc, and will mess out with the result.
3) Although this is not likely in my situation, I want to know, if there is a absolute layout on top of my view and partially block it, can I still find out the area? (both layout are in same activity)
My question is, is there any easy and accurate way to calculate the area I want?
Ok, I found the answer from one of the open source Ad framework:
/**
* Whether the view is at least certain % visible
*/
boolean isVisible(#Nullable final View rootView, #Nullable final View view, final int minPercentageViewed) {
// ListView & GridView both call detachFromParent() for views that can be recycled for
// new data. This is one of the rare instances where a view will have a null parent for
// an extended period of time and will not be the main window.
// view.getGlobalVisibleRect() doesn't check that case, so if the view has visibility
// of View.VISIBLE but it's group has no parent it is likely in the recycle bin of a
// ListView / GridView and not on screen.
if (view == null || view.getVisibility() != View.VISIBLE || rootView.getParent() == null) {
return false;
}
if (!view.getGlobalVisibleRect(mClipRect)) {
// Not visible
return false;
}
// % visible check - the cast is to avoid int overflow for large views.
final long visibleViewArea = (long) mClipRect.height() * mClipRect.width();
final long totalViewArea = (long) view.getHeight() * view.getWidth();
if (totalViewArea <= 0) {
return false;
}
return 100 * visibleViewArea >= minPercentageViewed * totalViewArea;
}
I made a mistake while I am using View.getGlobalVisibleRect, when the view disappear from the screen, this method will return false, although the mClipRect object still providing value. Above is the correct way in using it.
During implementing a new feature "ViewHierarchy" in my work at Instabug I face the same problem and fix this problem through the below code
This is util class that does all the logic
public class ViewFrameInspector {
private static final String KEY_X = "x";
private static final String KEY_Y = "y";
private static final String KEY_W = "w";
private static final String KEY_H = "h";
/**
* Method emit inspected ViewFrame of passed view, the emit ViewFrame contains inspected ViewFrames fot its children and children of the children and so on
* by converting the emitted ViewFrame to list of View Frames you can find the a specific view and its frame with easily way
*
* #param view the root view
* #return return ViewFrame observable
*/
public static Observable<ViewFrame> inspectRootViewFrameRx(final View view) {
return Observable.defer(new Func0<Observable<ViewFrame>>() {
#Override
public Observable<ViewFrame> call() {
ViewFrame rootViewFrame = new ViewFrame();
rootViewFrame.setRoot(true);
rootViewFrame.setView(view);
return Observable.just(inspectVisibleViewFrame(rootViewFrame));
}
});
}
private static ViewFrame inspectVisibleViewFrame(final ViewFrame viewFrame) {
if (viewFrame.getView().getVisibility() == View.VISIBLE)
try {
viewFrame.setId(inspectViewResourceId(viewFrame.getView().getContext(), viewFrame.getView().getId()));
viewFrame.setType(ViewFrameInspector.inspectViewType(viewFrame.getView()));
viewFrame.setOriginalRect(ViewFrameInspector.inspectViewOriginalRect(viewFrame.getView()));
viewFrame.setVisibleRect(ViewFrameInspector.inspectViewVisibleRect(viewFrame));
viewFrame.setFrame(ViewFrameInspector.inspectViewFrame(viewFrame));
// inspect view children if exist
if (viewFrame.getView() instanceof ViewGroup) {
viewFrame.setHasChildren(true);
inspectViewChildren(viewFrame);
} else {
viewFrame.setHasChildren(false);
}
} catch (JSONException e) {
Log.e(ActivityViewInspector.class.getSimpleName(), "inspect view frame got error: " + e.getMessage() + ",view id:" + viewFrame.getId() + ", time in MS: " + System.currentTimeMillis(), e);
}
return viewFrame;
}
private static void inspectViewChildren(ViewFrame parentViewFrame) throws JSONException {
if (parentViewFrame.getView() instanceof ViewGroup) {
ViewGroup parent = (ViewGroup) parentViewFrame.getView();
for (int i = 0; i < parent.getChildCount(); i++) {
ViewFrame childViewFrame = new ViewFrame();
childViewFrame.setRoot(false);
childViewFrame.setView(parent.getChildAt(i));
childViewFrame.setParent(parentViewFrame);
parentViewFrame.addNode(inspectVisibleViewFrame(childViewFrame));
}
}
}
private static String inspectViewType(View view) {
return view.getClass().getSimpleName();
}
private static String inspectViewResourceId(Context context, int id) throws JSONException {
try {
return context != null && context.getResources() != null && context.getResources().getResourceEntryName(id) != null ?
context.getResources().getResourceEntryName(id) : String.valueOf(id);
} catch (Resources.NotFoundException e) {
return String.valueOf(id);
}
}
private static Rect inspectViewOriginalRect(View view) {
int[] locationOnScreen = new int[2];
view.getLocationOnScreen(locationOnScreen);
return new Rect(locationOnScreen[0],
locationOnScreen[1],
locationOnScreen[0] + view.getWidth(),
locationOnScreen[1] + view.getHeight());
}
private static Rect inspectViewVisibleRect(ViewFrame viewFrame) {
if (viewFrame.isRoot()) {
return viewFrame.getOriginalRect();
} else {
Rect viewVisibleRect = new Rect(
viewFrame.getOriginalRect().left,
viewFrame.getOriginalRect().top,
viewFrame.getOriginalRect().right,
viewFrame.getOriginalRect().bottom);
Rect parentAvailableVisibleRect = new Rect(
inspectViewAvailableX(viewFrame.getParent()),
inspectViewAvailableY(viewFrame.getParent()),
inspectViewAvailableRight(viewFrame.getParent()),
inspectViewAvailableBottom(viewFrame.getParent()));
if (viewVisibleRect.intersect(parentAvailableVisibleRect)) {
return viewVisibleRect;
} else {
return new Rect(0, 0, 0, 0);
}
}
}
private static int inspectViewAvailableX(ViewFrame viewFrame) {
int visibleLeft, paddingLeft, originalLeft;
visibleLeft = viewFrame.getVisibleRect().left;
paddingLeft = viewFrame.getView().getPaddingLeft();
originalLeft = viewFrame.getOriginalRect().left;
if (paddingLeft == 0) {
return visibleLeft;
} else {
if (visibleLeft > (originalLeft + paddingLeft)) {
return visibleLeft;
} else {
return originalLeft + paddingLeft;
}
}
}
private static int inspectViewAvailableY(ViewFrame viewFrame) {
int visibleTop, paddingTop, originalTop;
visibleTop = viewFrame.getVisibleRect().top;
paddingTop = viewFrame.getView().getPaddingTop();
originalTop = viewFrame.getOriginalRect().top;
if (paddingTop == 0) {
return visibleTop;
} else {
if (visibleTop > (originalTop + paddingTop)) {
return visibleTop;
} else {
return originalTop + paddingTop;
}
}
}
private static int inspectViewAvailableRight(ViewFrame viewFrame) {
int visibleRight, paddingRight, originalRight;
visibleRight = viewFrame.getVisibleRect().right;
paddingRight = viewFrame.getView().getPaddingRight();
originalRight = viewFrame.getOriginalRect().right;
if (paddingRight == 0) {
return visibleRight;
} else {
if (visibleRight < (originalRight - paddingRight)) {
return visibleRight;
} else {
return originalRight - paddingRight;
}
}
}
private static int inspectViewAvailableBottom(ViewFrame viewFrame) {
int visibleBottom, paddingBottom, originalBottom;
visibleBottom = viewFrame.getVisibleRect().bottom;
paddingBottom = viewFrame.getView().getPaddingBottom();
originalBottom = viewFrame.getOriginalRect().bottom;
if (paddingBottom == 0) {
return visibleBottom;
} else {
if (visibleBottom < (originalBottom - paddingBottom)) {
return visibleBottom;
} else {
return originalBottom - paddingBottom;
}
}
}
private static JSONObject inspectViewFrame(ViewFrame viewFrame) throws JSONException {
return new JSONObject().put(KEY_X, viewFrame.getVisibleRect().left)
.put(KEY_Y, viewFrame.getVisibleRect().top)
.put(KEY_W, viewFrame.getVisibleRect().width())
.put(KEY_H, viewFrame.getVisibleRect().height());
}
public static List<ViewFrame> convertViewHierarchyToList(ViewFrame viewFrame) {
ArrayList<ViewFrame> viewFrameHierarchies = new ArrayList<>();
if (viewFrame != null) {
viewFrameHierarchies.add(viewFrame);
if (viewFrame.hasChildren()) {
for (ViewFrame childViewHierarchy : viewFrame.getNodes()) {
viewFrameHierarchies.addAll(convertViewHierarchyToList(childViewHierarchy));
}
}
}
return viewFrameHierarchies;
}
}
This is model class that hold all data related to inspected views
public class ViewFrame {
private String id;
private String type;
private JSONObject frame;
private ViewFrame parent;
private ArrayList<ViewFrame> nodes;
private boolean hasChildren;
private boolean isRoot;
private Rect originalRect;
private Rect visibleRect;
private View view;
public ViewFrame() {
nodes = new ArrayList<>();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public JSONObject getFrame() {
return frame;
}
public void setFrame(JSONObject frame) {
this.frame = frame;
}
public ViewFrame getParent() {
return parent;
}
public void setParent(ViewFrame parent) {
this.parent = parent;
}
public ArrayList<ViewFrame> getNodes() {
return nodes;
}
public void addNode(ViewFrame childViewHierarchy) {
nodes.add(childViewHierarchy);
}
public boolean hasChildren() {
return hasChildren;
}
public void setHasChildren(boolean hasChildren) {
this.hasChildren = hasChildren;
}
public boolean isRoot() {
return isRoot;
}
public void setRoot(boolean root) {
isRoot = root;
}
public Rect getVisibleRect() {
return visibleRect;
}
public void setVisibleRect(Rect visibleRect) {
this.visibleRect = visibleRect;
}
public Rect getOriginalRect() {
return originalRect;
}
public void setOriginalRect(Rect originalRect) {
this.originalRect = originalRect;
}
public View getView() {
return view;
}
public void setView(View view) {
this.view = view;
}
}
Hope this code help you also

How to populate pool with different types of sprites in AndEngine?

I am new to Android AndEngine game development. I am developing a game in which i am using GenericPool to load multiple spites on the screen. Problem is that these sprites are of same type.I want to load different type of sprites. After some research i got the idea of using Multipool but do n't know how to use it in my code.
Here is my code :
public class Enemy {
public Sprite sprite;
public int hp;
// the max health for each enemy
protected final int MAX_HEALTH = 2;
Camera mCamera;
BaseActivity activity = BaseActivity.getSharedInstance();
public Enemy() {
sprite = new Sprite(32, 32, BaseActivity.getSharedInstance().mBirdTextureRegion,
BaseActivity.getSharedInstance().getVertexBufferObjectManager());
init();
}
// method for initializing the Enemy object , used by the constructor and
// the EnemyPool class
public void init() {
hp = MAX_HEALTH;
mCamera = activity.mCamera;
}
public void clean() {
sprite.clearEntityModifiers();
sprite.clearUpdateHandlers();
}
// method for applying hit and checking if enemy died or not
// returns false if enemy died
public boolean gotHit() {
synchronized (this) {
hp--;
if (hp <= 0)
return false;
else
return true;
}
}
public class EnemyLayer extends Entity {
private LinkedList<Enemy> enemies;
public static EnemyLayer instance;
public int enemyCount;
public static EnemyLayer getSharedInstance() {
return instance;
}
public static boolean isEmpty() {
if (instance.enemies.size() == 0)
return true;
return false;
}
public static Iterator<Enemy> getIterator() {
return instance.enemies.iterator();
}
public void purge() {
detachChildren();
for (Enemy e : enemies) {
EnemyPool.sharedEnemyPool().recyclePoolItem(e);
}
enemies.clear();
}
public EnemyLayer(int x) {
enemies = new LinkedList<Enemy>();
instance = this;
enemyCount = 4;
}
public void restart() {
Log.v("jimvaders", "EnemyLayer restarted");
enemies.clear();
clearEntityModifiers();
clearUpdateHandlers();
for (int i = 0; i < enemyCount; i++) {
Enemy e = EnemyPool.sharedEnemyPool().obtainPoolItem();
float finalPosX = (i % 6) * 2 * e.sprite.getWidth()/2 * 3/2;
float finalPosY = ((int) (i / 6)) * e.sprite.getHeight() * 2;
Random r = new Random();
e.sprite.setPosition(r.nextInt(2) == 0 ? -e.sprite.getWidth() * 3
: BaseActivity.CAMERA_WIDTH + e.sprite.getWidth() * 3,
(r.nextInt(5) + 1) * e.sprite.getHeight());
e.sprite.setVisible(true);
attachChild(e.sprite);
e.sprite.registerEntityModifier(new MoveModifier(1,
e.sprite.getX(), finalPosX, e.sprite.getY(), finalPosY));
enemies.add(e);
}
setVisible(true);
setPosition(50, 30);
MoveXModifier movRight = new MoveXModifier(1, 50, 120);
MoveXModifier movLeft = new MoveXModifier(1, 120, 50);
MoveYModifier moveDown = new MoveYModifier(1, 30, 100);
MoveYModifier moveUp = new MoveYModifier(1, 100, 30);
registerEntityModifier(new LoopEntityModifier(
new SequenceEntityModifier(movRight, moveDown, movLeft, moveUp)));
}
public static void purgeAndRestart() {
Log.v("Birds Shooter", "EnemyLayer PurgeAndRestart()");
instance.purge();
instance.restart();
}
#Override
public void onDetached() {
purge();
clearUpdateHandlers();
super.onDetached();
}
public class EnemyPool extends GenericPool<Enemy> {
public static EnemyPool instance;
public static EnemyPool sharedEnemyPool() {
if (instance == null)
instance = new EnemyPool();
return instance;
}
private EnemyPool() {
super();
}
#Override
protected Enemy onAllocatePoolItem() {
return new Enemy();
}
#Override
protected void onHandleObtainItem(Enemy pItem) {
pItem.init();
}
protected void onHandleRecycleItem(final Enemy e) {
e.sprite.setVisible(false);
e.sprite.detachSelf();
e.clean();
}
}
How can i modify this code to use multiple sprites of different types intead of same type.????? Any help will be appreciated .
You can extend the Sprite class and make new pools using the custom Sprite Object. For example:
public class FlyingEnemy extends Sprite
{
//Class Body Here
}
Once you have overwritten the Sprite class to match your needs you simply extend the generic pool to handle your new Sprites
public class FlyingEnemyPool extends GenericPool<FlyingEnemy>
{
//Class Body Here
}
Then you just use your new pools like normal.

Draw mathematical function with "androidPlot" library

I want to draw math-function like y=x^2+1 with androidPlot library.I have "SimpleXYPlot". It works but I don't know how to change it from sin to my function.
Here's the code:
public class DynamicXYPlotActivity extends Activity {
// redraws a plot whenever an update is received:
private class MyPlotUpdater implements Observer {
Plot plot;
public MyPlotUpdater(Plot plot) {
this.plot = plot;
}
#Override
public void update(Observable o, Object arg) {
plot.redraw();
}
}
private XYPlot dynamicPlot;
private MyPlotUpdater plotUpdater;
SampleDynamicXYDatasource data;
private Thread myThread;
#Override
public void onCreate(Bundle savedInstanceState) {
// android boilerplate stuff
super.onCreate(savedInstanceState);
setContentView(R.layout.dynamicxyplot_example);
// get handles to our View defined in layout.xml:
dynamicPlot = (XYPlot) findViewById(R.id.dynamicXYPlot);
plotUpdater = new MyPlotUpdater(dynamicPlot);
// only display whole numbers in domain labels
dynamicPlot.getGraphWidget().setDomainValueFormat(new DecimalFormat("0"));
// getInstance and position datasets:
data = new SampleDynamicXYDatasource();
SampleDynamicSeries sine1Series = new SampleDynamicSeries(data, 0, "Sine 1");
SampleDynamicSeries sine2Series = new SampleDynamicSeries(data, 1, "Sine 2");
LineAndPointFormatter formatter1 = new LineAndPointFormatter( Color.rgb(0, 0, 0), null, null, null );
formatter1.getLinePaint().setStrokeJoin(Paint.Join.ROUND);
formatter1.getLinePaint().setStrokeWidth(10);
dynamicPlot.addSeries( sine1Series,formatter1 );
LineAndPointFormatter formatter2 = new LineAndPointFormatter(Color.rgb(0, 0, 200), null, null, null);
formatter2.getLinePaint().setStrokeWidth(10);
formatter2.getLinePaint().setStrokeJoin(Paint.Join.ROUND);
//formatter2.getFillPaint().setAlpha(220);
dynamicPlot.addSeries(sine2Series, formatter2);
// hook up the plotUpdater to the data model:
data.addObserver(plotUpdater);
// thin out domain tick labels so they dont overlap each other:
dynamicPlot.setDomainStepMode(XYStepMode.INCREMENT_BY_VAL);
dynamicPlot.setDomainStepValue(5);
dynamicPlot.setRangeStepMode(XYStepMode.INCREMENT_BY_VAL);
dynamicPlot.setRangeStepValue(10);
dynamicPlot.setRangeValueFormat(new DecimalFormat("###.#"));
// uncomment this line to freeze the range boundaries:
dynamicPlot.setRangeBoundaries(-100, 100, BoundaryMode.FIXED);
// create a dash effect for domain and range grid lines:
DashPathEffect dashFx = new DashPathEffect(
new float[] {PixelUtils.dpToPix(3), PixelUtils.dpToPix(3)}, 0);
dynamicPlot.getGraphWidget().getDomainGridLinePaint().setPathEffect(dashFx);
dynamicPlot.getGraphWidget().getRangeGridLinePaint().setPathEffect(dashFx);
}
#Override
public void onResume() {
// kick off the data generating thread:
myThread = new Thread(data);
myThread.start();
super.onResume();
}
#Override
public void onPause() {
data.stopThread();
super.onPause();
}
class SampleDynamicXYDatasource implements Runnable {
// encapsulates management of the observers watching this datasource for update events:
class MyObservable extends Observable {
#Override
public void notifyObservers() {
setChanged();
super.notifyObservers();
}
}
private static final double FREQUENCY = 5; // larger is lower frequency
private static final int MAX_AMP_SEED = 100; //100
private static final int MIN_AMP_SEED = 10; //10
private static final int AMP_STEP = 1;
public static final int SINE1 = 0;
public static final int SINE2 = 1;
private static final int SAMPLE_SIZE = 30;
private int phase = 0;
private int sinAmp = 1;
private MyObservable notifier;
private boolean keepRunning = false;
{
notifier = new MyObservable();
}
public void stopThread() {
keepRunning = false;
}
//#Override
public void run() {
try {
keepRunning = true;
boolean isRising = true;
while (keepRunning) {
Thread.sleep(100); // decrease or remove to speed up the refresh rate.
phase++;
if (sinAmp >= MAX_AMP_SEED) {
isRising = false;
} else if (sinAmp <= MIN_AMP_SEED) {
isRising = true;
}
if (isRising) {
sinAmp += AMP_STEP;
} else {
sinAmp -= AMP_STEP;
}
notifier.notifyObservers();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public int getItemCount(int series) {
return SAMPLE_SIZE;
}
public Number getX(int series, int index) {
if (index >= SAMPLE_SIZE) {
throw new IllegalArgumentException();
}
return index;
}
public Number getY(int series, int index) {
if (index >= SAMPLE_SIZE) {
throw new IllegalArgumentException();
}
double angle = (index + (phase))/FREQUENCY;
double amp = sinAmp * Math.sin(angle);
switch (series) {
case SINE1:
return amp;
case SINE2:
return -amp;
default:
throw new IllegalArgumentException();
}
}
public void addObserver(Observer observer) {
notifier.addObserver(observer);
}
public void removeObserver(Observer observer) {
notifier.deleteObserver(observer);
}
}
class SampleDynamicSeries implements XYSeries {
private SampleDynamicXYDatasource datasource;
private int seriesIndex;
private String title;
public SampleDynamicSeries(SampleDynamicXYDatasource datasource, int seriesIndex, String title) {
this.datasource = datasource;
this.seriesIndex = seriesIndex;
this.title = title;
}
#Override
public String getTitle() {
return title;
}
#Override
public int size() {
return datasource.getItemCount(seriesIndex);
}
#Override
public Number getX(int index) {
return datasource.getX(seriesIndex, index);
}
#Override
public Number getY(int index) {
return datasource.getY(seriesIndex, index);
}
}
}
=======================================================
After what "Nick" said and other minor addition, I got this result:
but as we know :
https://www.google.com/search?q=y%3Dx%5E2%2B1&oq=y%3Dx%5E2%2B1&aqs=chrome..69i57j0l5.7056j0j7&sourceid=chrome&es_sm=93&ie=UTF-8
Now how to make the left side?
Using the code above can modify SampleDynamicXYDatasource to do what you want. All that code does is generate some data in a sine pattern. I don't know how your x values are going to be generated so here's a modified SampleDynamicXYDatasource.getY(...) that just uses the original code where x=index above and uses your function to generate the y-values:
public Number getY(int series, int index) {
if (index >= SAMPLE_SIZE) {
throw new IllegalArgumentException();
}
Number x = getX(series, index);
double y = Math.pow(x.doubleValue(), 2) + 1;
switch (series) {
case SINE1:
return y;
case SINE2:
return -y;
default:
throw new IllegalArgumentException();
}
}
You'll notice that when you make this change, the plot appears to no longer be animated. (it actually still is but that's besides the point) This is because y is now purely a function of x and the x values never change.
As far as how to stop the animation, the plot redraws whenever plot.redraw() is called, which in the example above is in response to an event being continuously fired by events generated by the thread being run on the Runnable instance of SampleDynamicXYDatasource. Using the example above, the simplest way to stop the animation is to replace:
#Override
public void onResume() {
// kick off the data generating thread:
myThread = new Thread(data);
myThread.start();
super.onResume();
}
with:
#Override
public void onResume() {
dynamicPlot.redraw();
super.onResume();
}
Try replace this>>
public Number getX(int series, int index) {
if (index >= SAMPLE_SIZE) {
throw new IllegalArgumentException();
}
return index;
}
To this>>
public Number getX(int series, int index) {
if (index >= SAMPLE_SIZE) {
throw new IllegalArgumentException();
}
return index - 15;
}

Android type mismatch in readFromParcel method

< want to make a parcelable from an Object that contains an Arraylist, But in my readFromParcel method I get the error Type Mismatch: cannot convert from void to ArrayList. What can I do to read my ArrayList properly from my parcel?
edit: With the help of the answers below I now no longer get a type mismatch error, but now I get the message"- Syntax error on token ">", invalid Name - Syntax error on token ">", Expression expected after this token"
edit New errors were resolved when I cleaned the project.
Here's my code
public class Game implements Parcelable{
private ArrayList<Stone> allStones;
public Game(){
allStones = new ArrayList<Stone>();
for(int x=0; x<10; x++) {
for(int y=0; y<10; y++) {
if((x+y)%2 == 1 && y<4){
Stone stone = new Stone(x, y, Stone.WHITE);
allStones.add(stone);
} else if((x+y)%2 == 1 && y>5){
Stone stone = new Stone(x, y, Stone.BLACK);
allStones.add(stone);
}
}
}
}
public Game(Parcel in) {
allStones = new ArrayList<Stone>();
readFromParcel(in);
}
public ArrayList<Stone> getAllStones() {
return allStones;
}
public void removeFromStones(Stone stone) {
allStones.remove(stone);
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(allStones);
}
private void readFromParcel(Parcel in) {
in.readTypedList(allStones, Stone.CREATOR); //This line has the error in it
}
}
And the Stone class
public class Stone implements Parcelable{
private int x, y, color;
private Boolean king;
public static final int BLACK = 0;
public static final int WHITE = 1;
public Stone(int x, int y, int color) {
this.x = x;
this.y = y;
this.color = color;
this.king = false;
}
public Stone(Parcel in) {
readFromParcel(in);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getColor() {
return color;
}
public boolean getKing() {
return king;
}
public void setKing() {
king = true;
}
public void setXY(int x, int y) {
this.x = x;
this.y = y;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(x);
dest.writeInt(y);
dest.writeInt(color);
dest.writeByte((byte) (king ? 1:0));
}
public void readFromParcel(Parcel in) {
x = in.readInt();
y = in.readInt();
color = in.readInt();
king = in.readByte() == 1;
}
public final static Creator<Stone> CREATOR = new Parcelable.Creator<Stone>() {
public Stone createFromParcel(Parcel source) {
return new Stone(source);
}
public Stone[] newArray(int size) {
return new Stone[size];
}
};
}
readTypedList() does not return a value. It puts the list of objects into the list you pass as the first parameter. You code should look like this:
private void readFromParcel(Parcel in) {
in.readTypedList(allStones, Stone.CREATOR); // Should work now
}

Filtering a cursor the right way?

At the moment I need to filter a Cursor/CursorAdapter to only show rows that match a specific condition in the ListView. I don't want to requery the db all the time. I just want to filter the Cursor I got from querying the DB.
I have seen the question: Filter rows from Cursor so they don't show up in ListView
But I don't understand how to do the filtering by overwritting the "move" methods in my CursorWrapper. An example would be nice.
Thank you very much.
UPDATE:
I have rewritten the source and my employer has made it available as open source software: https://github.com/clover/android-filteredcursor
You don't need to override all the move methods in CursorWrapper, you do need to override a bunch though due to the design of the Cursor interface. Let's pretend you want to filter out row #2 and #4 of a 7 row cursor, make a class that extends CursorWrapper and override these methods like so:
private int[] filterMap = new int[] { 0, 1, 3, 5, 6 };
private int mPos = -1;
#Override
public int getCount() { return filterMap.length }
#Override
public boolean moveToPosition(int position) {
// Make sure position isn't past the end of the cursor
final int count = getCount();
if (position >= count) {
mPos = count;
return false;
}
// Make sure position isn't before the beginning of the cursor
if (position < 0) {
mPos = -1;
return false;
}
final int realPosition = filterMap[position];
// When moving to an empty position, just pretend we did it
boolean moved = realPosition == -1 ? true : super.moveToPosition(realPosition);
if (moved) {
mPos = position;
} else {
mPos = -1;
}
return moved;
}
#Override
public final boolean move(int offset) {
return moveToPosition(mPos + offset);
}
#Override
public final boolean moveToFirst() {
return moveToPosition(0);
}
#Override
public final boolean moveToLast() {
return moveToPosition(getCount() - 1);
}
#Override
public final boolean moveToNext() {
return moveToPosition(mPos + 1);
}
#Override
public final boolean moveToPrevious() {
return moveToPosition(mPos - 1);
}
#Override
public final boolean isFirst() {
return mPos == 0 && getCount() != 0;
}
#Override
public final boolean isLast() {
int cnt = getCount();
return mPos == (cnt - 1) && cnt != 0;
}
#Override
public final boolean isBeforeFirst() {
if (getCount() == 0) {
return true;
}
return mPos == -1;
}
#Override
public final boolean isAfterLast() {
if (getCount() == 0) {
return true;
}
return mPos == getCount();
}
#Override
public int getPosition() {
return mPos;
}
Now the interesting part is creating the filterMap, that's up to you.
I was looking for something similar, in my case I wanted to filter items based on a string comparision. I found this gist https://gist.github.com/ramzes642/5400792, which works fine unless you start playing around with the position of the cursor. So I found satur9nine answer, his one respects the position api but just needs some adjustments for filtering based on cursor, so I merged the two. You can change your code to fit it: https://gist.github.com/rfreitas/ab46edbdc41500b20357
import java.text.Normalizer;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.util.Log;
//by Ricardo derfreitas#gmail.com
//ref: https://gist.github.com/ramzes642/5400792 (the position retrieved is not correct)
//ref: http://stackoverflow.com/a/7343721/689223 (doesn't do string filtering)
//the two code bases were merged to get the best of both worlds
//also added was an option to remove accents from UTF strings
public class FilterCursorWrapper extends CursorWrapper {
private static final String TAG = FilterCursorWrapper.class.getSimpleName();
private String filter;
private int column;
private int[] filterMap;
private int mPos = -1;
private int mCount = 0;
public FilterCursorWrapper(Cursor cursor,String filter,int column) {
super(cursor);
this.filter = deAccent(filter).toLowerCase();
Log.d(TAG, "filter:"+this.filter);
this.column = column;
int count = super.getCount();
if (!this.filter.isEmpty()) {
this.filterMap = new int[count];
int filteredCount = 0;
for (int i=0;i<count;i++) {
super.moveToPosition(i);
if (deAccent(this.getString(this.column)).toLowerCase().contains(this.filter)){
this.filterMap[filteredCount] = i;
filteredCount++;
}
}
this.mCount = filteredCount;
} else {
this.filterMap = new int[count];
this.mCount = count;
for (int i=0;i<count;i++) {
this.filterMap[i] = i;
}
}
this.moveToFirst();
}
public int getCount() { return this.mCount; }
#Override
public boolean moveToPosition(int position) {
Log.d(TAG,"moveToPosition:"+position);
// Make sure position isn't past the end of the cursor
final int count = getCount();
if (position >= count) {
mPos = count;
return false;
}
// Make sure position isn't before the beginning of the cursor
if (position < 0) {
mPos = -1;
return false;
}
final int realPosition = filterMap[position];
// When moving to an empty position, just pretend we did it
boolean moved = realPosition == -1 ? true : super.moveToPosition(realPosition);
if (moved) {
mPos = position;
} else {
mPos = -1;
}
Log.d(TAG,"end moveToPosition:"+position);
return moved;
}
#Override
public final boolean move(int offset) {
return moveToPosition(mPos + offset);
}
#Override
public final boolean moveToFirst() {
return moveToPosition(0);
}
#Override
public final boolean moveToLast() {
return moveToPosition(getCount() - 1);
}
#Override
public final boolean moveToNext() {
return moveToPosition(mPos + 1);
}
#Override
public final boolean moveToPrevious() {
return moveToPosition(mPos - 1);
}
#Override
public final boolean isFirst() {
return mPos == 0 && getCount() != 0;
}
#Override
public final boolean isLast() {
int cnt = getCount();
return mPos == (cnt - 1) && cnt != 0;
}
#Override
public final boolean isBeforeFirst() {
if (getCount() == 0) {
return true;
}
return mPos == -1;
}
#Override
public final boolean isAfterLast() {
if (getCount() == 0) {
return true;
}
return mPos == getCount();
}
#Override
public int getPosition() {
return mPos;
}
//added by Ricardo
//ref: http://stackoverflow.com/a/22612054/689223
//other: http://stackoverflow.com/questions/8523631/remove-accents-from-string
//other: http://stackoverflow.com/questions/15190656/easy-way-to-remove-utf-8-accents-from-a-string
public static String deAccent(String str) {
//return StringUtils.stripAccents(str);//this method from apache.commons respects chinese characters, but it's slower than flattenToAscii
return flattenToAscii(str);
}
//ref: http://stackoverflow.com/a/15191508/689223
//this is the fastest method using the normalizer found yet, the ones using Regex are too slow
public static String flattenToAscii(String string) {
char[] out = new char[string.length()];
string = Normalizer.normalize(string, Normalizer.Form.NFD);
int j = 0;
for (int i = 0, n = string.length(); i < n; ++i) {
char c = string.charAt(i);
int type = Character.getType(c);
if (type != Character.NON_SPACING_MARK){
out[j] = c;
j++;
}
}
return new String(out);
}
}
I've compared iterating through cursor 1790 entries against query in cursor with REGEXP and it is 1 min 15 sec against 15 sec.
Use REGEXP - it is much faster.

Categories

Resources