我的UI表现得很有趣,经过大量研究,我仍然不知道为什么。
我从Internet检索了一些数据并将其呈现给用户。问题是,在第一次加载时,一切正常(检索到的数据并正确显示)。之后,当onClickListeners执行时,UI将不会更新(检索数据并将其应用于View,但是View不会更新)。但是,如果我更改了片段(过渡),然后又回到了片段,则一切正常(执行onClickListener动作时,视图将更新)。
使用RetroFit库检索数据。
我已经尝试过的方法:更新其他通用视图(例如TextView),以丢弃问题是MyView(MyProgressBar)类,在代码中的其他位置(在RetroFit方法之外,在onResponse的最后)更新UI在RetroFit等内部),使用AsyncTask并将RetroFit内容放入其中,调用invalidate和postInvalidate。无回应:我总是得到与上述相同的结果。 我已经调试了代码:一切都按预期执行,包括更新UI的行。响应来自服务器,结果全部正确,并已应用于视图,但不会更新。
请帮助!
PS:该应用程序还有其他与此非常相似的片段。它们都可以正常工作,但这是“家”,因此在此之后的另一个负荷。看起来一个片段的onDestroy调用是使其他片段起作用的原因,这没有任何意义,但也许可以提供一个线索。
这是我的课程(简体):
public class HomeFragment extends Fragment {
Activitys dayActivity; // An object to retreive from Internet API
private MyProgressBar stepProgress, walkingProgress, cyclingProgress, exerciseProgress, otherProgress,
standingProgress, restingProgress; // Custom made Views
private TextView dateTextView,lastSyncTextView;
private View v; // The view where the Fragment is hosted
private Calendar calendar; // Store the date I am working on
public HomeFragment() {
this.calendar = Calendar.getInstance();
}
public static HomeFragment getInstance(Date date) {
HomeFragment r = new HomeFragment();
r.calendar = Calendar.getInstance();
r.calendar.setTime(date);
return r;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.daily_progress_activity, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Set Date to today if needed
if (this.calendar == null)
calendar = Calendar.getInstance();
android.text.format.DateFormat dateFormat = new android.text.format.DateFormat();
shownDate = dateFormat.format(DATE_FORMAT, calendar).toString();
setupUi();
//Get Retrofit Instance(API)
Retrofit retrofit = ApiHelper.getClient();
userClient = retrofit.create(UserClient.class);
//API Request and set Progressbars
getActivityData();
}
/**
* connect UI with controller
*/
private void setupUi() {
v = getView();
stepProgress = (MyProgressBar) v.findViewById(R.id.dai_pb_pbSteps);
walkingProgress = (MyProgressBar) v.findViewById(R.id.dai_pb_pbWalking);
cyclingProgress = (MyProgressBar) v.findViewById(R.id.dai_pb_pbCycling);
exerciseProgress = (MyProgressBar) v.findViewById(R.id.dai_pb_pbExercise);
otherProgress = (MyProgressBar) v.findViewById(R.id.dai_pb_pbOthers);
standingProgress = (MyProgressBar) v.findViewById(R.id.dai_pb_pbStanding);
restingProgress = (MyProgressBar) v.findViewById(R.id.dai_pb_pbResting);
//SyncTime
lastSyncTextView = (TextView)v.findViewById(R.id.dai_pb_tvLastSync);
//Date
dateTextView = (TextView) v.findViewById(R.id.dailyTextViewDate);
writeDateOverCircle();
checkRightAngleVisibility();
// With the left angle we go to the previous date
// TODO: Start reseting progressBars, so if there is no data loaded, it will show all gray
ImageView letfAngle = v.findViewById(R.id.dailyAngleLeft);
letfAngle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG,"Push left");
// Calculate previous day
HomeFragment.this.calendar.add(Calendar.DATE, -1);
// Store it in showDate
android.text.format.DateFormat dateFormat = new android.text.format.DateFormat();
shownDate = dateFormat.format(DATE_FORMAT, calendar).toString();
writeDateOverCircle();
checkRightAngleVisibility();
// Call getActivityData
getActivityData();
}
});
// With the right angle we go to the next date (if possible)
// TODO: Start reseting progressBars, so if there is no data loaded, it will show all gray
ImageView rightAngle = v.findViewById(R.id.dailyAngleRight);
rightAngle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Calendar calendar = HomeFragment.this.calendar; // Make the calendar easy to access
calendar.add(Calendar.DATE, 1); // Go to next date
// Store it in showDate
android.text.format.DateFormat dateFormat = new android.text.format.DateFormat();
shownDate = dateFormat.format(DATE_FORMAT, calendar).toString();
writeDateOverCircle();
checkRightAngleVisibility();
// Call getActivityData
getActivityData();
}
});
// Several views will have the same OnClickListener, so we create this and the apply it to
// these views
View.OnClickListener goToWeekView = new View.OnClickListener() {
@Override
public void onClick(View view) {
Fragment frag = HomeFragmentWeekly.getInstance(HomeFragment.this.calendar.getTime());
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.main_home_fragment, frag);
transaction.commit();
}
};
v.findViewById(R.id.dayProgressCircleLeft).setOnClickListener(goToWeekView);
v.findViewById(R.id.dayProgressCircleRight).setOnClickListener(goToWeekView);
v.findViewById(R.id.dai_pb_tvWeekly).setOnClickListener(goToWeekView);
v.findViewById(R.id.textViewDaily).setOnClickListener(goToWeekView);
v.findViewById(R.id.dailyTextViewDate).setOnClickListener(goToWeekView);
// When the user swipes the finger to the left, goes to the daily pie chart view
v.setOnTouchListener(new OnSwipeTouchListener(getContext()) {
public void onSwipeLeft() {
Fragment frag = HomeFragmentPieChart.getInstance(HomeFragment.this.calendar.getTime());
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.main_home_fragment, frag);
transaction.commit();
}
});
}
/**
* Paints the date over the top circle, checking that everything fits
*/
private void writeDateOverCircle() {
// Try with the month's full name and see what happens
String month = calendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
int day = calendar.get(Calendar.DAY_OF_MONTH);
dateTextView.setText(day + " " + month);
// If the dateTextView is too wide, then redo with a shorter month name
// To get the measures with safety, you need to use getMeasuredWidth. For it to work, you have to do a .meassure first
dateTextView.measure(0,0);
int dateWidth = dateTextView.getMeasuredWidth();
View circle = v.findViewById(R.id.dayProgressCircleLeft);
circle.measure(0,0);
int circleWidth = circle.getMeasuredWidth();
if (dateWidth > circleWidth-16) {
month = calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault());
month = month + ".";
}
dateTextView.setText(day + " " + month);
}
/**
* Makes the right angle invisible is we are already in today's date, because we shouldn't be able
* to navigate to the future
*/
private void checkRightAngleVisibility() {
ImageView rightAngle = v.findViewById(R.id.dailyAngleRight);
Calendar today = Calendar.getInstance();
// Reset the time of the day in today
today.set(Calendar.HOUR_OF_DAY, 0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
if (today.after(this.calendar))
rightAngle.setVisibility(View.VISIBLE);
else
rightAngle.setVisibility(View.INVISIBLE);
}
/**
* API request and set the Progressbar and TextView
*/
private void getActivityData() {
Call<ResponseProgress> call = userClient.getProgress(projKey, patKey, shownDate, dayCount);
call.enqueue(new Callback<ResponseProgress>() {
@Override
public void onResponse(Call<ResponseProgress> call, Response<ResponseProgress> response) {
Log.d(TAG,"Get Data");
if (response.isSuccessful()) {
Log.d(TAG, response.body().toString());
//Get Activity Values
dayActivity = response.body().getValue().getData()[0].getValues();
//Steps
HomeFragment.this.dayStepsCount = dayActivity.getActivityStepsCount();
//Walking
HomeFragment.this.dayWalkingTime = dayActivity.getActivityWalkingTime();
//Cycling
HomeFragment.this.dayCyclingTime = dayActivity.getActivityCyclingTime();
//Exercise
HomeFragment.this.dayExerciseTime = dayActivity.getActivityExerciseTime();
//Other
HomeFragment.this.dayOtherTime = dayActivity.getActivityOtherTime();
//Standing
HomeFragment.this.dayStandingTime = dayActivity.getActivityStandingTime();
//Resting
HomeFragment.this.dayRestingTime = dayActivity.getActivityrestingtime();
syncTime(); // I tried commenting this line. Same results.
putDataToUI(); // This is the call that is causing no effect
} else {
ErrorHelper error = new ErrorHelper();
ErrorMessage errorMessage = error.help(response.errorBody());
Toast.makeText(v.getContext(), errorMessage.getStatus_msg(), Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Call<ResponseProgress> call, Throwable t) {
}
});
}
/**
* Get last SyncTime from Sensor. To see the data are up to date or not.
*/
private void syncTime() {
Call<ResponseSensors> call = userClient.getSensors(HelperShared.loadString(getContext(),
Constants.PREF_TOKEN), HelperShared.loadString(getContext(), Constants.PREF_ORGID),
HelperShared.loadString(getContext(), Constants.PREF_PROJ_ID));
call.enqueue(new Callback<ResponseSensors>() {
@Override
public void onResponse(Call<ResponseSensors> call, Response<ResponseSensors> response) {
if (response.isSuccessful()) {
Log.d(TAG, "Sensor: " + response.body().getValue().
getSensorWithShortName(sensorShortName).getLast_synced_timestamp());
String lastSync = response.body().getValue().
getSensorWithShortName(sensorShortName).getLast_synced_timestamp();
lastSyncTextView.setText(lastSync);
} else {
ErrorHelper error = new ErrorHelper();
ErrorMessage errorMessage = error.help(response.errorBody());
Toast.makeText(getContext(), errorMessage.getStatus_msg(), Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Call<ResponseSensors> call, Throwable t) {
Log.d(TAG, "FEhler: " + t.getMessage());
}
});
}
private void putDataToUI() {
Log.d(TAG,"Set Progress");
//Steps
setProgressBar(stepProgress, stepGoal, stepProg, this.dayStepsCount);
//Walking
setProgressBar(walkingProgress, walkingGoal, walkingProg, this.dayWalkingTime);
//Cycling
setProgressBar(cyclingProgress, cyclingGoal, cyclingProg, this.dayCyclingTime);
//Exercise
setProgressBar(exerciseProgress, exerciseGoal, exerciseProg, this.dayExerciseTime);
//Other
setProgressBar(otherProgress, otherGoal, otherProg, this.dayOtherTime);
//Standing
setProgressBar(standingProgress, standingGoal, standingProg, this.dayStandingTime);
//Resting
setProgressBar(restingProgress, restingGoal, restingProg, this.dayRestingTime);
// Here I tried v.invalidate() and v.postInvalidate(). No results.
// Also tried to invalidate and postInvalidate each MyProgressBar. No results.
}
/**
* @param progBar Progressbar to set the values
* @param goal daily goal the user has to reach
* @param activityValue the value form the API for the spacific activity
*/
private void setProgressBar(MyProgressBar progBar, float goal, float progGoal, float activityValue) {
float value = (100 / progGoal) * activityValue;
float dailyGoal = (100 / progGoal) * goal;
progBar.setSecondaryProgress((int) dailyGoal);
if (value >= 100) {
progBar.setProgress(100);
} else {
progBar.setProgress((int) value);
}
if (progBar != stepProgress) {
int houers = (int) activityValue / 60;
int minutes = (int) activityValue % 60;
progBar.setTagText(houers + "h:" + minutes + "min");
} else {
progBar.setTagText((int) activityValue + "");
}
}
}