I am trying to make a wizard using Roman Nurik's library (https://plus.google.com/113735310430199015092/posts/6cVymZvn3f4).
I am having trouble accessing the collected data from the Review Fragment.
I made mCurrentReviewItems public in ReviewFragment and then I tried it like this
mNextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mPager.getCurrentItem() == mCurrentPageSequence.size()) {
ReviewFragment reviewFragment = (ReviewFragment) mPagerAdapter.getItem(mPager.getCurrentItem());
for (ReviewItem item : reviewFragment.mCurrentReviewItems)
Log.d(MainActivity.TAG, "Item: " + item.getDisplayValue());
}
} else {
if (mEditingAfterReview) {
mPager.setCurrentItem(mPagerAdapter.getCount() - 1);
} else {
mPager.setCurrentItem(mPager.getCurrentItem() + 1);
}
}
}
});
However its always null.
Inside if (mPager.getCurrentItem() == mCurrentPageSequence.size()) { }
For single page variable:
String data = mWizardModel.findByKey("Sandwich:Bread").getData().getString(Page.SIMPLE_DATA_KEY);
For customized page:
String data =
mWizardModel.findByKey(THE_KEY).getData().getString(CustomerInfoPage.YOUR_DATA_KEY);
If you want to assign the data back to the wizard, put this at the end of onCreate in FragmentActivity:
Bundle data = new Bundle();
if (!TextUtils.isEmpty(DATA_STRING)) {
data.putString(Page.SIMPLE_DATA_KEY, DATA_STRING);
mWizardModel.findByKey("Sandwich:Bread"").resetData(data);
}
The key "Sandwich:Bread" is from the example, change whatever suit you. Never try the multi one, I think it is more or less the same.
Sorry for big delay, but I think that someone will found this info useful. I found a way to get all ReviewItems since you can have a lot of branches and you won't be able to use the first answer.
I'm pretty sure, that your mPagerAdapter::getItem code looked like in example (so it just returned new fragment, instead of returning current pager fragment). You have to use instantiateItem to get reference on your ReviewFragment.
Object o = mPager.getAdapter().instantiateItem(mPager, mPager.getCurrentItem());
if(o instanceof ReviewFragment) {
List<ReviewItem> items = ((ReviewFragment) o).getCurrentReviewItems();
if(items != null) {
Log.v(TAG, "Items are: " + items.toString());
}
}
This is my code #Anton_Shkurenko
mNextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mPager.getCurrentItem() == mCurrentPageSequence.size()) {
Object o = mPager.getAdapter().instantiateItem(mPager, mPager.getCurrentItem());
if(o instanceof ReviewFragment) {
List<ReviewItem> items = ((ReviewFragment) o).getCurrentReviewItems();
if(items != null) {
Log.v(TAG, "Items are: " + items.toString());
}
}
}
}
});
The best solution is to include this library in your project as module, and implement your own method for getting review items in ReviewFragment.
public List<ReviewItem> getReviewItems() {
return mCurrentReviewItems;
}
I am not sure why developer did not add that. It's the most important thing in project. Choose items and DO something with them.
Anyone still looking for a solution for this issue you can use following code
ArrayList<ReviewItem> reviewItems = new ArrayList<ReviewItem>();
for (Page page : mWizardModel.getCurrentPageSequence()) {
page.getReviewItems(reviewItems);
}
Related
I have a project that use Android to display Unity Player. So I export Untiy project as Android module which implemented by Android Application.
I create buttons in Android Activity which contains UnityPlayer, And when I click button, it send a message to Unity Player to invoke C# function, just like this:
findViewById(R.id.btnChange).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mUnityPlayer.UnitySendMessage("ScriptHolder", "ChangeSkin", "");
}
});
And the function named "ChangeSkin" is just to change some GameObjects' active. Just like this:
void ChangeSkin()
{
int prefab;
if (_currentPrefab == PREFAB_DEFAULT)
{
prefab = PREFAB_PRINCESS;
}
else
{
prefab = PREFAB_DEFAULT;
}
ShowSkin(prefab);
}
private void ShowSkin(int prefab)
{
_currentPrefab = prefab;
foreach (var item in _defaultDressList)
{
item.SetActive(prefab == PREFAB_DEFAULT);
}
foreach (var item in _princessDressList)
{
item.SetActive(prefab == PREFAB_PRINCESS);
}
}
And something weird happening: when I click button to change the person's cloth in Unity, the GameObjects which called SetActive(true) show at the position above the right position for a frame and become normal, it looks like they flash. Here is the gif of the project demo:
It looks like the position offset is equal to the height of status bar. If I create a button on Unity Scene and call "ChangeSkin" function, everything will be OK.
I tried all I can to fix this but not succeed. So I hope you will help me, thx.
You should check your Unity layout. If you have a layout group that has content size fitter component, and the child objects also have it (content size fitter), this could cause these glitches.
I fixed this problem by using a flag (or trigger). Just like this:
// set value true to trigger ChangeSkin() in Update(),
// instead of invoke ChangeSkin() directly
private bool _changingSkinTrigger = false;
void ChangeSkin()
{
if (_currentPrefab == PREFAB_DEFAULT)
{
_currentPrefab = PREFAB_PRINCESS;
}
else
{
_currentPrefab = PREFAB_DEFAULT;
}
_changingSkinTrigger = true;
}
void Update()
{
if (_changingSkinTrigger)
{
_changingSkinTrigger = false;
ShowSkin();
}
}
private void ShowSkin()
{
foreach (var item in _defaultDressList)
{
item.SetActive(_currentPrefab == PREFAB_DEFAULT);
}
foreach (var item in _princessDressList)
{
item.SetActive(_currentPrefab == PREFAB_PRINCESS);
}
}
Thank #AndriyMarshalek for enlightening me.
I know it sounds strange/ridiculous, but I am having this issue
Update#2
I am sharing the code that is indicated by #EpicPandaForce.
SyncService.onNetworkSuccess
public void onNetworkCallSuccess(Response response) {
List<TransactionHistory> historyList = (List<TransactionHistory>) response.body();
if(historyList != null && historyList.size() > 0) {
TransactionHistory max = Collections.max(historyList, new Comparator<TransactionHistory>() {
#Override
public int compare(TransactionHistory o1, TransactionHistory o2) {
return o1.getUpdatedAt().compareTo(o2.getUpdatedAt());
}
});
if(max != null) {
session.putStringForKey(Session.timeStamp, String.valueOf(max.getUpdatedAt()));
}
for(TransactionHistory history : historyList) {
String id;
if(history.getTo().equals(history.getFrom()) ||
history.getFrom().equals(session.getStringForKey(Session.fpIdKey)))
id = history.getTo();
else id = history.getFrom();
LatestTransactionResponse latestTransactionResponse = new LatestTransactionResponse();
DateTransactionResponse dateTransactionResponse = new DateTransactionResponse(DateUtility.getDateFromEpoch(history.getEpoch()));
dateTransactionResponse.addTransaction(history);
latestTransactionResponse.setArchived(history.isArchived());
latestTransactionResponse.addTransaction(history);
latestTransactionResponse.setId(id);
dateTransactionResponse.setId(id);
LatestTransactionRepository.getInstance().addLatestTransaction(realm,
latestTransactionResponse);
ContactTransactionRepository.getInstance().addNewTransaction(realm, dateTransactionResponse, id);
}
try {
Activity temp = MyFirebaseMessagingService.getRunningActivity();
if(temp != null) {
if(temp instanceof MainActivity) {
((MainActivity) temp).refreshLatestTransactions();
} else if(temp instanceof TransactionDetailActivity) {
((TransactionDetailActivity) temp).refreshOnMainThread();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
addNewTransaction
public void addNewTransaction(Realm realm, final DateTransactionResponse response, final String id) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
List<TransactionHistory> tempHistoryList;
DateTransactionResponse temp = realm
.where(DateTransactionResponse.class)
.equalTo("id", id)
.equalTo("date", response.getDate())
.findFirst();
if(temp == null)
realm.insertOrUpdate(response);
else {
tempHistoryList = temp.getTransactions();
for(TransactionHistory history : response.getTransactions()) {
boolean found = false;
for(int i=0; i < tempHistoryList.size(); i++) {
if (history.getId().equals(tempHistoryList.get(i).getId())) {
if(history.getStatus().equals(tempHistoryList.get(i).getStatus())) {
found = true;
break;
} else {
tempHistoryList.get(i).setStatus(history.getStatus());
}
}
}
if(!found)
tempHistoryList.add(history);
}
//realm.insertOrUpdate(temp);
realm.copyToRealm(temp);
//DateTransactionResponse transactionResponse = temp;
//temp.deleteFromRealm();
//realm.insertOrUpdate(temp);
}
}
});
//removeDuplicateTransactions(realm);
}
removeDuplicateTransaction
private void removeDuplicateTransactions(Realm realm) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
RealmQuery<DateTransactionResponse> query = realm.where(DateTransactionResponse.class);
RealmResults<DateTransactionResponse> results = query.findAll();
List<DateTransactionResponse> transactions = new ArrayList<>(results);
for(DateTransactionResponse response : transactions) {
List<TransactionHistory> historyList = response.getTransactions();
Set<TransactionHistory> historySet = new LinkedHashSet<>(historyList);
RealmList<TransactionHistory> histories = new RealmList<>();
histories.addAll(new ArrayList<>(historySet));
response.setTransactions(histories);
realm.copyToRealm(response);
}
}
});
}
Update#1
There are 3 tabs with RecyclerViews on my main screen. Below are the implementation of Adapter for all three.
I have been developing an App for quite a time. It has been working just fine and I occasionally work to improve its performance. It is still under development. Some days ago, I cut-out the branch and done nothing notable (just one or two bug fixes) and started testing it and OOPS it started giving ANR's. I revert back to previous branch and very strangely it started giving me the same result. I have removed all changes and tried, still the same result. I am not sure what's happening. I tried to study traces.txt, but couldn't find waiting to lock as suggested in this SO answer.
I have also difficulty reading traces, couldn't find the culprit. Here is the traces.txt file.
I am using Realm as Database in my application and couldn't find a way to perform operations on Realm on other thread. I tried to find any other culprit in code, but all is till the same as before which was working perfectly fine.
Hierarchy
Here is the App Hierarchy.
Login screen is shown and user enters PIN. Then comes the main screen. Main screen contains 4 tabs, just like WhatsApp i.e first tab is camera and rest contains RecyclerViews in which data is being populated from Realm. ANR is only happening here. Keeping in mind that it was literally perfect some days ago until I took branch out and fixed some bugs, which were not even related to the main screen.
Any help or direction is highly appreciated.
I have a memory leak because of AppCompatTextView
It has no click listeners it's just a plain TexView with some text in it.
Is there anything I can do about that? Is that a bug or am I doing something wrong?
I've tried solution suggested here but that didn't helped.
It's an android framework bug. https://code.google.com/p/android/issues/detail?id=34731
It hasn't been fixed yet, even in support library.
Here is the fix:
public static void fixInputMethodManagerLeak(Context destContext) {
if (destContext == null) {
return;
}
InputMethodManager imm = (InputMethodManager) destContext.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) {
return;
}
String[] arr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};
Field f = null;
Object obj_get = null;
for (int i = 0; i < arr.length; i++) {
String param = arr[i];
try {
f = imm.getClass().getDeclaredField(param);
if (!f.isAccessible()) {
f.setAccessible(true);
}
obj_get = f.get(imm);
if (obj_get != null && obj_get instanceof View) {
View v_get = (View) obj_get;
if (v_get.getContext() == destContext) { // referenced context is held InputMethodManager want to destroy targets
f.set(imm, null); // set empty, destroyed node path to gc
} else {
// Not want to destroy the target, that is, again into another interface, do not deal with, to avoid affecting the original logic, there is nothing further for the cycle
Log.e(TAG, "fixInputMethodManagerLeak break, context is not suitable, get_context=" + v_get.getContext() + " dest_context=" + destContext);
break;
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Call it like this:
#Override
protected void onDestroy() {
super.onDestroy();
//if you get memory leak on configuration change too, remove the if clause.
if (isFinishing()) {
fixInputMethodManagerLeak(this);
}
}
Take a look at this question too.
According to this link:
https://code.google.com/p/android/issues/detail?id=179272
It seems that the leak is caused by:
It happens with anything which uses TextLine (TextView, descendants, Layout) with Spanned text. As SearchView uses a SpannableStringBuilder internally, it gets leaked.
I hope it will help you :)
I have a array of jokes
String jokes[]={"x","y","z","j"};
i am using two methods next and previous to go front and back.
public void nextJoke(View view) {
if (jokeNumber < jokes.length - 1) {
jokeNumber++;
tv1.setText(jokes[jokeNumber]);
}
}
public void prevJoke(View view) {
if (jokeNumber > 0) {
jokeNumber--;
tv1.setText(jokes[jokeNumber]);
}
I want to give this list a endless scroll functionality .
That means if the user next or previous - and list reaches the last three elements , it should again start from first element.
How can i achieve this functionality .
This is more of a programming question .
Any Help will be highly appreciated.
Using the remainder operator, you'll get the required behavior.
Replace:
jokeNumber++;
with:
jokeNumber = ++jokeNumber % jokes.length;
and do the same for jokeNumber--;
On next:
next(){
jokeNumber++;
if(jokeNumber>=jokes.length) { jokeNumber =0;}
}
on previous:
previous(){
jokeNumber--;
if(jokeNumber<=0) { jokeNumber =jokes.length;}
}
public void nextJoke(View view) {
if (jokeNumber < jokes.length ) {
jokeNumber = ++jokeNumber % jokes.length;
tv1.setText(jokes[jokeNumber]); } }
public void prevJoke(View view) {
if (jokeNumber > 0) {
jokeNumber = --jokeNumber % jokes.length;
tv1.setText(jokes[jokeNumber]);
}
At the beginning of the chat app user see a list off groups (listview group) available and the user have the possibility to create a new group or click on some off the available groups and then start to write messages (listview messages). The functions CreateNewMessage and CreateNewGroup pushes information to firebase correctly
Above scenarios works finne problems arise when user navigates backwards (popBackStack()) from listview with messages to GroupFragment, here should user be presented a list off available groups but the listview is empty. The ReadGroupData() function is not reading the already created groups from firebase and inserts them in the group listview. How to make this happen?
GroupFragment:
public void ReadGroupData() {
Firebase firebaserootRef = new Firebase("https://000.firebaseio.com");
firebaserootRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot snapshot, String s) {
if (snapshot.getValue() != null) {
Group newGroup = new Group((String)snapshot.child("name").getValue(),
(String) snapshot.child("id").getValue());
if(!groupKeyValues.contains(newGroup.GetId())) {
groupKeyValues.add(newGroup.GetId());
AddToLstViewGroup(newGroup);
System.out.println("Read group data from firebase and
inserted in listView");
}
}
}
});
}
public void AddToLstViewGroup(Group newGroup) {
groupNameList.add(newGroup);
if(groupAdapter == null) {
groupAdapter = new GroupAdapter(getActivity(), groupNameList);
}
if (lstViewGroup == null) {
lstViewGroup = (ListView) getView().
findViewById(R.id.listView_group);
}
lstViewGroup.setOnItemClickListener(onItemClickListener);
lstViewGroup.setOnItemLongClickListener(onItemLongClickListener);
groupAdapter.notifyDataSetChanged();
lstViewGroup.setAdapter(groupAdapter);
}
ChatFragment:
public void ReadChatMessages(Firebase firebaseRootRef) {
firebaseRootRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot snapshot, String s) {
if (snapshot.child(GetGroupId()).child("messages").
getChildren() != null) {
for (DataSnapshot c :
snapshot.child(GetGroupId()).child("messages").getChildren()) {
String key = c.getKey();
Message newMessage = new Message();
newMessage.SetFrom((String) c.child("from").getValue());
newMessage.SetMsg((String)
c.child("message").getValue());
newMessage.SetTime((String) c.child("time").getValue());
newMessage.SetId((String) c.child("id").getValue());
if ((!msgKeyValues.contains(key)) ||
newMessage.GetFrom() != "") {
msgKeyValues.add(key);
AddToLstViewChat(newMessage);
//Automatic scrolls to last line in listView.
lstViewChat.setSelection(chatAdapter.getCount() -1);
}
}
}
}
public void AddToLstViewChat(Message newMessage) {
chatMsgList.add(newMessage);
if (chatAdapter == null) {
chatAdapter = new ChatAdapter(getActivity(), chatMsgList);
}
if(IsMsgFromMe(newMessage)) {
lstViewChat = (ListView)
getView().findViewById(R.id.listView_chat_message_me);
} else {
lstViewChat =
(ListView)getView().findViewById(R.id.listView_chat_message_others);
}
chatAdapter.notifyDataSetChanged();
lstViewChat.setAdapter(chatAdapter);
}
ChatActivity:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
finish();
}
}
For all the code click on the link: "http://pastebin.com/97nR68Rm"
SOLUTION!
Kato thank you for you patience and help. I have now found a solution for the problem. I'm calling ReadGroupData() and ReadChatMessages() at the end (before return) in my onCreateView methods. As Kato pointed out onCreate() is not getting called on popBackStack()
In my AddToLStViewGroup the if statement for lstViewGroup is deleted so now it always sets the listView otherwise it will throw an exception for not finding the correct view, To clarifying:
Deleted this line:
if (lstViewGroup == null) {
lstViewGroup = (ListView)getView().findViewById(R.id.listView_group);
}
And replaced with:
ListView lstViewGroup=(ListView)getView().findViewById(R.id.listView_group);
Kato thank you for you patience and help. I have now found a solution for the problem. I'm calling ReadGroupData() and ReadChatMessages() at the end (before return) in my onCreateView methods. As Kato pointed out onCreate() is not getting called on popBackStack()
In my AddToLStViewGroup the if statement for listViewGroup is deleted so now it always sets the listView otherwise it will throw an exception for not finding the correct view.
To clarify:
I deleted this line:
if (lstViewGroup == null) {
lstViewGroup = (ListView)getView().findViewById(R.id.listView_group);
}
And replaced it with:
ListView lstViewGroup =(ListView)getView().findViewById(R.id.listView_group);
(The original asker posted the answer as part of the question. I'm copying it here as a matter of housekeeping.)