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();
}
}
Related
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
I have a real problem using my app that involve 2 processes. One process its executing a Service (p1) and the other the GUI (p2).
I have a class in p2 that implements the use of an object (iThing) that is custom memory managed (and its static). It has to be like this bacause of Android OS implementation of destroying the views whenever he wants.
public class Connections{
public static int iGlobalCounter=0;
public static Object iThing;
public static void start(){
iGlobalCounter++;
Log.d("PROCESS", "UP: "+iGlobalCounter);
if (iGlobalCounter<=1){
//Create the object "iThing"
}
}
public static int stop(){
iGlobalCounter--;
Log.d("PROCESS", "DOWN: "+iGlobalCounter);
if (iGlobalCounter<=0){
//Destroy the object "iThing"
}
}
}
The main GUI (in p2), starts and stops the variable on the onCreate / onDestroy (for all views in my app)
public class MyMainClass extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Connections.start();
}
#Override
public void onDestroy(){
super.onDestroy();
Connections.stop();
}
}
Finally in p1 I have the service, which also needs the variable, so, it does the same
public class MyMainService extends Service{
#Override
public void onCreate() {
super.onCreate();
Connections.start();
}
#Override
public void onDestroy(){
super.onDestroy();
Connections.stop();
}
}
The problem is that if I use only p2 (GUI), it goes all well, but when I execute the service (in p1), the counter doesn't increment from the last state, but from 0, resulting in destroying the object when leaving the service, not the app.
if do this navigation, I get the following counters:
MyMainClass (1) --> OtherClass (2) --> AnotherClass (3) --> MyMainService (1)
My question is if there is a way of having a multi-process global variable? As it seems that every process takes its own static variables and are not "real static". A solution could be using SharedPreferences to save the state, but not really nice solution, as it hasn't to be saved when leaving the app.
Thanks,
PAU
I think that you should extend Application class and put your globalVariable there.
You can store your global data in shared memory (see MemoryFile).
To synchronize access to the file, I think the best approach is to implement some sort of spinlock using the same memory file.
In and case, I don't know a simply way of doing this.
You have the following options which you can look into for sharing data between different processes,
Message Queue,
Named Pipes,
Memory mapped files
WCF on Named Pipes or MSMQ
I'm familiar with Java but am just starting out Android programming, and don't really know what I need to make things happen. I'm trying to work with a Canvas, I'm basically making an app that reads real-time data and makes a constantly changing graph based off of it, with some buttons and other interactive UI. What are the methods I need to implement? For example, in "regular" Java, I know I would NEED to have
public void init(){//...}
public void paint(Graphics g) {//...}
public void run(){//...}
public static void main (String argv[]) {//...}
//...and more
Based on sample code that I found it seems like I need the following general outline (plus my own miscellaneous functions and classes).
public class MyClass extends Activity{
public void onCreate(Bundle savedInstanceState){//initialization and setup}
public class MySurfaceView extends SurfaceView implements Runnable{
public MySurfaceView(Context context){//constructor}
public void onResumeMySurfaceView(){//???}
public void onPauseMySurfaceView(){//deal with user leaving the activity}
public void run(){//...}
public boolean onTouchEvent(){//...}
}
}
Do I need all of these? What more/else do I need? And, what goes in each of the methods (e.g., where does the stuff I would normally put in paint(Graphics g) go)?
I realize this is a very general question that's kind of big, and would appreciate either tips or a link to a tutorial that is more specific than, say, http://developer.android.com/reference/android/app/Activity.html
http://www.amazon.com/Hello-Android-Introducing-Development-Programmers/dp/1934356565/ref=sr_1_1?ie=UTF8&qid=1309211182&sr=8-1
I would suggest getting a good book like the one above.
I download some data from internet in background thread (I use AsyncTask) and display a progress dialog while downloading. Orientation changes, Activity is restarted and then my AsyncTask is completed - I want to dismiss the progess dialog and start a new Activity. But calling dismissDialog sometimes throws an exception (probably because the Activity was destroyed and new Activity hasn't been started yet).
What is the best way to handle this kind of problem (updating UI from background thread that works even if user changes orientation)? Did someone from Google provide some "official solution"?
Step #1: Make your AsyncTask a static nested class, or an entirely separate class, just not an inner (non-static nested) class.
Step #2: Have the AsyncTask hold onto the Activity via a data member, set via the constructor and a setter.
Step #3: When creating the AsyncTask, supply the current Activity to the constructor.
Step #4: In onRetainNonConfigurationInstance(), return the AsyncTask, after detaching it from the original, now-going-away activity.
Step #5: In onCreate(), if getLastNonConfigurationInstance() is not null, cast it to your AsyncTask class and call your setter to associate your new activity with the task.
Step #6: Do not refer to the activity data member from doInBackground().
If you follow the above recipe, it will all work. onProgressUpdate() and onPostExecute() are suspended between the start of onRetainNonConfigurationInstance() and the end of the subsequent onCreate().
Here is a sample project demonstrating the technique.
Another approach is to ditch the AsyncTask and move your work into an IntentService. This is particularly useful if the work to be done may be long and should go on regardless of what the user does in terms of activities (e.g., downloading a large file). You can use an ordered broadcast Intent to either have the activity respond to the work being done (if it is still in the foreground) or raise a Notification to let the user know if the work has been done. Here is a blog post with more on this pattern.
The accepted answer was very helpful, but it doesn't have a progress dialog.
Fortunately for you, reader, I have created an extremely comprehensive and working example of an AsyncTask with a progress dialog!
Rotation works, and the dialog survives.
You can cancel the task and dialog by pressing the back button (if you want this behaviour).
It uses fragments.
The layout of the fragment underneath the activity changes properly when the device rotates.
I've toiled for a week to find a solution to this dilemma without resorting to editing the manifest file. The assumptions for this solution are:
You always need to use a progress dialog
Only one task is performed at a time
You need the task to persist when the phone is rotated and the progress dialog to be automatically dismisses.
Implementation
You will need to copy the two files found at the bottom of this post into your workspace. Just make sure that:
All your Activitys should extend BaseActivity
In onCreate(), super.onCreate() should be called after you initialize any members that need to be accessed by your ASyncTasks. Also, override getContentViewId() to provide the form layout id.
Override onCreateDialog() like usual to create dialogs managed by the activity.
See code below for a sample static inner class to make your AsyncTasks. You can store your result in mResult to access later.
final static class MyTask extends SuperAsyncTask<Void, Void, Void> {
public OpenDatabaseTask(BaseActivity activity) {
super(activity, MY_DIALOG_ID); // change your dialog ID here...
// and your dialog will be managed automatically!
}
#Override
protected Void doInBackground(Void... params) {
// your task code
return null;
}
#Override
public boolean onAfterExecute() {
// your after execute code
}
}
And finally, to launch your new task:
mCurrentTask = new MyTask(this);
((MyTask) mCurrentTask).execute();
That's it! I hope this robust solution will help someone.
BaseActivity.java (organize imports yourself)
protected abstract int getContentViewId();
public abstract class BaseActivity extends Activity {
protected SuperAsyncTask<?, ?, ?> mCurrentTask;
public HashMap<Integer, Boolean> mDialogMap = new HashMap<Integer, Boolean>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentViewId());
mCurrentTask = (SuperAsyncTask<?, ?, ?>) getLastNonConfigurationInstance();
if (mCurrentTask != null) {
mCurrentTask.attach(this);
if (mDialogMap.get((Integer) mCurrentTask.dialogId) != null
&& mDialogMap.get((Integer) mCurrentTask.dialogId)) {
mCurrentTask.postExecution();
}
}
}
#Override
protected void onPrepareDialog(int id, Dialog dialog) {
super.onPrepareDialog(id, dialog);
mDialogMap.put(id, true);
}
#Override
public Object onRetainNonConfigurationInstance() {
if (mCurrentTask != null) {
mCurrentTask.detach();
if (mDialogMap.get((Integer) mCurrentTask.dialogId) != null
&& mDialogMap.get((Integer) mCurrentTask.dialogId)) {
return mCurrentTask;
}
}
return super.onRetainNonConfigurationInstance();
}
public void cleanupTask() {
if (mCurrentTask != null) {
mCurrentTask = null;
System.gc();
}
}
}
SuperAsyncTask.java
public abstract class SuperAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
protected BaseActivity mActivity = null;
protected Result mResult;
public int dialogId = -1;
protected abstract void onAfterExecute();
public SuperAsyncTask(BaseActivity activity, int dialogId) {
super();
this.dialogId = dialogId;
attach(activity);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mActivity.showDialog(dialogId); // go polymorphism!
}
protected void onPostExecute(Result result) {
super.onPostExecute(result);
mResult = result;
if (mActivity != null &&
mActivity.mDialogMap.get((Integer) dialogId) != null
&& mActivity.mDialogMap.get((Integer) dialogId)) {
postExecution();
}
};
public void attach(BaseActivity activity) {
this.mActivity = activity;
}
public void detach() {
this.mActivity = null;
}
public synchronized boolean postExecution() {
Boolean dialogExists = mActivity.mDialogMap.get((Integer) dialogId);
if (dialogExists != null || dialogExists) {
onAfterExecute();
cleanUp();
}
public boolean cleanUp() {
mActivity.removeDialog(dialogId);
mActivity.mDialogMap.remove((Integer) dialogId);
mActivity.cleanupTask();
detach();
return true;
}
}
Did someone from Google provide some "official solution"?
Yes.
The solution is more of an application architecture proposal rather that just some code.
They proposed 3 design patterns that allows an application to work in-sync with a server, regardless of the application state (it will work even if the user finishes the app, the user changes screen, the app gets terminated, every other possible state where a background data operation could be interrumpted, this covers it)
The proposal is explained in the Android REST client applications speech during Google I/O 2010 by Virgil Dobjanschi. It is 1 hour long, but it is extremely worth watching.
The basis of it is abstracting network operations to a Service that works independently to any Activity in the application. If you're working with databases, the use of ContentResolver and Cursor would give you an out-of-the-box Observer pattern that is convenient to update UI without any aditional logic, once you updated your local database with the fetched remote data. Any other after-operation code would be run via a callback passed to the Service (I use a ResultReceiver subclass for this).
Anyway, my explanation is actually pretty vague, you should definititely watch the speech.
While Mark's (CommonsWare) answer does indeed work for orientation changes, it fails if the Activity is destroyed directly (like in the case of a phone call).
You can handle the orientation changes AND the rare destroyed Activity events by using an Application object to reference your ASyncTask.
There's an excellent explanation of the problem and the solution here:
Credit goes completely to Ryan for figuring this one out.
After 4 years Google solved the problem just calling setRetainInstance(true) in Activity onCreate. It will preserve your activity instance during device rotation. I have also a simple solution for older Android.
you should call all activity actions using activity handler. So if you are in some thread you should create a Runnable and posted using Activitie's Handler. Otherwise your app will crash sometimes with fatal exception.
This is my solution: https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog
Basically the steps are:
I use onSaveInstanceState to save the task if it is still
processing.
In onCreate I get the task if it was saved.
In onPause I discard the ProgressDialog if it is shown.
In onResume I show the ProgressDialog if the task is still
processing.
I was pretty excited to see how easy it is to set up Google Analytics with my app, but the lack of documentation has me sitting with a few questions. The only information that I can find is right from the documentation here, which only looks at reporting PageViews and Events from one Activity. I want to report PageViews and Events across multiple Activities in my app.
Right now in the onCreate() of all of my activities, I am calling:
tracker = GoogleAnalyticsTracker.getInstance();
tracker.start("UA-xxxxxxxxx", this);
And in the onDestroy() of all of my activities:
tracker.stop();
I then track PageViews and Events as needed, and Dispatch them along with another HTTP request I am performing. But I'm not so sure this is the best way. Should I be calling start() and stop() in each activity, or should I only call start() and stop() in my main launcher activity?
The problem with calling start()/stop() in every activity (as suggested by Christian) is that it results in a new "visit" for every activity your user navigates to. If this is okay for your usage, then that's fine, however, it's not the way most people expect visits to work. For example, this would make comparing android numbers to web or iphone numbers very difficult, since a "visit" on the web and iphone maps to a session, not a page/activity.
The problem with calling start()/stop() in your Application is that it results in unexpectedly long visits, since Android makes no guarantees to terminate the application after your last activity closes. In addition, if your app does anything with notifications or services, these background tasks can start up your app and result in "phantom" visits. UPDATE: stefano properly points out that onTerminate() is never called on a real device, so there's no obvious place to put the call to stop().
The problem with calling start()/stop() in a single "main" activity (as suggested by Aurora) is that there's no guarantee that the activity will stick around for the duration that your user is using your app. If the "main" activity is destroyed (say to free up memory), your subsequent attempts to write events to GA in other activities will fail because the session has been stopped.
In addition, there's a bug in Google Analytics up through at least version 1.2 that causes it to keep a strong reference to the context you pass in to start(), preventing it from ever getting garbage collected after its destroyed. Depending on the size of your context, this can be a sizable memory leak.
The memory leak is easy enough to fix, it can be solved by calling start() using the Application instead of the activity instance itself. The docs should probably be updated to reflect this.
eg. from inside your Activity:
// Start the tracker in manual dispatch mode...
tracker.start("UA-YOUR-ACCOUNT-HERE", getApplication() );
instead of
// Start the tracker in manual dispatch mode...
tracker.start("UA-YOUR-ACCOUNT-HERE", this ); // BAD
Regarding when to call start()/stop(), you can implement a sort of manual reference counting, incrementing a count for each call to Activity.onCreate() and decrementing for each onDestroy(), then calling GoogleAnalyticsTracker.stop() when the count reaches zero.
The new EasyTracker library from Google will take care of this for you.
Alternately, if you can't subclass the EasyTracker activities, you can implement this manually yourself in your own activity base class:
public abstract class GoogleAnalyticsActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Need to do this for every activity that uses google analytics
GoogleAnalyticsSessionManager.getInstance(getApplication()).incrementActivityCount();
}
#Override
protected void onResume() {
super.onResume();
// Example of how to track a pageview event
GoogleAnalyticsTracker.getInstance().trackPageView(getClass().getSimpleName());
}
#Override
protected void onDestroy() {
super.onDestroy();
// Purge analytics so they don't hold references to this activity
GoogleAnalyticsTracker.getInstance().dispatch();
// Need to do this for every activity that uses google analytics
GoogleAnalyticsSessionManager.getInstance().decrementActivityCount();
}
}
public class GoogleAnalyticsSessionManager {
protected static GoogleAnalyticsSessionManager INSTANCE;
protected int activityCount = 0;
protected Integer dispatchIntervalSecs;
protected String apiKey;
protected Context context;
/**
* NOTE: you should use your Application context, not your Activity context, in order to avoid memory leaks.
*/
protected GoogleAnalyticsSessionManager( String apiKey, Application context ) {
this.apiKey = apiKey;
this.context = context;
}
/**
* NOTE: you should use your Application context, not your Activity context, in order to avoid memory leaks.
*/
protected GoogleAnalyticsSessionManager( String apiKey, int dispatchIntervalSecs, Application context ) {
this.apiKey = apiKey;
this.dispatchIntervalSecs = dispatchIntervalSecs;
this.context = context;
}
/**
* This should be called once in onCreate() for each of your activities that use GoogleAnalytics.
* These methods are not synchronized and don't generally need to be, so if you want to do anything
* unusual you should synchronize them yourself.
*/
public void incrementActivityCount() {
if( activityCount==0 )
if( dispatchIntervalSecs==null )
GoogleAnalyticsTracker.getInstance().start(apiKey,context);
else
GoogleAnalyticsTracker.getInstance().start(apiKey,dispatchIntervalSecs,context);
++activityCount;
}
/**
* This should be called once in onDestrkg() for each of your activities that use GoogleAnalytics.
* These methods are not synchronized and don't generally need to be, so if you want to do anything
* unusual you should synchronize them yourself.
*/
public void decrementActivityCount() {
activityCount = Math.max(activityCount-1, 0);
if( activityCount==0 )
GoogleAnalyticsTracker.getInstance().stop();
}
/**
* Get or create an instance of GoogleAnalyticsSessionManager
*/
public static GoogleAnalyticsSessionManager getInstance( Application application ) {
if( INSTANCE == null )
INSTANCE = new GoogleAnalyticsSessionManager( ... ,application);
return INSTANCE;
}
/**
* Only call this if you're sure an instance has been previously created using #getInstance(Application)
*/
public static GoogleAnalyticsSessionManager getInstance() {
return INSTANCE;
}
}
The SDK now has a external library which takes care of all of this. Its called EasyTracker. You can just import it and extend the provided Activity or ListActivity, create a string resource with your code and you are done.
The tracker will only track the activity where it's executed. So, why don't you subclass an Activity which start it every time on onCreate:
public class GAnalyticsActivity extends Activity{
public void onCreate(Bundle icicle){
super.onCreate(icile);
tracker = GoogleAnalyticsTracker.getInstance();
tracker.start("UA-xxxxxxxxx", this);
}
// same for on destroy
}
Then, you extends that class for every activity you use:
public class YourActivity extends GAnalyticsActivity{
public void onCreate(Bundle icicle){
super.onCreate(icile);
// whatever you do here you can be sure
// that the tracker has already been started
}
}
The approach I am using is to use a Bound Service (I happen to be using one already so was spared the creation of extra boiler plate code.)
A Bound Service will only last as long as there are Activities bound to it. All the activities in my app bind to this service, so it lasts only as long as the user is actively using my application - therefore very much a real 'session'.
I start the tracker with a singleton instance of Application which I have extended and added a static getInstance() method to retrieve the instance:
// Non-relevant code removed
public IBinder onBind(Intent intent) {
tracker = GoogleAnalyticsTracker.getInstance();
tracker.startNewSession(PROPERTY_ID, MyApp.getInstance());
}
public boolean onUnbind(Intent intent) {
tracker.stopSession();
}
See: http://developer.android.com/guide/topics/fundamentals/bound-services.html
I did a time based split between visits in my app, working like this:
I've build a wrapper singleton Tracker object for the GoogleAnalyticsTracker where i keep the last time something got tracked. If that time's more then x seconds i treat it as a new visit.
Of course this is only useful if you track everything in your app, and may not be the best solution in every situation, works well for my app though.
It only supports trackPageView, but setCustomVar and trackEvent should be easily implemented..
Anywhere you need to track something just add the line:
Tracker.getInstance(getApplicationContext()).trackPageView("/HelloPage");
I usually do it in the onResume of an activity
Tracker gist
You will need something like this: http://mufumbo.wordpress.com/2011/06/13/google-analytics-lags-on-android-how-to-make-it-responsive/
That's on the previous version and used to work very well. Now I'm in the same struggle as you, as V2 doesn't seems to be very consistent.
I wonder if this is something that could be done using AOP.
Android can only use compile-time AOP methods so maybe something like AspectJ?
There's a little more info on using AspectJ in Android in this thread. The main issue being that you would still need to declare on classes you own.