aChartEngine; determining when a GraphicalView is fully rendered/drawn - android

I've got a fragment, which I construct and insert a GraphicalView, and I need to know when the GraphicalView (chart) is done being drawn. the api isChartDrawn always returns false, including within onResume of the containing fragment.
public void onResume()
{
Log.d(TAG, "onResume, the mChart isDrawn: " + mChart.isChartDrawn());
super.onResume();
mListener.didNotificyChartDrawn();
}
Is there a notification I'm not seeing, or strategy for knowing when the chart is done being rendered? I'm asking because I need to access the series points from within one of the series of the XYChart used to construct the graphical view, like this:
mChart = new GraphicalView(getActivity(), mXYChart);
where mXYChart is an instance of the LineChart.
The graph renders fine, and I'm able to access the points I need later on via touch handling, just need to get to them a little earlier now and am hitting this issue. Any work arounds, etc, appreciated.

you're getting that because during onResume still was not draw yet. That's whole Android, not just aChartEngine. I'm not sure it's the best design decision, but that's how it is.
But good news is: there's a nice trick.
getView().getViewTreeObserver().addOnDrawListener(new OnDrawListener(){
void onDraw(){
getView().getViewTreeObserver().removeOnDrawListener(this);
// do your stuff here
}
});
this trick is used A LOT for animation, so you can measure stuff on screen and do the proper animations.

If you look at the onDraw method in GraphicalView, it sets the boolean mDrawn to true at the very end. So what must be happening is you are calling
public boolean isChartDrawn() {
return mDrawn;
}
Before it has completed the onDraw method. I would either create a interval handler to keep checking if mDrawn has been changed to true, or modify the library file GraphicalView so that it has an optional listener that you can attach to be fired off when the thing is drawn:
DrawnInterface mCallback;
public interface DrawnInterface{
public void onDrawn();
}
.....
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.getClipBounds(mRect);
......
canvas.drawBitmap(fitZoomImage, left + width - zoomSize * 0.75f, buttonY, null);
}
mDrawn = true;
mCallback.onDrawn();
}
Then make your calling activity implement the DrawnInterface you defined, and initialize the interface inside the constructor of GraphicalView

Related

How to listen for Android View transformation change?

I am creating a custom View and I would like to listen for the transformation changes. For example, the ones triggered by View#setScaleX. One way to do it is overriding all the methods:
setTranslationX
setTranslationY
setTranslationZ
setElevation
setRotation
setRotationX
setRotationY
setScaleX
setScaleY
setPivotX
setPivotY
setCameraDistance
setAnimationMatrix
Am I missing anything? I don't care for the top/left/bottom/right properties so they are left out intentionally. However this is cumbersome. It would be better if I can just get a callback and listen for it. Is that possible?
//Make some kind of callback
public interface TransformationCallback{
//String whatWho is an example it can be anything.
void onTransform(String whatWho);
}
public class YourView extends View{
private TransformationCallback callback;
//Pass an interface into the View constructor
public YourView(Context context, TransformationCallback callback){
super(context);
this.callback = callback;
}
}
#Override
public void setTranslationX(float x){
//call onTransform from the callback
callback.onTransform("setTranslationX was called");
super.setTranslationX(x);
}
The only problem with this, is it will not detect internal changes to the underlining values that these functions "set".
For example there is a variable inside View called protected int mLeft; Which is modified multiple times, internally not using functions.
The variable is also protected meaning abstractions of View can also modify it without function calls.
For the most part only external classes that mess with Views will use those functions which may or may not effect you.

OpenGL ES and Thread Structure

I have the following (simplified) rig so far:
MyActivity.java:
public class MyActivity extends Activity {
public GLSurfaceView myGLView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myGLView = new MyGLSurfaceView(this);
setContentView(myGLView);
}
}
MyGLSurfaceView.java:
public class MyGLSurfaceView extends GLSurfaceView {
private MyRenderer mMyRenderer = new MyRenderer();
private MyThread mMyThread = new MyThread();
public MyView(Context context) {
super(context);
setRenderer(mGameRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
mGameThread.setRunning(true);
}
}
MyRenderer.java:
public class GameRenderer implements GLSurfaceView.Renderer {
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// ...
}
}
MyThread.java:
Here I'm doing all initializations, creating objects and so on.
public class MyThread extends Thread {
private MyObject mMyObject = new MyObject();
public MyThread {
// ...
mMyObject.setRot();
this.start();
}
public void run() {
// Fixed Timestep Loop goes here
mMyObject.getRot();
}
}
MyObject.java:
This is a sample object which holds different fileds and methods.
public class MyObject {
private double mRot;
// Getters & Setters
protected double getRot() { return mRot; }
protected void setRot() {
// ... Do calculations
}
public void draw() {
// OGL Instructions go here
gl.glRotatef(1.2f, 0, 0, setRot());
}
}
Now the problem I was running into is the following: (I guess, I missed something very basic and simple :) )
As stated above, I'm creating my object instances in the MyThread class. The Thread is created in the MyGLSurface class, same goes for the Renderer. Now, that I have that two threads I can't figure out, how to use that one instance and their methods in that two separate threads.
I tried different approaches, but nothing did work. So in my opinion I made a mistake in the class design. I mean, I don't just want to get it running (that'd be quite easy), but I want to know how to do it correctly.
The main problem is actually that I can't access the MyObject's instance and simply use the draw() method in the renderer - because I don't get it.
I thought, it would be possible to call the draw() method of MyObject within the rendering thread without the need of using a singleton and so on. So simply referencing the instance to it. But somehow that seemed weird and dirty (besides that it doesn't work for me).
I tried dozens of different approaches, but I really need a bump into the right direction. I'm quite familar with OOP, but here I might really miss something.
In that many samples I found on the web (stackoverflow, Replica Island, different tutorial sites, Google I/O, DevCentral, etc.) they either didn't use a multithreaded system or they split it directly (GL objects from regular objects).
Any hint into the right direction would be much appreciated!
Another example to peruse:
https://code.google.com/p/android-breakout/
The wiki and code comments discuss the threading issues inherent in using GLSurfaceView. In particular, the game does as much setup as it can before the Renderer thread starts; once it's running, as much work as possible is done on that thread. The game state objects are effectively "owned" by the renderer thread, and the Activity is owned by the UI thread, so any "off-thread" interactions are handled by sending messages rather than making direct method calls. For example, see the handling of touch events.
It's good that you're thinking about this -- you either need synchronization or careful object discipline to avoid nasty race conditions.
See also: android game loop vs updating in the rendering thread
The nice thing about GLSurfaceView is that it creates the OpenGL rendering thread for you, so you don't need to create one yourself. The main UI thread will call the OnDraw() method in your view class and that's all the threads you need. If you really want to create your own thread for OpenGL rendering, use TextureView instead of GLSurfaceView. Here is an article that I think will help:
http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1

Android Service communcation

I'm writing an application which run a background Service which communicate with a remote server.
when the server sends me a new message, i need to update an object which is represent in the UI and then to update the UI View to represent the new state of the object (for example if the object's background propery is true - set the background of the View to green and if false set the background of the view to red).
I'm using a list view to show all an ArrayList of all those objects throw an ArrayAdapter.
I have an Application object (named app) for static reference and i have there a CurrentActivity property which store the current activity running (or null if the UI is closed).
i'm using this code to update the UI:
in my Service:
onNewMessage(boolean backgruond)
{
if (app.getCurrentActivity != null)
app.getCurrentActivity.onNewMessage(background);
}
in my Activity:
onNewMessage(boolean background)
{
object.setBackground(bacground);
Log.d("Background", String.valueof(background));
runOnUiThread(new Runnable() {
#Override
public void run()
{
arrayAdapter.notifyDataSetChanged();
}
});
}
and although the Log returns the right background state, the view isn't refreshing with the notifyDataSetChanged();
i've tried to send message to Activity throw BroadcastRecevier but it much more complicated because i have lots of messages coming from the server and i will have to register many receivers.
And besides - i don't understand why would the recevier work and this mechanism wont..
example of working method which updates the ListView:
ListViewActivity - inheritance from BaseActivity:
#Override
public void onUnFriend(FacebookUser facebookUser, boolean isYouRemovedClient)
{
super.onUnFriend(facebookUser, isYouRemovedClient);
updateView();
}
BaseActivity (the super class which extends Activity):
public void onUnFriend(FacebookUser facebookUser, boolean isYouRemovedClient)
{
facebookUser.setApplicationFriend(false);
app.getApplicationFriends().remove(facebookUser);
app.getDatabaseManager().deleteApplicationFriend(facebookUser.getId());
if (isYouRemovedClient)
app.showToast(facebookUser.getName() + " has removed from your friends", true);
else
app.showToast(facebookUser.getName() + " has removed you from friends", true);
}
this one works and does change the background color in the ListView.
not working example
ListViewActivity:
#Override
public void onFriendRequestAccepted(FacebookUser facebookUser, boolean showDialog) {
super.onFriendRequestAccepted(facebookUser, showDialog);
updateView();
}
BaseActivity:
public void onFriendRequestAccepted(FacebookUser facebookUser, boolean showDialog)
{
facebookUser.setApplicationFriend(true);
app.getApplicationFriends().add(facebookUser);
app.getDatabaseManager().addApplicationFriend(facebookUser);
if (showDialog)
app.showNewEventActivity(facebookUser, EventDialogManager.EVENT_FRIEND_ACCEPTED);
}
no update is made... i can't really understand why..
i have there a CurrentActivity property which store the current activity running (or null if the UI is closed)
I do not recommend this practice. It relies upon you consistently and reliably updating that Application data member, and it increases the coupling between your service and your UI.
and although the Log returns the right background state, the view isn't refreshing with the notifyDataSetChanged();
It would appear that you did not change the data in the adapter. Certainly, there is no evidence in the code that you have here that you updated the data in the adapter.
BTW, neither of the code snippets you have shown here are likely to compile (first is not valid Java, second has a typo).
i have lots of messages coming from the server and i will have to register many receivers
No, you will have to register one receiver, and in onReceive(), use an if statement (or perhaps a switch, if you prefer) to distinguish one message from another.
In addition to what CommonsWare said, I assume that object in the first line of your onNewMessage is the view. setBackround accepts an int parameter, not a boolean.
Use 0xFF00FF00 for green and 0xFFFF0000 for red.
By the way, it's a very bad practice to keep static references of Context objects and it's derived classes (Application and Activity both derive from Context, and keeping a static reference of them may lead to serious memory leaks. Read more here.)
Use a BroadcastReceiver instead. They are much more simple comparing to how you described them - you only need one.

android measuring angle

I know a good amount of java but this is my first time programming with the android sdk. I need to get the rotation of the phone in real time and display it on the screen. I was wondering what sensor method to use, as I heard that getOrientation was processor intensive and may not work in real time. Secondly, I was wondering which class I'd right this program in, I don't quite understand android class hierarchy yet. Thirdly, how would I make the numbers change on the screen in real time?
Thanks for the help!
I was wondering what sensor method to use, as I heard that getOrientation was processor intensive and may not work in real time.
You'll want to have a look at the OrientationEventListener object.
Secondly, I was wondering which class I'd right this program in, I don't quite understand android class hierarchy yet.
To get you started, you could build all this code into an Activity. Unlike a traditional Java program there is no main() entry point method and you won't user the constructors of application component classes to instantiate them. Lifecycle callback methods like onCreate() and onDestroy() are where you will want to do initialization and teardown of instance information. This guide may help you in how to construct your application to use a single Activity.
Thirdly, how would I make the numbers change on the screen in real time? Thanks for the help!
The OrientationEventListener includes a callback method for each change, simply use this callback to update a view in your UI.
Here is a simple example pulling it all together:
public class OrientationActivity extends Activity {
private OrientationEventListener mListener;
private TextView mTextView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = new TextView(this);
setContentView(mTextView);
mListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_UI) {
#Override
public void onOrientationChanged(int orientation) {
mTextView.setText(String.valueOf(orientation);
}
};
}
#Override
public void onResume() {
super.onResume();
mListener.enable();
}
#Override
public void onPause() {
super.onPause();
mListener.disable();
}
}

How can I pass an int to my onDraw(Canvas canvas) in Android?

I use a surfaceview to draw a pie chart in Android. In order to know how big the pie slice should be I need to pass a parameter to the onDraw() method. How can I do this? Inside the onDraw() I make a query to a datahelper-class that fetches the right data.
I tried to call a static function in one Activity from the onDraw, and which function returned an integer. But I want something more dynamic, so I can send the integers I need to from the Activity to the onDraw and just get the result in form of a pie chart.
Any suggestions?
One of solutions can be like this:
public class MySurfaceView extends SurfaceView
{
private MyParameter parameter;
public void setParameter(MyParameter parameter)
{
this.parameter=parameter;
}
#Override
public void onDraw(Canvas canvas)
{
if(this.parameter==null)
return; //nothing to draw...
//draw here...
}
}
//somewhere in code
MySurfaceView sView=(SurfaceView )findViewById(R.id.pie_chart);
//
sView.setParameter(new MyParameter(100,2000, false));
}

Categories

Resources