繁体   English   中英

从Web服务检索数据后,Android数据绑定未更新UI

[英]Android Data Binding not Update UI after retreive data from webservice

我尝试通过Mindorks实现MVVM,以在此处显示我的Activity数据:( https://api.themoviedb.org/3/movie/384018?api_key=67bc513a7a353631119fdffe5f7377a8&language=zh-CN )。 我尝试对更新UI使用数据绑定,但是在更新databinding后,数据databinding不会更新我的textview。 这是我的详细活动类:

   public class DetailActivity extends BaseActivity<ActivityDetailBinding, DetailViewModel> implements DetailNavigator {
@Inject
DetailViewModel detailViewModel;

public static final String INTENT_ID = "id_intent";

public static final String INTENT_FLAG = "id_flag";

private ActivityDetailBinding mActivityDetailBinding;

public static Intent newIntent(Context context) {
    return new Intent(context, DetailActivity.class);
}

@Override
public int getBindingVariable() {
    return BR.viewModel;
}

@Override
public int getLayoutId() {
    return R.layout.activity_detail;
}

@Override
public DetailViewModel getViewModel() {
    return detailViewModel;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail);
    detailViewModel.setNavigator(this);
    mActivityDetailBinding = getViewDataBinding();
    initView();
    initData(savedInstanceState);

}


private void initData(Bundle savedInstanceState) {
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
        int id = extras.getInt(INTENT_ID, 0);
        int flag = extras.getInt(INTENT_FLAG, 0);
        detailViewModel.fetchDetail(id, flag);
    }
}

private void initView() {
    if (getSupportActionBar() != null) {
        getSupportActionBar().hide();
    }
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}


@Override
public void ShowProgressDialog(Boolean loading) {
    if (loading) {
        showLoading();
    } else {
        hideLoading();
    }
}
}

和我的BaseActivity像这样:

   public abstract class BaseActivity<T extends ViewDataBinding, V extends BaseViewModel> extends AppCompatActivity
        implements BaseFragment.Callback {

    // TODO
    // this can probably depend on isLoading variable of BaseViewModel,
    // since its going to be common for all the activities
    private ProgressDialog mProgressDialog;
    private T mViewDataBinding;
    private V mViewModel;

    /**
     * Override for set binding variable
     *
     * @return variable id
     */
    public abstract int getBindingVariable();

    /**
     * @return layout resource id
     */
    public abstract
    @LayoutRes
    int getLayoutId();

    /**
     * Override for set view model
     *
     * @return view model instance
     */
    public abstract V getViewModel();

    @Override
    public void onFragmentAttached() {

    }

    @Override
    public void onFragmentDetached(String tag) {

    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        performDependencyInjection();
        super.onCreate(savedInstanceState);
        performDataBinding();
    }

    public T getViewDataBinding() {
        return mViewDataBinding;
    }

    @TargetApi(Build.VERSION_CODES.M)
    public boolean hasPermission(String permission) {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
                checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
    }

    public void hideKeyboard() {
        View view = this.getCurrentFocus();
        if (view != null) {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            if (imm != null) {
                imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
            }
        }
    }

    public void hideLoading() {
        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.cancel();
        }
    }

    public void showLoading() {
        hideLoading();
        mProgressDialog = CommonUtils.showLoadingDialog(this);
    }

    public boolean isNetworkConnected() {
        return NetworkUtils.isNetworkConnected(getApplicationContext());
    }

    public void performDependencyInjection() {
        AndroidInjection.inject(this);
    }

    @TargetApi(Build.VERSION_CODES.M)
    public void requestPermissionsSafely(String[] permissions, int requestCode) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(permissions, requestCode);
        }
    }

//    public void showLoading() {
//        hideLoading();
//        mProgressDialog = CommonUtils.showLoadingDialog(this);
//    }

    private void performDataBinding() {
        mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId());
        this.mViewModel = mViewModel == null ? getViewModel() : mViewModel;
        mViewDataBinding.setVariable(getBindingVariable(), mViewModel);
        mViewDataBinding.setLifecycleOwner(this);
        mViewDataBinding.executePendingBindings();
    }
    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

这是我的ViewModel类:

public class DetailViewModel extends BaseViewModel<DetailNavigator> {

private final ObservableField<String> originalName = new ObservableField<>();
private final ObservableField<String> releaseDate = new ObservableField<>();
private final ObservableField<String> overview = new ObservableField<>();
private final ObservableField<String> genreMovie = new ObservableField<>();
private final ObservableField<String> posterPath = new ObservableField<>();
private final ObservableField<String> voteAverage = new ObservableField<>();

public DetailViewModel(DataManager dataManager, SchedulerProvider schedulerProvider) {
    super(dataManager, schedulerProvider);
}

public void fetchDetail(int id, int flag) {
    if (flag == 1) {
        getNavigator().ShowProgressDialog(true);
        getCompositeDisposable().add(getDataManager()
                .getApiHelper().doDetailMovie(id, URLConfig.API_KEY, getDataManager().getLanguage())
                .subscribeOn(getSchedulerProvider().io())
                .observeOn(getSchedulerProvider().ui())
                .subscribe(detailResponse -> {
                    setUpData(detailResponse);
                    getNavigator().ShowProgressDialog(false);
                }, throwable -> {
                    getNavigator().ShowProgressDialog(false);
                }));
    } else if (flag == 2) {
        getNavigator().ShowProgressDialog(true);
        getCompositeDisposable().add(getDataManager()
                .getApiHelper().doDetailTV(id, URLConfig.API_KEY, getDataManager().getLanguage())
                .subscribeOn(getSchedulerProvider().io())
                .observeOn(getSchedulerProvider().ui())
                .subscribe(detailResponse -> {
                    setUpData(detailResponse);
                    getNavigator().ShowProgressDialog(false);
                }, throwable -> {
                    getNavigator().ShowProgressDialog(false);
                }));
    }
}

private void setUpData(DetailResponse detailResponse) {
    if (detailResponse.getOriginal_name() != null) {
        originalName.set(detailResponse.getOriginal_name());
    } else {
        originalName.set(detailResponse.getOriginal_title());
    }
 originalName.notifyChange();
    if (detailResponse.getFirst_air_date() != null) {
        releaseDate.set(detailResponse.getFirst_air_date());
    } else {
        releaseDate.set(detailResponse.getRelease_date());
    }
    overview.set(String.valueOf(detailResponse.getOverview()));

    posterPath.set(String.valueOf(detailResponse.getPoster_path()));

    voteAverage.set(String.valueOf(detailResponse.getVote_average()));

    String genres = "";

    for (int i = 0;i<detailResponse.getGenreList().size();i++){
        genres = genres+detailResponse.getGenreList().get(i);
    }

    genreMovie.set(genres);

}

public ObservableField<String> getOriginalName() {
    return originalName;
}

public ObservableField<String> getReleaseDate() {
    return releaseDate;
}

public ObservableField<String> getOverview() {
    return overview;
}

public ObservableField<String> getGenreMovie() {
    return genreMovie;
}

public ObservableField<String> getPosterPath() {
    return posterPath;
}

public ObservableField<String> getVoteAverage() {
    return voteAverage;
}
}

这是我的DetailResponse类:

public class DetailResponse {
    @SerializedName("original_name")
    private String original_name ;
    @SerializedName("original_title")
    private String original_title ;
    @SerializedName("release_date")
    private String release_date ;
    @SerializedName("first_air_date")
    private String first_air_date ;
    @SerializedName("vote_average")
    private Double vote_average ;
    @SerializedName("overview")
    private String overview ;
    @SerializedName("poster_path")
    private String poster_path;
    @SerializedName("genres")
    private List<Genre> genreList;

    public String getOriginal_name() {
        return original_name;
    }

    public String getOriginal_title() {
        return original_title;
    }

    public String getRelease_date() {
        return release_date;
    }

    public String getFirst_air_date() {
        return first_air_date;
    }

    public Double getVote_average() {
        return vote_average;
    }

    public String getOverview() {
        return overview;
    }

    public String getPoster_path() {
        return poster_path;
    }

    public List<Genre> getGenreList() {
        return genreList;
    }

    public static class Genre{
        @SerializedName("name")
        private String name ;

        public String getName() {
            return name;
        }
    }
}

最后一个,这里是我如何尝试使用数据绑定在UI中获取数据,这是我的布局:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".ui.detail.DetailActivity">

    <data>

        <variable
            name="viewModel"
            type="test.ui.detail.DetailViewModel" />
    </data>
<androidx.core.widget.NestedScrollView
    android:id="@+id/nestedScrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">


    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:animateLayoutChanges="true">

        <com.github.florent37.shapeofview.shapes.ArcView
            android:id="@+id/shape_header"
            android:layout_width="match_parent"
            android:layout_height="@dimen/size300dp"
            android:alpha="0.7"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:shape_arc_cropDirection="outside"
            app:shape_arc_height="@dimen/size30dp"
            app:shape_arc_position="bottom">

            <com.flaviofaria.kenburnsview.KenBurnsView
                android:id="@+id/image_header"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/poster_avengerinfinity"
                android:tint="#6F000000" />

        </com.github.florent37.shapeofview.shapes.ArcView>

        <com.github.florent37.shapeofview.shapes.RoundRectView
            android:id="@+id/shape_poster"
            android:layout_width="@dimen/size150dp"
            android:layout_height="@dimen/size200dp"
            android:layout_marginTop="@dimen/margin250dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/shape_header"
            app:shape_roundRect_bottomLeftRadius="@dimen/corner10dp"
            app:shape_roundRect_bottomRightRadius="@dimen/corner10dp"
            app:shape_roundRect_topLeftRadius="@dimen/corner10dp"
            app:shape_roundRect_topRightRadius="@dimen/corner10dp">

            <ImageView
                android:id="@+id/image_poster"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:contentDescription="@string/hint_poster"
                android:scaleType="fitXY"
                app:imageDetailUrl="@{viewModel.posterPath}"
                android:src="@drawable/poster_avengerinfinity" />

        </com.github.florent37.shapeofview.shapes.RoundRectView>

        <TextView
            android:id="@+id/text_title"
            style="@style/FontText.Title.Detail"
            android:layout_marginTop="@dimen/margin15dp"
            android:textSize="@dimen/font_large_size"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/shape_poster"
            android:text="@{viewModel.originalName}"
            tools:text="@string/hint_title" />

        <TextView
            android:id="@+id/text_title_release"
            style="@style/FontText"
            android:layout_marginTop="@dimen/margin10dp"
            android:text="@string/text_release"
            app:layout_constraintEnd_toStartOf="@+id/guideline"
            app:layout_constraintTop_toBottomOf="@+id/text_title" />

        <TextView
            android:id="@+id/text_release"
            style="@style/FontText"
            android:layout_marginStart="@dimen/margin2dp"
            android:layout_marginTop="@dimen/margin10dp"
            app:layout_constraintStart_toEndOf="@+id/text_title_release"
            app:layout_constraintTop_toBottomOf="@+id/text_title"
            tools:text="@string/hint_release" />

        <TextView
            android:id="@+id/text_genres"
            style="@style/FontText.Normal"
            android:layout_marginStart="@dimen/margin15dp"
            android:layout_marginTop="@dimen/margin10dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/text_release"
            tools:text="@string/hint_genres" />

        <TextView
            android:id="@+id/text_duration"
            style="@style/FontText.Normal.White"
            android:layout_marginTop="@dimen/margin10dp"
            android:layout_marginEnd="@dimen/margin15dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/text_release"
            tools:text="@string/hint_duration" />

        <RatingBar
            android:id="@+id/rating_bar"
            android:layout_width="wrap_content"
            android:layout_height="45dp"
            android:layout_marginStart="@dimen/margin15dp"
            android:layout_marginTop="@dimen/margin5dp"
            android:isIndicator="true"
            android:numStars="5"
            android:rating="3.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/text_duration" />

        <TextView
            android:id="@+id/text_rating"
            style="@style/FontText.Rating.Orange"
            android:layout_marginStart="@dimen/margin5dp"
            app:layout_constraintRight_toLeftOf="parent"
            app:layout_constraintStart_toEndOf="@+id/rating_bar"
            app:layout_constraintTop_toBottomOf="@+id/text_duration"
            tools:text="@string/hit_rating" />

        <TextView
            android:id="@+id/text_default_rating"
            style="@style/FontText.Rating"
            android:textStyle="normal"
            app:layout_constraintRight_toLeftOf="parent"
            app:layout_constraintStart_toEndOf="@+id/text_rating"
            app:layout_constraintTop_toBottomOf="@+id/text_duration"
            tools:text="@string/hint_default_rating" />

        <TextView
            android:id="@+id/text_desc"
            style="@style/FontText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/margin15dp"
            android:layout_marginTop="@dimen/margin25dp"
            android:layout_marginEnd="@dimen/margin15dp"
            android:paddingBottom="@dimen/padding100dp"
            app:layout_constraintTop_toBottomOf="@+id/rating_bar"
            tools:text="@string/hint_desc" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.5" />

    </androidx.constraintlayout.widget.ConstraintLayout>


</androidx.core.widget.NestedScrollView>
</layout>

我尝试先显示一个数据,即text_title OriginalNametext_titledebug我的应用程序

public ObservableField<String> getOriginalName() {
    return originalName;
}

ViewModel类中的getOriginalName ,在检索响应之前被调用,但是在设置OriginalName之后,UI不更新, getOriginalName也不再调用getOriginalName已经添加了originalName.notifyChange(); getOriginalName 设置数据后,但似乎没有任何改变。

我已经很沮丧了..所以请...我希望任何人都可以帮助我向我展示如何做。 非常感谢你。

从明细活动中删除此行

setContentView(R.layout.activity_detail);

在基本活动中,您具有performDataBinding方法,该方法使用DataBindingUtil类设置布局ID。

    mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId());
    this.mViewModel = mViewModel == null ? getViewModel() : mViewModel;
    mViewDataBinding.setVariable(getBindingVariable(), mViewModel);
    mViewDataBinding.setLifecycleOwner(this);
    mViewDataBinding.executePendingBindings();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM