Android how to update (UI thread) from other classes (really?) - java

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);
}
}
}

Related

What does running on main thread mean in android

I'm trying to connect to a PC server (using Hercules) through TCP from an android app (client) but I'm really lost and don't know where to go. None of the tutorials are fully working for me, most of them can allow me to send messages from client to server but not vice versa.
I read about connections not supposed to be run from the "main thread" but what does that mean?
Also any examples of a TCP connection from android would be great.
Thanks!
I suspect that the "main thread" in this context means that thread that is managing the user interface. If you do anything much in this thread, you run the risk of Android killing your app because it appears to have hung.
Personally, I don't think it's a huge problem to have the user interface thread block for a few milliseconds to do a TCP operation. You'd need to make sure that you code the operation to have sensible timeouts, so you don't end with a dead app because the remote server takes too long to respond.
The official way to handle situations like this is to define the network operations in services, or in separate threads, and have the user interface thread communicate with those services or threads using short-lived operations.
This process is documented with examples here:
https://developer.android.com/training/basics/network-ops/connecting
Main thread in android is responsible to create and display UI on screen
to perform task related to connection strictly need to use background thread otherwise UI become laggy.
There are two method available to perform background Task
Runnable:
new Thread(new Runnable() {
public void run() {
..... // code here
}
}).start();
Android AsyncTask: https://developer.android.com/reference/android/os/AsyncTask
Like #Kevin Boone said, Main thread means UI thread in Android.
You can't do networking operations in the Main thread, otherwise you will get NetworkOnMainThreadException. You can create a new thread and then pass result back to the Main thread using Handler. Code could look like this:
public class MyActivity extends AppCompatActivity implements FetchDataUseCase.Listener {
private FetchDataUseCase fetchDataUseCase;
private TextView textView;
private Button dataButton;
public void onCreate() {
textView = findViewById(R.id.textView);
dataButton = findViewById(R.id.dataButton);
dataButton.setOnClickListener(v -> getDataFromNetwork());
fetchDataUseCase = new FetchDataUseCase(this);
}
void getDataFromNetwork() {
fetchDataUseCase.fetchDataAndNotify();
// start async operation! and receive result in onDataFetched()
}
#Override
public void onDataFetched(String data) {
// now you are in Main thread
// do something with data
textView.setText(data);
textView.setVisibility(View.VISIBLE);
}
#Override
public void onError() {
textView.setText("ERROR!!!");
textView.setVisibility(View.VISIBLE);
}
}
public class FetchDataUseCase {
public interface Listener {
void onDataFetched(String data);
void onError();
}
private final Listener listener;
private final Handler handler = new Handler(Looper.getMainLooper());
public FetchDataUseCase(Listener listener) {
this.listener = listener;
}
public void fetchDataAndNotify() {
new Thread(() -> {
String myData = "";
try {
// your networking operation
// where you receive some data
} catch (Exception e) {
handler.post(() -> listener.onError();
} finally {
// close stream, file, ...
}
// pass it back to Listener in Ui Thread
handler.post(() -> listener.onDataFetched(myData);
}).start();
}
}
read ThreadPoster: Multi-Threading in Android
And don't use AsyncTask =)) Async task is deprecated
Also, you need to add permision to your AndroidManifest file.
<uses-permission android:name="android.permission.INTERNET"/>
Hope it will help you)) Good luck!

Calling activity from class that doesnt extend Activity

Is there any way to call an activity from something that doesnt extend Activity? without running it on UI-tread. I want toast-messages in my game, like in candy crush. But I have no idea how to call the toast-activity in an efficient way during real-time.
I know you can use context and get activity from that but it does not run very smoothly. Does anyone have experience with how to do this?
Toasts as well as other components that manipulates the user interface must not be used outside of the UI thread.
What you could do in order to solve your issue, is to design a messaging system between the thread managing you game, and your UI thread. In order to do so, you can use a Handler and its messaging facilities (sendMessage, post, postDelayed ...) to send messages or even Runnables to be run on your main thread.
If you create a Handler in the main thread, it will automatically associate itself with your main thread's event loop, thus making every work sent to it be executed in the main thread.
A basic example of what you could do would be :
class MainActivity extends Activity {
// The handler is associated with your Activity's thread
private Handler _handler = new Handler();
// ...
private Thread _worker = new Thread() {
#Override
public void run() {
_handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "Some text", Toast.LENGTH_SHORT).show();
}
});
}
};
};
As a shorthand, you could also use Activity.runOnUiThread(Runnable r) that executes the given runnable in the UI thread by default.

Synchronization on methods executing methods on other threads

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.

Android Thread modify EditText

I am having a problem with modifying EditText in another function started by the thread:
Thread thRead = new Thread( new Runnable(){
public void run(){
EditText _txtArea = (EditText) findViewById(R.id.txtArea);
startReading(_txtArea);
}
});
my function is as follows:
public void startReading(EditText _txtArea){
_txtArea.setText("Changed");
}
It always force closes while trying to modify the edittext. Does someone know why?
UI views should not be modified from non-UI thread. The only thread that can touch UI views is the "main" or "UI" thread, the one that calls onCreate(), onStop() and other similar component lifecycle function.
So, whenever your application tries to modify UI Views from non-UI thread, Android throws an early exception to warn you that this is not allowed. That's because UI is not thread-safe, and such an early warning is actually a great feature.
UPDATE:
You can use Activity.runOnUiThread() to update UI. Or use AsyncTask. But since in your case you need to continuously read data from Bluetooth, AsyncTask should not be used.
Here is an example for runOnUiThread():
runOnUiThread(new Runnable() {
#Override
public void run() {
//this will run on UI thread, so its safe to modify UI views.
_txtArea.setText("Changed");
}
});
First of all take a look at your log, it usually contains a stack trace when an app shuts down.
You shouldn't run the thread like you normally do, instead use runOnUiThread:
Runnable thRead = new Runnable(){
public void run() {
EditText _txtArea = (EditText) findViewById(R.id.txtArea);
startReading(_txtArea);
}
};
runOnUiThread(thRead);
The explaination: Only the UI thread is allowed to change the state of UI components.
This article may help you.
http://android-developers.blogspot.com/2009/05/painless-threading.html
There are few options:
1. run it on UI thread Activity.runOnUiThread(Runnable)
2. use AsyncTask
Except runOnUiThread() (which works), there is also another way, which I know of:
Define a handler in your UI (Activity) class:
public class MainActivity extends Activity {
.....
Handler uiThreadHandler = new Handler() {
public void handleMessage(Message msg) {
Object o = msg.obj;
if (o==null) o = "";
TextView textIn = (TextView)findViewById(R.id.textin);
textIn.setText(o.toString());
}
};
}
and from inside some thread you can call it:
Message msg = uiThreadHandler.obtainMessage();
msg.obj = "Text for EditView";
uiThreadHandler.sendMessage(msg);
By default, the main thread is the UI thread. All code that modifies the appearance of the application needs to be run in this thread. If you want to have multiple threads in your application that can modify the UI I would suggest using the AsyncTask class.
public someMethod(){
new ChangeTextTask().execute();
}
private class ChangeTextTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
startReading(_txtArea);
return null;
}
}
However, you need to take steps to prevent multiple threads from accessing the EditText object at once. Otherwise you'll wind up getting a CurrentModificationException error.
http://developer.android.com/reference/android/os/AsyncTask.html

How to trigger UI update on Activity when underlying datahandler receives data

I am creating an application which relies on data backend over Internet connection. This data is common between activities. Also, data will be kept refresh e.g. by updating it every two or three minutes. Therefore, I have created a data handler class, which should handle everything related to data downloading, parsing and such. Sometimes, it will receive command from Activity to refresh the data.
The problem is, how to refresh the UI in the activity when new data becomes available in the datahandler. If the datahandler was in activity, I could just post a handler for UI thread to update it. However, I don't know how to do it from this underlying class. Any advice?
Here's the rough code for three classes:
/**
* The data handler class itself
*/
public class DataHandler {
Object data;
public void getData () {
// starts a thread (HTTP query) to get data
}
private class dataReceived (Object data) {
// receives data
this.data = data;
// TRIGGER updateUI() in MyActivity! HOW?
}
}
/**
* Application class. I'm planning to keep data handler here, and reference it from activities when required.
*/
public class MyApplication extends Application {
private DataHandler dataHandler;
public DataHandler getDataHandler() {
return dataHandler;
}
public void onCreate() {
DataHandler dataHandler = new DataHandler();
}
}
/**
* Activity
*/
public class MyActivity extends Activity {
DataHandler dataHandler;
public void onCreate(Bundle o) {
dataHandler = ((MyApplication) getApplication()).getDataHandler();
}
public void onResume() {
// trigger data refresh (OBS! This could also be by a button press etc.)
dataHandler.getData();
}
public void updateUI() {
// UPDATE UI
// should be called on DataHandler when data is received. HOW?
}
}
Register your activity as a listener to the DataHandler and when the thread recieves data invoke any listeners.
How are you presenting the data? If it's a ListView with an ArrayAdapter, then simply invoke the notifyDataSetChanged() on it as you get an update.
You'll have to make sure you update the UI in an appropriate UI thread, of which there are many ways. One that springs to mind is you could create a blocking AsyncTask that receives the listener events, unblocks it's background thread and runs its publishProgress() to ensure the update happens on the UI.

Categories