we have two activities one is where we make the connection via bluetooth and managing the blutooth other one is the update the UI where we want to update the GUI containing the TextViews.
We successfully send and recieve the message within two activities and vice versa.
private OnMessageReceivedListener dataReceivedListener = new OnMessageReceivedListener() {
public void OnMessageReceived(String device, String message) {
//t.setText(message);
Log.d("Message" , message);
msg = message;
UpdateGUI();
}
};
THE above function recieves the message and we did that successfully.
private void UpdateGUI() {
//i++;
//tv.setText(String.valueOf(i));
myHandler.post(myRunnable);
}
final Runnable myRunnable = new Runnable() {
public void run() {
btBoard.UpdateYoursBoard(mystring);
}
};
The above function of connection class calls the method of our GUI class and send a recieved message to it.
In our GUI class we want this
public void UpdateYoursBoard(String positions)
{
Log.d("Positions" , positions);
tv.setText(positions);
};
we successfully recieved the message in log.d but when we want to change our textview text it gives following errors.
java.lang.NullPointerException
at net.clc.bt.Board.UpdateYoursBoard(Board.java:3460)
NOTE : we are working with bluetooth and we have 3 mobile connected simultaneously and UpdateYourBoard will change the TextViews of 3 mobiles GUI's.
kindly help me to fix the problem.
Thanks in advance
First your Board class is far too big. 3 500 lines in a java file is very bad idea. Design more, decouple and split things. You are missing the divide and conqueer principle of IT.
In your case, tv is null. How and when do you get a reference to it ? If you used findViewById in your onCreate method (after super.onCreate has been called), it should work.
The reference to your TextView 'tv' is null. Initialize it somewhere using findViewById() or some other appropriate method.
Check your scopes etc so that the reference is maintained properly at the point where you call the setText() method.
Related
I'm implementing a chat client.
Everytime user clicks Send message button - I perform a Realm insert of this message.
I have a service 'waiting' for this change to send this message via socket.
Like this:
Observable<RealmResults<RealmMessage>> observable = getUnsentMessages();
subscribeUnsendMessages = observable
...
.subscribe(message -> {
launchMessageSending(message);
});
and method for getting this observable looks like this:
public Observable<RealmResults<RealmMessage>> getUnsentMessages() {
final Realm instance = getRealmInstance();
return instance.where(RealmMessage.class)
...
.findAllAsync()
.asObservable()
.filter(o -> ... )
.doOnUnsubscribe(instance::close);
}
And here is the problem - there is a corner case, when I perform two operations roughly at the same time.
The second one looks like this:
public boolean shouldTrack(#NonNull RealmChat chat) {
getRealmInstance().executeTransactionAsync(realm ->{
RealmTrackedState trackedStates = realm.where(RealmTrackedState.class).findFirst();
trackedStates.getRealmChats().add(chat);
});
return true;
}
The above method is a tracking cache for remembering if I tracked given chat or not.
(This is a bit more complicated than this, bear with me).
This PROBABLY causes the observer to react on the second database change.
Because these two operations happen almost at the same time - the second notification is still "valid" because there is an unsent message.
So, questions:
Am I right?
If so - how should I handle this?
I don't really want to 'delay' the shouldTrack(); method because I'm afraid that the same problem will occur in a different way.
Maybe create a flag for this message being 'handled', so the second will be ignored - but this is a bit nasty I guess. The second 'send' shouldn't happen.
EDIT:
Here is my TrackedState object
public class RealmATrackedState extends RealmObject {
#PrimaryKey
private int id = 1;
private RealmList<RealmChat> realmChats;
private boolean isSomething;
}
Is updating such object (as posted above) causing RealmMessage table be notified?
Ok, so ive spend two days on this and I have tried everything under the sun and Google :L
Basically, if I add or delete something from my server, I want to update my listview which is in mylistfragment from my detailfragment to reflect the changes on the server. The changes have occur ed through clicking either a delete or add button in my detail fragment.
I have a callback method which has everything that I need to repopulate the listview with I just cant seem to get the listview to update.
Any help would be much appreciated.
My callback code is as follows :
public final Handler myCallBackAll = new Handler() {
#Override
public void handleMessage(Message msg) {
ListView lv = (ListView) view.findViewById(R.id.listView1);
if (msg.obj == "No Response") {
TextView tv2 = (TextView) view.findViewById(R.id.textView2);
tv2.setText("No Response. Please check your internet connection");
tv2.setVisibility(View.VISIBLE);
lv.setVisibility(View.INVISIBLE);
} else {
Beer beers = new Beer();
ArrayAdapter<Beer> arrayAdapter = new ArrayAdapter<Beer>(
getActivity(), android.R.layout.simple_list_item_1,(List)msg.obj);
lv.setAdapter(arrayAdapterNew);
arrayAdapter.notifyDataSetChanged();
}
}
};
It doesnt throw any errors just doesnt work
How my callback is called is here
if (isBound) {
myBinder.getAllBeer(myCallBackAll);
}
Its a bounded service I have to use, a stipulation of the project. All this code works, just mylistview wont update
You say that you have already have the callback set up, so I am assuming the callback is being fired accordingly. If that is the case, make sure you update the data source (Array, List, etc) you are using in your adapter to reflect the changes you made in detailfragment.
Also, don't forget that every time you add, edit, delete data from your adapter's data source, you must call mAdapter.notifyDataSetChanged() to tell the adapter something in your data changed.
EDIT
Try creating your handler this way instead: public final Handler myCallBackAll = new Handler(Looper.getMainLooper())
notifyDataSetChanged() must be executed on the main UI thread. When you create a new handler it will execute on its own thread, so you need to make sure it does execute on the UI thread. Take a look at here for more information
finally figured it out, may not be the best approach but it does work, i had declare my listview as a static variable in my main activity, i then reference this variable in both fragments and it works a treat :P
I create an app that like dictionary app. When the user types in an Edittext, I call an AsyncTask to compute and update the result to the screen (I put the UI update code in onPostExecute() method ). However, when you type little fast, the eddittext become not responesive (a little latency). I think this promblem occurs because many AsyncTasks are running (each AsynTask for an input letter). So, I think I need to stop the first task before calling new task. Am I right? What should I do in this situation?
You don't need to implement the filter method in an async task. I call filter method on data when first letter has been written in editbox and save the result in an temporary array, then when another letter has been written, I call filter method on the temporary data which technically has less information than the original data. By doing this, the dimmension of data set decreases as you type in editbox. Also, you can use this method to store previous data set so when you press backspace, you don't have to call filter method again, you just go to previous saved temporary data set. For me, it works fine and I don't have to use async task because it is efficient
I suggest you another approach: use only one thread. The searching thread should wait for searching data > do search > and sleep until new data. E.g.:
private static class SearchThread extends Thread{
private Object monitor = new Object();
private String value;
public void search(String value){
this.value = value;
synchronized (monitor){monitor.notify();}
}
#Override
public void run() {
while(true){
try {System.out.println("Wait for search data."); synchronized (monitor){monitor.wait(); }
} catch (InterruptedException e) {e.printStackTrace();}
System.out.println("Searching for " + value);
}
}
}
I've tried the following approaches to try to get the TextView to update from the model:
TextChangeListeners - error
Other Threads
asynctask
Added a refresh button which updates the data, I force the click
Scenario is as follows:
Standard thread running which updates the Model (MVC) object every second, which works perfectly.
When the Model object is updated, it notifies all classes which implement "Observer".
My GolfHomeScreen extends Activity and implements Observer (code below).
The GolfHomeScreen.update (Observable observable, Object data) method works perfectly. It executes every second as expected and S.O.P the correct data (see --> //* #1 *).
This then kicks off a Thread. I read on this site that you have to UI Thread to execute code which updates widgets and then run the "runOnUiThread" method - the code looked something like I have done below but I found it a little hard to follow. Anyway, this thread runs (see --> //* #2 ) which then executes method onClick(View v) (see --> // #3 *).
System.out.println("driverType :" + mvcModel.getDriverName()); (see --> //* #4 *) works perfectly.
//* #5 * - it MUST update but it doesn't.
If I actually physically click the button, the data is displayed correctly on the screen. My only guess is that the screen must not refresh on the forced click or else I am not using the UI thread to make the update.
NOTE: If the code below is missing something, it is because I removed a ton of code to simplify the understanding of what's going on.
public class GolfHomeScreen extends Activity implements Observer
{
GolfHomeScreen golfHomeScreen = null;
TextView driverName = null; // Type of driver used by golfer (eg: 1 wood)
Button refreshData = null;
#Override public void onClick(View v) //*** #3 ***
{
if ((v.getId()) == 12345) // ID of wood (12345 = 1 wood)
{
//*** #4 ***
System.out.println("driverType :" + mvcModel.getDriverName()); //THIS PRINTS OUT THE LATEST DATA!!!
//*** #5 ***
driverName.setText(String.valueOf(mvcModel.getDriverName())); //THIS DOESN'T AFFECT THE SCREEN?? WHY :-(
}
}
#Override public void onCreate(Bundle savedInstanceState)
{
golfHomeScreen = this;
refreshData = indViewById(R.id.golfhomescreen_button_refreshData);
driverName = (TextView) findViewById(R.id.golfhomescreen_text_drivername);
}
#Override public void update(Observable observable, Object data)
{
// #1 ***
System.out.println("driverType :" + mvcModel.getDriverName());
golfHomeScreen.runOnUiThread(new Runnable()
{
#Override
public void run()
{
refreshData.performClick(); //*** #2 ***
}
});
}
}
I'll run a few suggestions and a few fixes and hopefully your problem will be gone.
I'm saying that because conceptually you do have some wrong stuff, and my answer is kind of fixing those concepts:
remove GolfHomeScreen golfHomeScreen = null; and golfHomeScreen = this; you don't need an object referencing to itself. It's just making confusion. This line golfHomeScreen.runOnUiThread(new Runnable() you should just call runOnUiThread(new Runnable()
Change System.out.pr*** to Log.d(TAG, MESSAGE); that's just because that is Android specialised way of dumping logs and it won't really matter for your result. It's nicer than standard Java System.out because allows you to filter those logs by TAG and severity.
Do never call refreshData.performClick(); or anything similar to that because you want the action inside that button to be performed. If you want a certain thing to happen from more than one source, create a method doThatThing(), put the actions in there, and from the Click and from the Update, you call the method. The way you're doing is a bit of a "Rube Goldberg machine" that is updating something, to click a button, to change a text. Just change the text.
do never compare a view ID with a number if ((v.getId()) == 12345) the ID of views created from XML are generated by the system during compilation and you can't know if it's a fixed number. You should compare with the static int ID of that view, like this : if(v.getId() == R.id.golfhomescreen_text_drivername). If the view was not created in XML (which is not the case here), you can compare with the actual object if(v.equals(driverName))
with those changes I believe your code will work. Make sure to let me know and mark as correct answer if in fact does.
in my android application at some event in an activity I want to ask the user for a name (string). I know how to do this: call showDialog, create the dialog in the Activity.onCreateDialog method (I need to supply a string for the label) and handle the result in the onClick of the dialog. This works fine and to my satisfaction.
BUT this way I have three different places, where this simple task spreads throughout the code of my activity. I would much more prefer to keep this code together, to write some code like this:
string result;
if (showSimpleEditDialog(idForLabelString, result)==DIALOG_OK)
{
// do something with the result
}
or maybe with a class instance
SimpleEditDialog dlg = new SimpleEditDialog(idForLabelString);
if (dlg.showModal()==DIALOG_OK)
{
string result = dgl.getResult();
// do something with the result
}
(The "idForLabelString" would be some resource id for the label to use, DIALOG_OK would be some constant returned when the user clicks OK)
I know, I would have to write this methodes or this class. But for better readibility of my code I would do it. Any suggestions?
Thank you,
Gerhard
"BUT this way I have three different places, where this simple task spreads throughout the code"
So why don't you create a Method for this task? What you are talking about sounds like some sort of 'ActionListener' to me. This can be done in Java/Swing, but not in Android.
But, if you have three Dialogs, which all need to do the same when "YES" e.g. "NO" is pressed, you could define the 'DialogInterface.OnClickListener()' as a global inner-Class (or in a second class which extends the 'onClickListener') and then use it for all the Dialogs.
Now actually the problem with modal dialogs is mostly a problem with programm flow. You want to keep things together that belong together. You want to display a dialog that returns "ok" or "cancel" and additionaly e.g. a string that the user entered into one of the dialog widgets.
I do not want to write half of the code up to the line where I need the result of the dialog on one place and the rest of the code on another place namely the onClickListener of the dialog.
In some scenarios the first dialog might invoke a second dialog e.g. to specify a color which is not in the list of the first dialog's ListView.
Your code will be scattered all over the place (in each dialog's button onClickListener) and will be hard to read or to maintain.
Now after having written some unclear code like that I came up with the following solution which certainly respects the android design guides.
Instead of directly showing a dialog I create a Handler derived class which handles messages.
I send it a first message which creates and shows a dialog. It also forwards the handler to the dialog and the diaolg in it's onStop method sends another message to the handler, indicating the end of the dialog. There you can examine the dialogs properties, the contents of the edit fields or whether it was stopped with OK or CANCEL.
Now in the message handler all the logic of the task sits in different cases of the messages arg1 value.
Some cases might be skipped (e.g. the user selected a standard color and did not need a special color dialog).
The dialogs are independant of the scenario from which they are called and in their code only reflect their simple task (selecting from a list, some checkboxes etc.). They may be reused from other scenarios.
Following a kind of a template how to use this approach:
public class DoSomethingWithDialogs extends Handler
{
Context context; // from which it was called
final static int stepBegin = 0;
final static int stepNext = 1;
final static int stepSomethingElse = 2;
final static int stepLast = 3;
protected DoSomethingWithDialogs(Context context)
{
this.context = context;
}
public static void start(Context context)
{ // this is the main (only) entry point from outside
DoSomethingWithDialogs st = new DoSomethingWithDialogs(context);
st.sendMessage(st.obtainMessage(0, stepBegin, 0));
}
#Override
public void handleMessage(Message msg)
{
// step by step handling the task
switch (msg.arg1)
{
case stepBegin:
{
SomeDlg somedlg = new SomeDlg(context, this, stepNext);
// when the dialog closes, it sends a message to this with stepNext as arg1
somedlg.show();
}
break;
case stepNext:
{ // this message was send by the dialog when it finished
SomeDlg somedlg = (SomeDlg) msg.obj;
if (msg.arg2 == Dialog.BUTTON_NEGATIVE)
{
// has been canceled, nothing to do
} else
{
if (somedlg.someProperty)
{
} else
{
sendMessage(obtainMessage(0, stepSomethingElse, 0));
}
}
}
break;
case stepSomethingElse:
break;
}
}
}