I'm building a UI in which I'm using ListView to hold data about questions that users ask. Whenever a new question is created by the user, I try to update the listview. The problem right now is that the data is updated but not right away. After adding a question, I need to navigate to another screen and then come back to see the updated list. This is also causing some other problems that I would like to fix (layout is not getting properly displayed)
This is the code for my Activity:
public class QuestionsScreen extends Activity {
.....
.....
.....
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_questions_screen);
.....
questions=new ArrayList<String>();
qId=new ArrayList<Integer>();
.....
.....
//building API
resourceApi = ApiBuilder.getResourceApi(token);
// calling API function to get questions from db
resourceApi.listQuestions(groupId, new Callback<List<Question>>(){
#Override
public void failure(RetrofitError arg0) {
// TODO Auto-generated method stub
}
#Override
public void success(List<Question> arg0, Response arg1) {
// TODO Auto-generated method stub
for(Question q:arg0)
{
questions.add(q.getTitle());
qId.add(q.getId());
}
}
});
adapter= new ArrayAdapter<String>this,android.R.layout.simple_list_item_1,questions);
lv.setAdapter(adapter);
.....
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
LayoutInflater inflater = getLayoutInflater();
final View x;
x = inflater.inflate(R.layout.groupdialog, null);
dialog.setView(x);
dialog.setTitle("Add question");
TextView t= (TextView)x.findViewById(R.id.dialogTv);
t.setText("Please type in the question");
dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface d, int which) {
// TODO Auto-generated method stub
name = (EditText) x.findViewById(R.id.dialog_groupName);
out = name.getText().toString();
addQuestion();
d.dismiss();
}
});
dialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface d, int which) {
// TODO Auto-generated method stub
d.cancel();
}
});
alert = dialog.create();
//button to ask a new question
newQ.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
alert.show();
}
});
}
This is the function which is called when "Add new question" button is pressed:
public void addQuestion()
{
resourceApi.createQuestion(groupId, out, new Callback<Question>(){
#Override
public void failure(RetrofitError err) {
// TODO Auto-generated method stub
}
#Override
public void success(Question q, Response response) {
// TODO Auto-generated method stub
// adapter.add(q.getTitle());
questions.add(q.getTitle());
qId.add(q.getId());
}
});
adapter.notifyDataSetChanged();
Toast.makeText(QuestionsScreen.this, "New Question created",Toast.LENGTH_LONG).show();
}
The toast is displayed. However, the list view is not updated with the new question. I tried using adapter.add() as well but it just caused some other problems so I don't want to use that.
Can anyone suggest a better way or point out what I'm doing wrong?
You have to notify you data in the callback (success function)
Try something like this :
resourceApi.createQuestion(groupId, out, new Callback<Question>(){
#Override
public void failure(RetrofitError err) {
// TODO Auto-generated method stub
}
#Override
public void success(Question q, Response response) {
// TODO Auto-generated method stub
adapter.add(q.getTitle());
questions.add(q.getTitle());
qId.add(q.getId());
//Notify once you have add something in questions
adapter.notifyDataSetChanged();
}
});
Related
I am using Freshsmvvm in my project and I want to display a list of operations,
this is my method from the crud
public List<Operation> GetAll()
{
try
{
return connection.Table<Operation>().ToList();
}
catch (Exception ex)
{
StatusMessage = $"Error: {ex.Message}";
}
return null;
}
In my viewModel i'm have a list and a method to obtain the saved records
private List<Operation> _listOp;
public List<Operation> ListOp
{
get { return _listOp; }
set
{
_listOp = value;
RaisePropertyChanged();
}
}
private void GetOp()
{
ListOp = App.OperationRepository.GetAll();
}
*add the GetOp method in the constructor to load in the collectionview*
public override void Init(object initData)
{
GetOp();
}
What happens is that the list does not update, I have to close the application and when I open it again, the entered record appears.
This is the list without adding a new record
This is the list with a log after restarting the app
You can use the method OnAppearing() to refresh your list.
protected override async void OnAppearing()
{
base.OnAppearing();
ListOp = App.OperationRepository.GetAll();
}
I have implemented simple RxEventBus which starts emitting events, even if there is no subscribers. I want to cache last emitted event, so that if first/next subscriber subscribes, it receive only one (last) item.
I created test class which describes my problem:
public class RxBus {
ApplicationsRxEventBus applicationsRxEventBus;
public RxBus() {
applicationsRxEventBus = new ApplicationsRxEventBus();
}
public static void main(String[] args) {
RxBus rxBus = new RxBus();
rxBus.start();
}
private void start() {
ExecutorService executorService = Executors.newScheduledThreadPool(2);
Runnable runnable0 = () -> {
while (true) {
long currentTime = System.currentTimeMillis();
System.out.println("emiting: " + currentTime);
applicationsRxEventBus.emit(new ApplicationsEvent(currentTime));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable runnable1 = () -> applicationsRxEventBus
.getBus()
.subscribe(new Subscriber<ApplicationsEvent>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onNext(ApplicationsEvent applicationsEvent) {
System.out.println("runnable 1: " + applicationsEvent.number);
}
});
Runnable runnable2 = () -> applicationsRxEventBus
.getBus()
.subscribe(new Subscriber<ApplicationsEvent>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onNext(ApplicationsEvent applicationsEvent) {
System.out.println("runnable 2: " + applicationsEvent.number);
}
});
executorService.execute(runnable0);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(runnable1);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(runnable2);
}
private class ApplicationsRxEventBus {
private final Subject<ApplicationsEvent, ApplicationsEvent> mRxBus;
private final Observable<ApplicationsEvent> mBusObservable;
public ApplicationsRxEventBus() {
mRxBus = new SerializedSubject<>(BehaviorSubject.<ApplicationsEvent>create());
mBusObservable = mRxBus.cache();
}
public void emit(ApplicationsEvent event) {
mRxBus.onNext(event);
}
public Observable<ApplicationsEvent> getBus() {
return mBusObservable;
}
}
private class ApplicationsEvent {
long number;
public ApplicationsEvent(long number) {
this.number = number;
}
}
}
runnable0 is emitting events even if there is no subscribers. runnable1 subscribes after 3 sec, and receives last item (and this is ok). But runnable2 subscribes after 3 sec after runnable1, and receives all items, which runnable1 received. I only need last item to be received for runnable2. I have tried cache events in RxBus:
private class ApplicationsRxEventBus {
private final Subject<ApplicationsEvent, ApplicationsEvent> mRxBus;
private final Observable<ApplicationsEvent> mBusObservable;
private ApplicationsEvent event;
public ApplicationsRxEventBus() {
mRxBus = new SerializedSubject<>(BehaviorSubject.<ApplicationsEvent>create());
mBusObservable = mRxBus;
}
public void emit(ApplicationsEvent event) {
this.event = event;
mRxBus.onNext(event);
}
public Observable<ApplicationsEvent> getBus() {
return mBusObservable.doOnSubscribe(() -> emit(event));
}
}
But problem is, that when runnable2 subscribes, runnable1 receives event twice:
emiting: 1447183225122
runnable 1: 1447183225122
runnable 1: 1447183225122
runnable 2: 1447183225122
emiting: 1447183225627
runnable 1: 1447183225627
runnable 2: 1447183225627
I am sure, that there is RxJava operator for this. How to achieve this?
Your ApplicationsRxEventBus does extra work by reemitting a stored event whenever one Subscribes in addition to all the cached events.
You only need a single BehaviorSubject + toSerialized as it will hold onto the very last event and re-emit it to Subscribers by itself.
You are using the wrong interface. When you susbscribe to a cold Observable you get all of its events. You need to turn it into hot Observable first. This is done by creating a ConnectableObservable from your Observable using its publish method. Your Observers then call connect to start receiving events.
You can also read more about in the Hot and Cold observables section of the tutorial.
I'm trying to handle a DropDownChoice onchange event in a listView that can display a modal window. It seems working fine for first element but not for subsequent added elements.
final ModalWindow modal = new ModalWindow("modal");
modal.setOutputMarkupId(true);
form.add(modal);
final ListView<CommandeFournisseurDetails> myView = new ListView<CommandeFournisseurDetails>(
"rowsList",
new PropertyModel<List<CommandeFournisseurDetails>>(this,
"rows")) {
#Override
protected void populateItem(
final ListItem<CommandeFournisseurDetails> item) {
final CommandeCollectionJDBC myCollection = new CommandeCollectionJDBC();
CommandeFournisseurDetails row = item.getModelObject();
item.add(new Label("index",
new AbstractReadOnlyModel<Integer>() {
#Override
public Integer getObject() {
return item.getIndex() + 1;
}
}));
final DropDownChoice<String> ID_PRODUIT = new DropDownChoice(
"ID_PRODUIT", new PropertyModel<String>(row,
"ID_PRODUIT"), myCollection.getProduit());
ID_PRODUIT.setOutputMarkupId(true);
ID_PRODUIT.setMarkupId("ID_PRODUIT");
ID_PRODUIT.setLabel(Model.of("Produit"));
ID_PRODUIT.setRequired(true);
AjaxFormComponentUpdatingBehavior behavior = new AjaxFormComponentUpdatingBehavior(
"onChange") {
protected void onUpdate(AjaxRequestTarget target) {
if (!ID_PRODUIT.getDefaultModelObjectAsString()
.isEmpty()) {
final PageParameters params = new PageParameters();
params.set("message",
ID_PRODUIT.getDefaultModelObjectAsString());
params.set("type", "Produit");
modal.setPageCreator(new ModalWindow.PageCreator() {
public Page createPage() {
// Use this constructor to pass a reference
// of this page.
return new ModalContentPage(modal, params);
}
});
modal.show(target);
target.add(modal);
target.add(ID_PRODUIT);
}
}
protected void onError(AjaxRequestTarget target,
RuntimeException e) {
System.out.println(e.toString());
}
};
ID_PRODUIT.add(behavior);
AbstractSubmitLink remove = new SubmitLink("removeRowLink") {
#Override
public void onSubmit() {
getList().remove(item.getModelObject());
getParent().getParent().removeAll();
};
}.setDefaultFormProcessing(false);
item.add(remove);
}
}.setReuseItems(true);
form.add(new SubmitLink("addRowLink") {
#Override
public void onSubmit() {
rows.add(new CommandeFournisseurDetails());
}
}.setDefaultFormProcessing(false));
myView.setOutputMarkupId(true);
form.add(myView);
Any idea why the other elements do not inherit the same event?
Thanks for your help.
All ID-PRODUIT dropdownchoices (the first, but also the rest) have the same markupId, thanks to:
ID_PRODUIT.setMarkupId("ID_PRODUIT");
Try giving them a unique MarkupId. Perhaps by adding the index of the listitem:
ID_PRODUIT.setMarkupId("ID_PRODUIT" + item.getIndex());
or remove that line of code altogether.
I have the following code:
try {
res = new Utils(ubc_context).new DownloadCalendarTask().execute().get();
} catch (InterruptedException e) {
Log.v("downloadcalendar", "interruptedexecution : " + e.getLocalizedMessage());
res = false;
} catch (ExecutionException e) {
Log.v("downloadcalendar", "executionexception : " + e.getLocalizedMessage());
res = false;
}
Log.v("displaymenu", "A");
public class Utils {
private Context context;
public Utils(Context context) {
this.context = context;
}
public class DownloadCalendarTask extends AsyncTask<Void, Void, Boolean> {
private ProgressDialog dialog;
public DownloadCalendarTask() {
dialog = new ProgressDialog(context);
}
protected void onPreExecute() {
Log.v("preexecute", "A");
dialog.setMessage("Loading calendar, please wait...");
Log.v("preexecute", "B");
dialog.show();
Log.v("preexecute", "C");
}
protected Boolean doInBackground(Void... arg0) {
// do some work here...
return (Boolean) false;
}
protected void onPostExecute() {
Log.d("utils", "entered onpostexecute");
dialog.dismiss();
}
}
}
The first part of code is attached to an onClick listener for a button. When I click the button the button flashes (as it does to show it has been clicked), and then after about 8 seconds the Loading dialog appears but never finishes.
According to logcat, as soon as I click the button onPreExecute is executed as is Dialog.show(), so my first problem is why is there this 8 second delay? During these 8 seconds, logcat shows that doInBackground is being executed. However, according to logcat (this is the second problem) onPostExecute is never called (and so Dialog.dismiss()) is never run.
Logcat shows that everything following DownloadCalendarTask().execute().get() is being executed, so it's as if onPostExecute has just been skipped.
Many thanks for your help!
You are calling AsyncTask.get() which causes the UI thread to be blocked while the AsyncTask is executing.
new DownloadCalendarTask().execute().get();
If you remove the call to get() it will perform asynchronously and give the expected result.
new DownloadCalendarTask().execute();
Edit:
You will also need to update the parameters to your onPostExecute method, they need to include the result. e.g.
protected void onPostExecute(Boolean result) {
what i am trying to do is that on click of a button in screen1, i try push the screen2 repeatedly with different images and different Transition Context.
the code is as follows
public void fieldChanged(Field field, int context)
{
if(field==slideButton)
{
for(int i=0;i<bitmaps.length;i++)
{
slideScreen = new SliderScreen(bitmaps[i]);
UiApplication.getUiApplication().pushScreen(slideScreen);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
UiApplication.getUiApplication().popScreen(slideScreen);
}
}
}
}
Problem is that nothing appears.Is there any other way to achieve this..
Fixed version of your initial idea:
public void fieldChanged(Field field, int context) {
if (field==slideButton) {
final UiApplication app = UiApplication.getUiApplication();
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < bitmaps.length; i++) {
final SliderScreen slideScreen =
new SliderScreen(bitmaps[i]);
app.invokeAndWait(new Runnable() {
public void run() {
app.pushScreen(slideScreen);
}
});
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
app.invokeAndWait(new Runnable() {
public void run() {
app.popScreen(slideScreen);
}
});
}
}
}).start();
}
}
Your code did not work because the UI thread was sleeping between push and pop, so it has no time/chance to start drawing the screen. Note I moved the entire action into a separate thread. So now the main UI thread has free time to actually make drawing.