I am working on a game that involves using the accelerometer to control the character. My problem is this: I need to use the values recieved by the sensor in classes and methods that are not accessible inside OnSensorChanged(). I believe I need to implement a Callback from inside the OnSensorChanged, but I don't know how to do that. Can anyone help me out?
I believe the answer in this post (How to Define Callbacks in Android?) will help you out.
To summarize, create the callback interface:
// The callback interface
interface MyCallback {
void callbackCall(SensorEvent event);
}
Implement the call back interface in the class that is supposed to do calculations:
class Callback implements MyCallback {
void callbackCall(SensorEvent event) {
// callback code goes here
}
}
Make the call from your Activity where you have the onSensoreChanged():
// The class that takes the callback
class Worker extends Activity implements SensorEventListener {
MyCallback callback;
public void onSensorChanged(SensorEvent event) {
callback.callbackCall(event);
}
}
I hope this helps.
UPDATE:
I assume you already know about processes and threads (if not, please have a look at the Android doc about Processes and Threads).
The onSensorChanged method is an I/O and it is a good practice to do I/O operations in a separate thread (instead of the main UI thread).
Once the callback method is called, you can store the event in another variable and use those local variables in that class.
Since you are writing a game, it is unlikely for your app to require every single event. Therefore, while the app is busy calculating data for your game, the other events can be dropped. You can do this by setting a "busy" flag (boolean) and include the code for calculation within this if block.
void callbackCall(SensorEvent event) {
if (!busy) {
// Set the busy flag to block other event changes
busy = true;
// callback code goes here
// Once finished, reset the busy flag to allow other events to come in
busy = false;
}
}
Related
I have some fragments loaded in a ViewPager, where each "page" is loaded from a row in a cursor. Each fragment shows an image (JPEG) on the device. When the user dismisses the fragment (i.e swipe/page change, hits back/up, or just closes the app entirely) I want to invoke a method which opens the JPEG file for writing and does an update of its metadata. The actual work is eventually handled by the Apache Commons Imaging library.
I've implemented this by invoking my saveToFile() method from each fragment's life cycle onStop() handler. Does this mean the entire file operation ends up running on the UI thread? Should I definitely set up an AsyncTask for this?
Say the file write for some reason suddenly (for some jpeg) should take a long time, eg 2 minutes. What would then happen? Would the UI just wait (freeze) at this page/fragment before resuming? Or would the process (write to file) carry on "in the background" somehow? Or would the process just be killed, stopped short mid-process?
The way I have this wired up currently (onStop invoking saveToFile(), which calls up the imaging library and then updates the file) seems to work as it should. Even if I end the app, I still see my Toast text popping up, saying "Writing to file..." Seemingly, the process is never disturbed, and I can't say I'm experiencing any UI lag.
onStop() handler. Does this mean the entire file operation ends up
running on the UI thread? Should I definitely set up an AsyncTask for
this?
YES
An AsyncTask has several parts: a doInBackground method that does, in fact, run on a separate thread and the onPostExecute method that runs on the UI thread.
You can also use some sort of observer pattern such as EventBus to run async and post results to the UI.
Say the file write for some reason suddenly (for some jpeg) should
take a long time, eg 2 minutes. What would then happen? Would the UI
just wait (freeze)
The application will crash because Android will forcefully close it due to ANR (Application Not Responding).
Refer to the official documentation for details on this: https://developer.android.com/training/articles/perf-anr.html
Android applications normally run entirely on a single thread by
default the "UI thread" or "main thread"). This means anything your
application is doing in the UI thread that takes a long time to
complete can trigger the ANR dialog because your application is not
giving itself a chance to handle the input event or intent broadcasts.
Therefore, any method that runs in the UI thread should do as little
work as possible on that thread. In particular, activities should do
as little as possible to set up in key life-cycle methods such as
onCreate() and onResume(). Potentially long running operations such as
network or database operations, or computationally expensive
calculations such as resizing bitmaps should be done in a worker
thread (or in the case of databases operations, via an asynchronous
request).
The most effective way to create a worker thread for longer operations
is with the AsyncTask class.
Here is what I recommend though. Use the above mentioned, EventBus and create a BaseActivity which will automatically save the data for you onClose() by firing an event that runs Async. You then extend that base activity in all the places where you need autosave capabilities.
Here's what I mean with an example that uses EventBus.
public abstract class BaseActivity extends Activity{
#Override
protected void onResume(){
if(!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
super.onResume();
}
#Override
protected void onDestroy() {
if(EventBus.getDefault().isRegistered(this))
EventBus.getDefault().unregister(this);
super.onDestroy();
}
#Override
protected void onStop() {
super.onStop();
//We fire event and pass the current parent class that inherited this base.
EventBus.getDefault().post(new EventBusProcessMySaveData(this.getClass()));
}
}
//Your model class to use with EventBus
public final class EventBusProcessMySaveData{
private final Class className;
public EventBusProcessMySaveData(final Class className){
this.className = className;
}
public Class getClassName(){
return this.className;
}
}
public class MyMainActivity extends BaseActivity{
//Do you standard setup here onCreate() and such...
//Handle Event for Saving Operation, async.
//This will fire everytime theres an onClose() IN ANY activity that
//extends BaseActivity, but will only process if the class names match.
#Subscribe(threadMode = ThreadMode.ASYNC)
public void methodNameDoesNotReallyMatterHere(final EventBusProcessMySaveData model){
//We make sure this is the intended receiving end by comparing current class name
//with received class name.
if(model.getClassName().equals(this.getClass())){
//Do whatever you need to do that's CPUintensive here.
}
}
}
I know how to save states and restore them, but I just get confused when I have to do work with the Web services and to update UI. For times I was using the AsyncTask but then I came to point where I loose my activity/fragment context for example when I rotate the device. So in this way, I am thinking how other apps are handling such situations.
If I use the IntentService and call my web service from there, then I came to think that for each web service I have to make IntentService differently, and update the UI of each activity and fragment I have to make the BroadcastReceiver for each activity and fragments.
So what is a good practice for calling web service from the activity and the fragments?
How can I Update UI when the service return arrives (or call next service based on first services results)?
If you want your data to be instantly available through configuration changes (which you do), then you probably want to use Loaders.
It gives the developer a mechanism of loading data asynchronously for an activity or fragment. Since loaders are specifically designed to solve the issue of async loading, one does not have to spend too much time designing async tasks to handle all different scenarios efficiently.
Good article about Loaders https://medium.com/google-developers/making-loading-data-on-android-lifecycle-aware-897e12760832
Try using retrofit. It's a great networking libraries for Android apps and it's easy to use.
The entire network call + JSON/XML parsing is completely handled by it (with help from Gson for JSON parsing). Documentation is great and the community is huge.
check out this sample.
I noticed a comment you made:
...and my webservices are soap and I cant change them
The way I'm currently calling my web service, which is also SOAP, is via an Intent. I do this by passing in the data that I'm submitting to the Web service with putExtra then receiving it on my WebService, as you probably do right now. I then get the result from that web call and process it inside an AsyncTask, the async task will then utilize EventBus to post to Results as needed which are received on my MainThread via ThreadMode.Main.
So with that said, I highly recommend the use of a library called EventBus from Greenrobot.
You greatly simplify communication between Activities and Fragments, You can get started immediately using a default EventBus instance available from anywhere in your code. For example, you can do the following.
EventBus.getDefault().post(new ModelForOtherActivityToSee(data));
In the model, you can include anything you want, and react accordingly when received.
The best part is that when received, EventBus handles how the data will be executed by either running ASYNC, MAIN, BACKGROUND
ASYNC - Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long-running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications.
Background - Subscribers will be called in a background thread. If posting thread is not the main thread, event handler methods will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single background thread that will deliver all its events sequentially. Event handlers using this mode should try to return quickly to avoid blocking the background thread.
MAIN -Subscribers will be called in Android’s main thread (sometimes referred to as UI thread). If the posting thread is the main thread, event handler methods will be called directly (synchronously like described for ThreadMode.POSTING). Event handlers using this mode must return quickly to avoid blocking the main thread.
An example of receiving an event broadcasted from EventBus:
//ThreadMode can be ASYNC, MAIN, BACKGROUND
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ModelForOtherActivityToSee eventModel) {
/* Do something with eventModel received, this runs on UI thread */
};
Full example on how to use EventBus:
1 - Open your build.gradle for the app and set your dependency for EventBus:
dependencies { compile 'org.greenrobot:eventbus:3.0.0'}
2 - Create your first model to use in publishing an EventBus, I will use a very simplistic example of a model:
package com.myapp.models.eventbusmodels;
public final class EventBusMyModel {
private final String dataRaw
public EventBusMyModel(final String rawData) {
this.dataRaw = rawData;
}
public String getRawData() {
return this.dataRaw;
}
}
3 - Now all that's left is pushing out a broadcast by using from anywhere.
EventBus.post(new EventBusModel("My Data here"));
4 - To enable Activities/Fragments to receive events from EventBus you must attach and detach, this is what I mean. From inside an Activity on the onResume() and onStop() overrides:
public class SomeActivity {
#Override
protected void onResume() {
if(!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
}
#Override
protected void onStop() {
if(EventBus.getDefault().isRegistered(this))
EventBus.getDefault().unregister(this);
super.onStop();
}
}
5 - The final thing to do is receive that broadcast, you can receive it in Any Fragment, Activity, or in all your fragments/activities. Here's an example from inside the SomeActivity:
#Subscribe(threadMode = ThreadMode.MAIN)
public void eventThisNameDoesNotMatter(final EventBusMyModel resultModel) {
String receivedData = resultModel.getRawData();
//Do whatever with receivedData. Since we are on ThreadMode.MAIN, this is on the UI thread.
}
I'm realizing while reviewing some of my existing Activity code that some of the Volley async network response handlers call finish() to return to the caller (who typically start my Activity via startActivityForResult). Something like this:
private Response.Listener<MyResponse> mResponseListener = new Response.Listener<MyResponse>(){
#Override public void onResponse(MyResponse myResponse) {
// I could get here *after* rotation was initiated
// do stuff
finish();
};
}
After some recent investigation into a bug, I realized my code does not handle the rotation case properly -- I have cases where a network response handler could, in theory, be called in between activity instance A1's destruction and activity instance A2's creation when the device is rotated. What effect does calling finish() after A1's onDestroy is called have? Is the fact that "we're done" lost? Does A2 get created and stick around as though finish were never called?
What effect does calling finish() after A1's onDestroy is called have?
I'm not sure, but to me it seems like it should finish the activity and remove it from the task's back stack.
I think the root of your problem lies elsewhere, though - Activities and Fragments really aren't the proper place to be handling network or other asynchronous operations. You should treat Activities and Fragments more like dumb Views in terms of an MVC or MVP design - they should accept some data from a controller and render their Views accordingly.
Hence, the proper place for making async requests would be something like a plain Java class with an instance which is kept in the Application context, rather than in any Activity context. This way, the object that is performing your async operation is not bound to the fickle Activity/Fragment lifecycle.
For example, I like using EventBus with its cross-thread sticky events to communicate between the object making the request and the Activity that has to display the result, subscribing an event listener in the Activity's onResume callback and unsubscribing in onPause.
An article that helped me tremendously in learning to think of Activities and Fragments was this one by Matt Swanson.
I believe what happens after onDestroy is that the Activity reaches the end of its lifecycle and is soon garbage collected.
I can think of two solutions for your case
Cancel all Volley Requests in onDestroy. You can use RequestQueue#cancelAll which cancels all requests given a specific tag. This tag is attached when instantiating a Volley Request.
Use Publisher-Subsriber pattern such as provided by Otto or EventBus. I'll just demonstrate the magic of Otto.
public static class ResponseEvent{
MyResponse myResponse;
public ResponseEvent(MyResponse myResponse){
this.myResponse = myResponse;
}
}
public void onCreate(){
BusProvider.getInstance().register(this);// register this activity as subscriber
}
public void onDestroy(){
BusProvider.getInstance().unregister(this);
}
// it is up you where you want to register and unregister depending
// whether you want to digest the response when the activity
// is on foreground or background as well.
private Response.Listener<MyResponse> mResponseListener = new Response.Listener<MyResponse>(){
#Override public void onResponse(MyResponse myResponse) {
// I could get here *after* rotation was initiated
// do stuff
BusProvider.getInstance().post(new ResponseEvent(myResponse));
//sends this event to previously registered subcsriber.
//The subscriber method will be active as long the activity
//hasn't been de-registered.
//Nothing will happen after unregister has been called.
}};
//this is the subscriber method that will digest your response
#Subsribe
public void onGotResponse(ResponseEvent event){
// do your stuff with response here.
finish();
// notice I moved finish() here so you can be sure
// it will only be called as long as the activity is still active
}
I have an AsyncTask which never dies. The listener to the events in this AsyncTask keeps changing(depending on which activity/fragment is visible to the user). To accomplish this, I have a setup like the following :
An interface :
public interface TaskListener {
public void onItemChanged(String itemName)
}
AsyncTask which contains a TaskListener Member variable which is registered/unregistered using public methods.
public void registerListener(TaskListener listener) {
mListener = listener;
}
public void unregisterListener() {
mListener = null;
}
In the onPublishProgress() method (called via publishProgress() in the doInBackground() method) of the AsyncTask, I notify the listener.
Now, my question is are there any caveats for this situation while notifying the listener? In particular, I would like to know whether it is thread safe or not. i.e., if publishProgress() and registerListener() is called at the same time, will the right listener receives a callback?
I once had to debug an AsyncTask and followed my code even got into android's source code.
publishProgress() does not issue a direct call to onProgressUpdate() it just posts a message in a queue, and the queue handler eventually calls onProgressUpdate().
So strictly speaking, if publishProgress() and registerListener() are called at the same time registerListener() will get there first.
If you are concerned about interference between the two, just enclose the sensitive code in a synchronized block over whatever variable is there.
synchronized(mListener) {
// do stuff to mListener
}
do this in both onProgressUpdate() and registerListener() and anywhere else you want to be mutually exclusive on handling the listener.
AsyncTask should not live between activities. That's not really correct way.
Android has services for this.
http://developer.android.com/reference/android/app/Service.html
http://developer.android.com/guide/developing/tools/aidl.html
My Android app needs to be constantly receiving via USB serial in the background of my app, while sending information via USB serial only happens on certain functions. When we send and receive I am always sending a packet of X bytes every time. I understand how Android USB API works, the thing that I am having trouble with is how would I organize this? Would I use a thread for receiving only and the rest as functions, or for the whole USB connection/sending and receiving all together is in a thread? The main activity is called "Homescreen.java" and here is how I have it organized so far.
public class HomeScreen extends Activity implements OnTouchListener, Runnable{
onCreate() { }
onResume() { }
onStart() { }
onDestroy() { }
run() { }
}
Note: The reason there is no onPause is because this app is a fullscreen widget and should never be closed.
Another question: If I was to make a thread would I have to make it extend from Homescreen.java? And what of Context? Can I just import it? (Not very keen on Context object)
this is more of design choice, for instance if you want one background thread to handle the data from USB
public class test extends Activity{
Thread t;
runT= true;
public void onCreate(Bundle b)
{
..........
..........
t = new Thread(new Runnable() {
#Override
public void run()
{
while(runT)
{
//call data read or send functions here you can add condtion to sleep the thread as well
}
}
});
t.start();
}
}
When you are ending the activity simply set runT to false, which will stop the thread.
You can also have a thread pool and use theads accordingly.
If this is not happening frequently you can start an Asynctask everytime you want to send data.
You can look at AsyncTask. It is a special thread implementation for Android that should keep things simpler. If you are not doing any threaded "heavy lifting" I would recommend going with AsyncTask. You simply write an inner class inside your HomeScreen class, write your logic and call it from your Activity (for example from within onCreate()).
You could try getBaseContext() from within the Activity - I guess this will get you the relevant Context.
Cheers