I'm trying to create a chat bot. I need to simulate an interactive response from app.The response doesn't come from sever it's embedded inside app.
I'm using recycleview to implement chat UI, I need to delay every message for a specific time so user feels that someone is actually talking to him.
private void displayNewMessage(ArrayList<ChatMessage> messages) {
for (int i = 0; i < messages.size(); i++) {
chatMessages.add(messages.get(i));
}
adapter.notifyDataSetChanged();
}
The previous method is used to push an array of messages to user, how can I delay adding every element to adapter. or push them all to adapter and delay displaying them in adapter it self?
I tried to use Handler but it didn't work, it delays all messages and pushes them all together.
It's a logical question more than programming.
At first why it delays all messages and pushes them all together - because the for loop, it will add them to adapter at once.
An alternative solution is to use handler on some where else suppose on user sending message thread.
assume we have the user sendMessageButton we can make some nice logic there.
We will add message and a time for wait, you can make it Random time, e.g:
sendMessageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
chatMessages.add(newMessage);
adapter.notifyDataSetChanged();
}
},random);
}
});
In your for loop after adding data to arrat put delayedpost on recycler and call notify inside the run method, this will simulate delay for each message, instead of delay and then showing all messages at once
You can use Handler.post delay(new Runnable(),3000);
You put your code under their runnable interface run method it will start with after delay seconds.
Related
My scenario is an onCreate() activity method which executes the following code (simplified):
dialog.show(); //loading wheel
try {
remote.sendRequest(myData, new MyHandler());
}
catch (Exception e) {
dialog.dismiss();
//log and react
}
class MyHandler extends SDKSpecificCompiledHandler {
#Override
public void failure() {
dialog.dismiss();
//do stuff
}
#override
public void success() {
dialog.dismiss();
//do stuff
}
}
//I have read-only access to this handler!
public abstract class SDKSpecificCompiledHandler {
public abstract void success(JSONObject successData);
public abstract void failure(JSONObject errorData);
}
Explanation: A remote service is called passing an handler that gets called when he's done. A loading wheel (dialog) is shown to the user until a success, failure or exception happens.
The problem is when the service gets successfully called but no response ever comes. In that case dialog.dismiss() doesn't get called and the loading wheel keeps spinning for ever.
What I need is a sort of timeout which dismisses the dialog (and possibly takes other actions) after some seconds if the server doesn't get back.
My first though would be to create a new thread for the service call, and right after the launch set a timer which dismisses the dialog.
Would it be a good idea?
Thank you,
EDIT:
The service is third-party/not editable. I'm using a pre-compiled artifact.
Still not really sure what you're trying to achieve but if you want to run some code after some time on main thread (i.e. your code will do stuff to the UI), you can use a android.os.Handler
mHandler = new Handler(getMainLooper());
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
// do stuff on UI thread
}
},10000);
When your call returned from the server, simply cancel the messages on the queue:
mHandler.removeCallbacksAndMessages(null);
It is better to use time out in service call itself, You can set the time out with service , If you need know how to set the time out then I should know what kind of service you are using ?
One more thing is that if you are using a loader you should make that loader in such a way that it can be cancel by the client.
So, I have an activity with a handler.
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
matches = LiveAPI.getMatches();
listAdapter.notifyDataSetChanged();
}
LivePage.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Here I get some data and update my list with it. It works.
When I click on an item of my list, this functon is called
private void showLiveMatch(int position) {
Intent i = new Intent(this, LiveMatch.class);
i.putExtra("match", matches.get(position));
startActivity(i);
}
My new activity appears, wich also contains another handler:
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
match = LiveAPI.getMatch(match.getId());
displayCommentaries();
}
LiveMatch.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Sometimes this works as I want.
But in some cases it seems like in second activity is still called LiveAPI.getMatches() from the first handler rather than LiveAPI.getMatch(match.getId());
Every function displays a console text, and that's how I figure it out what function is called.
Can someone explain me why?
Once you post either m_Runnable (from LivePage or LiveMatch), it does its stuff and then schedules itself to run in 5 seconds. Basically, each time you start one with a click, it creates an infinite loop. Enough clicks and you will have the logic for each of these running constantly. (That is, unless you have some other code that periodically calls mHandler.removeCallbacks(m_Runnable); that you haven't shown us.) Without knowing more about what you're trying to do, it's hard to recommend how to fix this, but you should somehow avoid creating these kind of infinite loops.
Be aware that all handlers you create on the UI thread simply feed Runnable objects into the (single) MessageQueue for the thread. So there's no such thing as something being called from one handler or another.
Hey guys I am having an issue that a method I am trying to run every thirty seconds is causing my toggle button to crash. My goal is to send data to a database based on the button click, and while the toggle button is on to continue sending that data through a method every thirty seconds. When I click the button, I get the Unfortunately error and the app crashes.
To save the length of this post, this button to send the data only one time works fine:
uploadOnce.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view) {
try {
SendCode(socket);
}catch(Exception e){
String stackTrace = Log.getStackTraceString(e);
sendEmail(stackTrace);
}
}
});
Notice that the above button click uses the SendCode method and it works correctly.
The error that I am having is using that same method with a timer on it, like so:
This is the toggle button onClick:
toggle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
if (toggle.isChecked()) {
makeToast("On");
sendForever();
}
}catch (Exception e){
String stackTrace = Log.getStackTraceString(e);
sendEmail(stackTrace);
}
}
});
If I take the sendForever() method out, the toggle button works fine as expected.
This is the sendForever method in the toggle button:
public void sendForever(){
if(toggle.isChecked()) {
while (toggle.isChecked()) {
try {
new Handler().postDelayed(new Runnable() {
// Runs a timer to send code to database every 30 seconds
#Override
public void run() {
try {
SendCode(socket);
} catch (Exception e2) {
String stackTrace = Log.getStackTraceString(e2);
sendEmail(stackTrace);
}
}
}, 30000);
} catch (Exception e) {
String stackTrace = Log.getStackTraceString(e);
sendEmail(stackTrace);
}
sendForever();
}
}
}
So the goal is that when this method is called, it checks to see if the toggle button is in the "ON" state, then while it is on it will run the SendCode method (which works fine in the button to send it only once) then wait 30 seconds. After the 30 seconds is over I am going to call the method again until the toggle button is hit again and breaks the loop.
My problem I am having is that I am using this on an OBD2 sensor in my car, and it is not hitting the sendEmail methods to shoot me a stacktrace of the error, so I am not able to post the stacktrace as of now.
If anybody has any advice on what is going wrong or what I can look at to fix this, it would be greatly appreciated. Once again, sorry for not being able to put the stacktrace up right now, I will edit the post if I am able to acquire it.
You call sendForever() from the method itself (in a loop, even). That will result in a stack overflow as the recursion is limited only by the toggle condition. Just remove the recursive call, since you already have the loop handling the repetition (well, that would solve the stack overflow, but see next paragraph for further issues).
Note also that you have a blocking task running in the UI thread. Since you block the UI thread, the toolkit will have no chance to make the button not toggled anymore, essentially locking up your application. Simplest is probably checking the condition after the previous sending is done, and schedule a new one if needed.
A side note: It's needless to do an if (toggle.isChecked()) check in sendForever() since you have the same condition in the while loop.
try to dump the stack trace on file system instead of email... may be your whole application is crashing
or may be you should post the code of SendCode(socket) that function might be locking some resources that are not released in 30 sec i.e. before the next function call is made
I would like to have an application which either loads or saves data through a HTTP request, however the data must interact with the UI thread. Ideally, I would like a single thread to use an IF statement on a message to determine if the request is to "load" or "save".
What would be the simplest way of doing this with the smallest amount of code?
Also, do instances of Handlers run on individual threads?
EDIT: This is the code I am using now:
Handler doStuff = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 1){
// Load all the information.
// Get the ID from sharedPrefs
SharedPreferences details= getSharedPreferences("details", 0);
String ID = patDetails.getString("id", "error");
// Load up the ID from HTTP
String patInfo = httpInc.getURLContent("info.php?no="+AES.encrypt("387gk3hjbo8sgslksjho87s", ID));
// Separate all the details
patientInfo = patInfo.split("~");
}
if(msg.what == 2){
// Save the data
}
}
};
Eclipse halts the debugging and displays, "Source not found" for StrictMode.class
I suppose it's because it's using the Main thread to access the internet although it's running in individual threads.
Any idea.
Handlers do run on individual threads. Check that link. You should also check out AsyncTask.
I would propose submitting the jobs as Runnable to a single-threaded ExecutorService:
public class SomeClass {
private ExecutorService execService = Executors.newSingleThreadExecutor();
public void doSomething() {
final String someUiData = // retrieve data from UI
execService.submit(new Runnable() {
#Override
public void run() {
// so something time-consuming, which will be executed asynchronously from the UI thread
// you can also access someUiData here...
}
});
}
}
This way, the UI thread will not block whereas you can easily submit a different Runnable for different operations and the ExecutorService will completely take care of keeping it async.
Edit: If you need to interact with the UI, do so before becoming asynchronous and keep the result in final variables.
I first want to say I used google a lot to find a progress bar that fills itself when time passes. All results I found where either with a thread or with an Asynctask. As being new to Android, I thought it was easier to accomplish with an extra Handler that handles the updates of the progressbar.
However, I did not find anyone doing it my way. Does it maybe violate Android rules? For example, can I use multiple Handlers at the same time?
My code looks like:
public void restarttimebar()
{
stoptimebar();
for(int i=1;i<12;i++)
{
Message msg = timebarhandler.obtainMessage(0,i,0);
timebarhandler.sendMessageDelayed(msg, i*250);
}
};
public void stoptimebar()
{
timebarhandler.removeMessages(0);
Message msg = timebarhandler.obtainMessage(0,0,0);
timebarhandler.sendMessage(msg);
};
Handler timebarhandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
ProgressBar progressbar = (ProgressBar)findViewById(R.id.timebar);
if (msg.arg1 == 0)
{
progressbar.setProgress(0);
}
if (msg.arg1 > 0)
{
progressbar.setProgress(msg.arg1*9);
}
}
};
Now one can call restarttimebar(); to (re)start the progress bar. It will fill over 3 seconds with increments at each 0.25 second. Any remarks greatly appreciated!!
EDIT: Also added a stoptimebar(); to just stop the progressbar. Also, the standard size of a progressbar is 100. So I just make the twelve updates times 9. It is almost 100 ;) The bar does not have to be THAT very precise in my application.
As far as i know, the threads you create and Asynctasks (Non-UI-Threads) should not touch UI-stuff like your progressbar. If you need your task communicate with the progressbar, use Asynctask and make sure that UI related actions are done in onPostExecute(). This method will be also called by the main UI Thread.
I guess my method of updating the progress bar can be seen as correct. So for anyone who googles and has the same kind of question: Use the code in the question!