Hey m a newbie to android programming and I was working on this project.
This question is pretty long so here's the deal.
I have this GCMIntentService class extending GCMBaseIntentService and whenever a message arrives from the server, the GCMBroadcastReceiver automatically recognizes it and calls the overriden onMessage() method in the GCMIntentService class. Now in the onMessage body, I am doing some operations on the SQLiteDatabase and I am notifying my adapter for list view by calling the adapter.notifyDataSetChanged() in the ui thread inside the onMessage body.
Now, if more than 2 or 3 gcm messages come simultaneously to the device the app crashes since more than one thread is calling the same onMessage() method and is messing up with my database and adapter as well. I figured I needed to use synchronized keyword on the method that should be used by only one thread at a time.
But since my onMessage method is an overriden method, I decided to make another method and put synchronized modifier on it but once again I need to call the runOnUiThread() method from inside it since i need to notify changes to my list view's adapter.
I just want to ask if doing this is the right way or is it possible to use a much simpler solution to my problem?
Here is the sample code to what m doing:
#Override
protected void onMessage(Context arg0, Intent intent) {
// called when a new cloud message has been received
Log.w("Service ", "Started");
dbh = new DatabaseHandler(this);
sld = dbh.getWritableDatabase();
who = this;
// processing json object
putDataFromJSON();
//other stuff
}
synchronized private void putDataFromJSON(){
//do some work on JSON Object
//complete work on JSON by putting in database
dbh.saveInDB();
//notify the adapter
((MainActivity) MainActivity.con).runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
//do other stuffs as well
}
}
}
I'm writing a dummy code here that I think can demonstrate you an abstract architecture..
public class GCMIntentService extends GCMBaseIntentService{
private static ArrayList<Message> messageQueue = new ArrayList<Message>();
private static boolean isProcessingMessage = false;
onMessage(Context context, Intent intent)
{
if(isProcessingMessage)
{
Message currentMsg = new Message();//Create a instance of message and put it in arrayList
}
else{
isProcessingMessage = true;
for(int i = 0; i < messageQueue.size(); i++)
{// Process all your messages in the queue here
messageQueue.remove(i);
}
isProcessingMessage = false;
}
}
private class Message{
//In this class you can configure your message that you are going to queue.
}
}
Firstly, the onMessage() method gets executed every single time a new GCM message arrives(even when you are not into your app, because we register this receiver inside the manifest file.) So, getting the context of your activity my cause your app to crash (NullPointerException).
Now, as far as your question is concerned, you can maintain a queue that keeps track of incoming GCM messages. And, upon processing a message you can check for the entries in the queue and process them. For this purpose, you can use a boolean that flags if any message is currently being processed (flag == true). And when (flag == false), you can take the next entry from the queue and process that..
I hope it was useful.
Related
My service has a PhoneStateListener that overrides the onCellInfoChanged method. When running on Android Studio, it'll log whenever the method is called. Based on the logs, it seems that sometimes the method gets called consecutively (a couple milliseconds between logs).
public class OnCellChangeService extends Service
{
// other field declarations
private PhoneStateListener mPhoneStateListener = new PhoneStateListener()
{
#SuppressLint("DefaultLocale")
#Override
public void onCellInfoChanged(List<CellInfo> cellInfoList)
{
String timeStamp = simpleDateFormat.format(new Date());
List<CellNetwork> cellNetworks = setCellNetwork(cellInfoList);
String networkStrength = "";
int index = 1;
for (CellNetwork cell : cellNetworks)
networkStrength += String.format("%s (%d)%s\n", timeStamp, index++, cell.record());
try {
writer.write(networkStrength);
writer.flush();
Log.d("Phone Listener", "Cell Change");
} catch (Exception e) {
e.printStackTrace();
}
}
};
// rest of service
}
All the listener does is take the cellInfoList, calls another method to get a list that contains a list of custom class objects made from a subset of the original list. It writes to a file with a time stamp and other various pieces of information from each list object.
When the listener's method is called again while the same method is executing, does the current method stop and restart for the new call? Does it run in a separate thread of execution? Does it wait for the method to finish executing? If another call does halt or interfere with the same method executing, how could I implement threading and/or synchronization to make sure every called is executed in full while maintaining order?
The callbacks from PhoneStateListener are all made on the main (UI) thread. Therefore, each callback method will run to completion before the next one is called.
I am having serious difficulties to understand how can I make some AsyncTask children, declared and instantiated in the Main Thread, to await for a Service child instance to reach some specific state.
As code examples here is the relevant part for Service; this code does what expected: receives the JSON response and holds it.
public class MyService extends Service {
private boolean received = false;
private string url = "http://someserver.mine/get-data-in-json-format";
// [...]
#Override
public void onCreate() {
doHttpJsonQuery();
}
public boolean responseReceived() {
return this.received;
}
public List<MyModel> getResponseAsObject() {
if (!this.received) return new ArrayList<MyModel>;
// Many code lines that convert the data into a list.
// [...]
return the_list;
}
// [...]
private void doHttpJsonQuery() {
OkHttpClient client = new OkHttpClient.Builder()
.build();
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
call.cancel();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
//...and some code to hold data as JSONArray
//[...]
}
});
this.received = true;
}
}
This Service works; fine. Then, from another class (which purpose will be to handle persistence inserting the received data in a local Room Database), I try to do the following (here's where my mind is blown):
public class DataRepository {
private MyRoomDatabase db;
private MyModelDao mModelDao;
// I'm skipping irrelevant code on purpose
// [...]
public DataRepository(Application application) {
db = MyRoomDatabase.getDatabase(application);
mModelDao = db.myModelDao();
// [...]
// Here I instance a subclass of ContextWrapper(i named it RemoteDataSource) which
// responsability will be handling different Services for making HTTP operations
mRemoteDataSource = new RemoteDataSource(application.getApplicationContext());
// It holds a reference to MyService. It has some public methods, like this one, to
// control the referenced Service from outside with some encaspsulation
mRemoteDataSource.startMyService();
// Instantiating a private nested class...
PopulateDbAsync mPopulateDbAsync = new PopulateDbAsync(db);
mPopulateDbAsync.doInBackground();
}
// [...]
// Here is the failing code
private class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
PopulateDbAsync(MyRoomDatabase db) {}
#Override
protected Void doInBackground(final Void... params) {
MyService mService = mRemoteDataSource.getMyService();
if (mService == null) {
// This doesn't happen at all right now...
Log.e("MY_ERROR","DataRepository.PopulateDbAsync --> MyService from RemoteDataSource is NULL!!!!");
}
List<MyModel> the_list = mService.getResponseAsObject();
if (the_list == null) {
// HERE! I obtain the NullReferenceException here.
// I am confused about how would I avoid this flaw in my code
Log.e("MY_ERROR", "DataRepository.PopulateDbAsync --> error: response isn't ready yet.");
}
for (MyModel i_model : the_list) {
Log.d("MY_LOG", "DataRepository.PopulateDbAsync --> Inserting data in local DB...");
mModelDao.insert(i_model);
}
return null;
}
}
}
Summarizing: my problem is that I will always get NullReferenceException in this line:
for (MyModel i_model : the_list) {
I am not familiar with multithreading, asyncronous operations and concurrent execution. I have been reading, for two weeks, lots of different documents on the Internet both from Android Official Website and from other websites as well, trying to figure it out... "AsyncTask is not good to perform this kind of operations"... so, what infrastructure should I implement, I have been wondering... should I use Handlers, Threads, Messengers, or what? The more I read, the more confused I get. It's like I have an Analysis Paralysis issue...
Most of the examples I find out there provide too verbose code examples on how to implement multithreading and concurrent execution; while I read them and try to figure out how to implement those structures in my code, I just get stuck; also, with so many classes to choose, I get even more confused...
Due to the HTTP call will need to be performed asyncronously (and response time will not always be the same), I am trying to figure out how to make the piece of code that throws the NullReferenceException "wait" for MyService to complete it's job before starting it's execution; while loops will not work due to it would break Main Thread's lifecycle. "Knowing" if the Service completed it's task or not would be as simple as using the boolean method responseReceived. The big idea is, every time new data is obtained through HTTP, updating the RoomDatabase with it, and, meanwhile, MainActivity would be showing the current local data (if any, or an empty list if there's nothing yet).
So, when I get it, I will understand how to refactor the whole code structure properly to start adding more Service child instances into my RemoteDataSource class, which I created with the idea of having all Service childs that will use OkHttp to perform HTTP communications, wrapped together in a single class for better organization.
What would be the proper way to achieve what I am looking for about this? Would someone be able to provide some short example explaining the code structure I will need for something like this? Examples with empty blocks containing comments like "code to execute when ready here" would be great so I can figure it out.
The question exposed here is related with the same project that made me post this other question some weeks ago; I have been reading here and there, performing some trial-and-error and correcting some code issues here-and-there since then; however, I am making a different question here; finding an answer for this would probably be the first step towards figuring out an answer to the other question as well.
URL References to documentation I have been reading
Some of the documentation I have been reading (but not limited to):
AsyncTask class documentation
Handler class documentation
Basics on Multithreading
Introduction to background processing in Android - Tutorial
Thread With Handlers - Android Example
Messenger class documentation
Well problem is with your application logic as follows,
If you are using AsyncTask that is obviously a separate thread from the main thread. But syncing to your database after retrieving data via HTTP call is a process which has a sequence ( Call through HTTP and retreive -> then persist to database ), it cannot perform asynchronously. So when you call,
List<MyModel> the_list = mService.getResponseAsObject();
this call happens in a particular thread and the program flow is in a different thread.
Since these are asynchronous tasks, they work asynchronously. which means you will never know which one will execute first and which one is next. But as per your logic,
if (the_list == null) {
this part essentially need the_list to be initialized to run. But the problem is at that point, service thread has not finished his work to perform your next logic. so its obvious breaking.
Better if you can re-design this so that you wait for the HTTP request to complete and then persist to database. Because suppose if your HTTP request complets first but still it returns you null or whatever not-desired output. So in that case you need to handle it in your logic.
OK so let me tell you a quick workaround.
Lets use just one thread instead of different threads. So consider changing following line
private class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
to
private class PopulateDbAsync
then you will get an error with
#Override
protected Void doInBackground(final Void... params) {
since we no longer extend AsyncTask class.
so change it as follows, by removing #Override
public Void doInBackground(final Void... params) {
This should fix the stated problem here.
I found a solution: creating custom listeners.
Steps to create a custom listener
1. Define an interface as an event contract with methods that define
events and arguments which are relevant event data.
2. Setup a listener member variable and setter in the child object which can be assigned an implementation of the interface.
3. Owner passes in a listener which implements the interface and handles the events from the child object.
4. Trigger events on the defined listener when the object wants to communicate events to it's owner
I got the NullReferenceException because MyService didn't finish it's job yet. So, first I create the listener's structure within MyService class like this (steps 1 and 2):
private MyServiceListener listener;
public interface MyServiceListener {
public void onDataDownloaded();
}
public void setMyServiceListener(MyServiceListener listener) {
this.listener = listener;
}
And, within the HTTP request's callback (step 4):
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
//...and some code to hold data as JSONArray
//[...]
// XXX Trigger the custom event
if (listener != null) {
listener.onDataDownloaded();
}
}
Now, I just can wrap the code that triggered the NullReferenceException within the custom listener like this (step 3):
// Within DataRepository class
mService.setMyServiceListener(new MyService.MyServiceListener) {
#Override
public void onDataDownloaded() {
List<MyModel> the_list = mService.getResponseAsObject();
if (the_list == null) {
// HERE! I obtainED the NullReferenceException here.
Log.e("MY_ERROR", "DataRepository.PopulateDbAsync --> error: response isn't ready yet.");
}
for (MyModel i_model : the_list) {
Log.d("MY_LOG", "DataRepository.PopulateDbAsync --> Inserting data in local DB...");
mModelDao.insert(i_model);
}
return null;
}
}
Actually, the real implementation required to nest this code example into another custom listener following similar steps; but this worked for me.
I can call Snackbar.make() from a background thread without any problems. This is surprising to me since I thought UI operations are only allowed from the UI thread. But that is definitely not the case here.
What exactly makes Snackbar.make() different? Why doesn't this cause exceptions like any other UI component when you modify it from a background thread?
First of all: make() doesn't perform any UI related operations, it just creates a new Snackbar instance. It is the call to show() which actually adds the Snackbar to the view hierarchy and performs other dangerous UI related tasks. However you can do that safely from any thread because it is implemented to schedule any show or hide operation on the UI thread regardless of which thread called show().
For a more detailed answer let's take a closer look at the behaviour in the source code of the Snackbar:
Let's start where it all begins, with your call to show():
public void show() {
SnackbarManager.getInstance().show(mDuration, mManagerCallback);
}
As you can see the call to show() gets an instance of the SnackbarManager and then passes the duration and a callback to it. The SnackbarManager is a singleton. Its the class which takes care of displaying, scheduling and managing a Snackbar. Now lets continue with the implementation of show() on the SnackbarManager:
public void show(int duration, Callback callback) {
synchronized (mLock) {
if (isCurrentSnackbarLocked(callback)) {
// Means that the callback is already in the queue. We'll just update the duration
mCurrentSnackbar.duration = duration;
// If this is the Snackbar currently being shown, call re-schedule it's
// timeout
mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
scheduleTimeoutLocked(mCurrentSnackbar);
return;
} else if (isNextSnackbarLocked(callback)) {
// We'll just update the duration
mNextSnackbar.duration = duration;
} else {
// Else, we need to create a new record and queue it
mNextSnackbar = new SnackbarRecord(duration, callback);
}
if (mCurrentSnackbar != null && cancelSnackbarLocked(mCurrentSnackbar,
Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE)) {
// If we currently have a Snackbar, try and cancel it and wait in line
return;
} else {
// Clear out the current snackbar
mCurrentSnackbar = null;
// Otherwise, just show it now
showNextSnackbarLocked();
}
}
}
Now this method call is a little more complicated. I am not going to explain in detail what's going on here, but in general the synchronized block around this ensures thread safety of calls to show().
Inside the synchronized block the manager takes care of dismissing currently shown Snackbars updating durations or rescheduling if you show() the same one twice and of course creating new Snackbars. For each Snackbar a SnackbarRecord is created which contains the two parameters originally passed to the SnackbarManager, the duration and the callback:
mNextSnackbar = new SnackbarRecord(duration, callback);
In the above method call this happens in the middle, in the else statement of the first if.
However the only really important part - at least for this answer - is right down at the bottom, the call to showNextSnackbarLocked(). This where the magic happens and the next Snackbar is queued - at least sort of.
This is the source code of showNextSnackbarLocked():
private void showNextSnackbarLocked() {
if (mNextSnackbar != null) {
mCurrentSnackbar = mNextSnackbar;
mNextSnackbar = null;
final Callback callback = mCurrentSnackbar.callback.get();
if (callback != null) {
callback.show();
} else {
// The callback doesn't exist any more, clear out the Snackbar
mCurrentSnackbar = null;
}
}
}
As you can see first we check if a Snackbar is queued by checking if mNextSnackbar is not null. If it isn't we set the SnackbarRecord as the current Snackbar and retrieve the callback from the record. Now something kind of round about happens, after a trivial null check to see if the callback is valid we call show() on the callback, which is implemented in the Snackbar class - not in the SnackbarManager - to actually show the Snackbar on the screen.
At first this might seem weird, however it makes a lot of sense. The SnackbarManager is just responsible for tracking the state of Snackbars and coordinating them, it doesn't care how a Snackbar looks, how it is displayed or what it even is, it just calls the show() method on the right callback at the right moment to tell the Snackbar to show itself.
Let's rewind for a moment, up until now we never left the background thread. The synchronized block in the show() method of the SnackbarManager ensured that no other Thread can interfere with everything we did, but what schedules the show and dismiss events on the main Thread is still missing. That however is going to change right now when we look at the implementation of the callback in the Snackbar class:
private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
#Override
public void show() {
sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, Snackbar.this));
}
#Override
public void dismiss(int event) {
sHandler.sendMessage(sHandler.obtainMessage(MSG_DISMISS, event, 0, Snackbar.this));
}
};
So in the callback a message is send to a static handler, either MSG_SHOW to show the Snackbar or MSG_DISMISS to hide it again. The Snackbar itself is attached to the message as payload. Now we are almost done as soon as we look at the declaration of that static handler:
private static final Handler sHandler;
private static final int MSG_SHOW = 0;
private static final int MSG_DISMISS = 1;
static {
sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(Message message) {
switch (message.what) {
case MSG_SHOW:
((Snackbar) message.obj).showView();
return true;
case MSG_DISMISS:
((Snackbar) message.obj).hideView(message.arg1);
return true;
}
return false;
}
});
}
So this handler runs on the UI thread since it is created using the UI looper (as indicated by Looper.getMainLooper()). The payload of the message - the Snackbar - is casted and then depending on the type of the message either showView() or hideView() is called on the Snackbar. Both of these methods are now executed on the UI thread!
The implementation of both of these is kind of complicated, so I won't go into detail of what exactly happens in each of them. However it should be obvious that these methods take care of adding the View to the view hierarchy, animating it when it appears and disappears, dealing with CoordinatorLayout.Behaviours and other stuff regarding the UI.
If you have any other questions feel free to ask.
Scrolling through my answer I realize that this turned out way longer than it was supposed to be, however when I see source code like this I can't help myself! I hope you appreciate a long in depth answer, or maybe I might have just wasted a few minutes of my time!
Snackbar.make is completely safe from being called form non-ui thread. It uses an handler inside its manager which operates on the main looper thread and thus hides the caller form the underlying complexities of it.
Only the original thread that created a view hierarchy can touch its views.
If you use the onPostExecute you'll be able to access the views
protected void onPostExecute(Object object) { .. }
you may know about Google Cloud Messaging
The problem is that when a gcm message triggers by the server, my application receives a bundle from google play services, this happen at GcmBroadcastReceiver.java. Here i can send this data to other classes in order to append some info from the server.. well. I got stuck when i try to update, for example, some views in the UI thread.
HOW I CAN DO THIS?
Imagine that MainActivity.java is the UI thread when i declare the views, etc.
I tried to create here a public static method which can be called directly by GcmBroadcastReceiver.java by this way: MainActivity.*updateUI*(args..), but it throws this exception:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Can anyone try to explain me this? i also know about asyncTask but i cant imagine how it works. I also find some pages explaining events that are fired by the UI thread it self like runnables that do some task in background. Im searching something like this:
MainActivity extends Activity{
...
protected void onCreate(Bundle blabla)..{
setContentView(R.layout.blabla);
registerSomeEvent(this);
}
private void handleEvent(Bundle ...){
... do stuff with the data provided in the UI thread
}
}
And here at GcmBroadcastReceiver, when gcm push some data, trigger that magic event in order to perform updates at the UI thread with some views like ListViews or TextView
One way is to use use LocalBroacastManager. For how to implement is, there is a great example on how to use LocalBroadcastManager?.
LocalBroadcast Manager is a helper to register for and send broadcasts of Intents to local objects within your process. The data you are broadcasting won't leave your app, so don't need to worry about leaking private data.`
Your activity can register for this local broadcast. From the GCMBroadcastReceiver, you send a local broadcast when you receive something in GcmBroadcastReceiver. Inside your Activity you can listen to the broadcast. This way if the activity is in the forefront/is active, it will receive the broadcast otherwise it won't. So, whenever you receive that local broadcast, you may do the desired action if activity is open. This is like saying to the activity that "Hey Activity, I've received a message. Do whatever you want with it".
If you want to do for the whole app, then you can make all your activities extend an abstract activity. And inside this abstract activity class you can register it for this 'LocalBroadcast'. Other way is to register for LocalBroadcast inside all your activities (but then you'll have to manage how you'll show the message only once).
You can use Handlers in your MainActivity in order to comunicate with UI Thread.
Communicating with the UI Thread
public class MainActivity extends Activity{
public static final int NEW_DATA_AVAILABLE = 0;
public static final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MainActivity.NEW_DATA_AVAILABLE:
String newData = msg.getData().getString(MyClass.DATA);
//Do some stuff with newData
break;
}
}
};
}
and in your non Activity class
public class MyClass implements Runnable{
Thread thread;
public final static String DATA = "new_data";
public MyClass(){
thread = new Thread(this);
thread.start();
}
#Override
public void run() {
while(true){
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
Message msg = mHandler.obtainMessage(MainActivity.NEW_DATA_AVAILABLE);
Bundle bundle = new Bundle();
bundle.putString(DATA, "We have received new data");
msg.setData(bundle);
MainActivity.handler.sendMessage(msg);
}
}
}
I think I may have accidentally switched on some setting I didn't intent to in Eclipse or something. I'm working on an android game and from within the game logic, when certain events happen I send messages to the main activity to display certain things.
I have the following classes:
public class GameMessageHandler extends Handler {
public static final int DO_SOMETHING = 0;
private final WeakReference<MyActivity> myActivity;
public GameMessageHandler(MyActivity myActivity) {
this.myActivity = new WeakReference<MyActivity>(myActivity);
}
#Override
public void handleMessage(Message msg) {
if (myActivity != null) {
MyActivity activity = myActivity.get();
if (msg.what == DO_SOMETHING) {
//even if the caller only called this one time, this keeps executing forever
activity.doSomething();
}
}
}
}
public class GameEventListenerAndroid implements GameEventListener {
private Handler handler;
public GameEventListenerAndroid(GameMessageHandler gameMessageHandler){
this.handler = gameMessageHandler;
}
#Override
public void playerTookSomeAction() {
//this only gets called one time
handler.sendEmptyMessage(GameMessageHandler.DO_SOMETHING);
}
}
I KNOW this logic works because what I'm trying to run right now is from a backup I saved after I saw it work MULTIPLE times, but as I said what is happening right now is for some reason the Looper keeps calling the message handler with the same message a million times per second and never discards the message to move on to something else.
Any help is greatly appreciated!
Check points:
activity.doSomething() will not send message GameMessageHandler.DO_SOMETHING
playerTookSomeAction() is not called repeatedly
Just format it to be BETTER, incase someone feels so boring!