Android MVVM框架搭建腾讯X5WebView + DrawerLayout + NavigationView

Posted 初学者-Study

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MVVM框架搭建腾讯X5WebView + DrawerLayout + NavigationView相关的知识,希望对你有一定的参考价值。

前言

  在上一篇文章中在HomeActivity中通过装载不同的Fragment显示不同的数据,目前有新闻数据和视频数据,不过光是显示数据,看不到详细内容也不行。其次在这样的页面中要想显示个人信息的话,可以增加一个Fragment或者通过侧滑抽屉来显示,同时既然有个人信息页面,自然就要有登录和注册的关系,之前的登录是个假的,这次我就做的真一点,用一下本地数据库。

效果图

正文

  首先我们先显示新闻详情信息。这里会用到WebView,Android原生的WebView好不好用,用过的就不会再用,因此我们用更加好用的WebView,就是腾讯的X5 WebView,你可以看到微信里面也是这个WebView。要使用这个WebView需要添加依赖。

一、添加依赖

在app的build.gradle中的dependencies闭包中添加如下代码:

	// 腾讯X5内核WebView
    implementation 'com.tencent.tbs:tbssdk:44085'

添加后,点击Sync Now,进行项目同步。然后需要在AndroidManifest.xml中进行网络权限配置

	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

二、使用WebView

下面在Activity中新建一个WebActivity,布局是activity_web.xml,这个类用于装载WebView显示,首先改一下布局activity_web.xml,代码如下:

<?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">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context=".ui.activity.WebActivity">

        <com.tencent.smtt.sdk.WebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

然后在WebActivity中增加如下代码,用于配置WebView。

	private final WebViewClient client = new WebViewClient() 
        /**
         * 防止加载网页时调起系统浏览器
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) 
            view.loadUrl(url);
            return true;
        

        @Override
        public void onReceivedHttpAuthRequest(WebView webview,
                                              com.tencent.smtt.export.external.interfaces.HttpAuthHandler httpAuthHandlerhost, String host,
                                              String realm) 
            boolean flag = httpAuthHandlerhost.useHttpAuthUsernamePassword();
        

        @Override
        public void onPageFinished(WebView webView, String s) 
            super.onPageFinished(webView, s);
        

        @Override
        public void onReceivedError(WebView webView, int i, String s, String s1) 
            System.out.println("***********onReceivedError ************");
            super.onReceivedError(webView, i, s, s1);
        

        @Override
        public void onReceivedHttpError(WebView webView, WebResourceRequest webResourceRequest, WebResourceResponse webResourceResponse) 
            System.out.println("***********onReceivedHttpError ************");
            super.onReceivedHttpError(webView, webResourceRequest, webResourceResponse);
        
    ;

  当前的页面是需要网络请求的,因此就会有相应的ViewModel和Repository,因为聚合给的新闻数据里面有一个uniquekey,用于查询新闻的详情信息,然后再去返回的详情信息里面找到url通过WebView去加载。当然并不是每一条新闻都能够去显示的,有一些新闻是没有详情信息的,这在我们点击新闻的时候就要做处理。

  这是我们下面要做的事情,现在对于X5WebView还需要进行一个初始化,这样做是方便使用的。在BaseApplication中增加如下代码:

	private void initX5WebView() 
        HashMap map = new HashMap(2);
        map.put(TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER, true);
        map.put(TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE, true);
        QbSdk.initTbsSettings(map);
        //搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
        QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() 
            @Override
            public void onViewInitFinished(boolean arg0) 
                //x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
                Log.d("app", " onViewInitFinished is " + arg0);
            

            @Override
            public void onCoreInitFinished() 
            
        ;
        //x5内核初始化接口
        QbSdk.initX5Environment(getApplicationContext(), cb);
    

然后在onCreate中调用它。

下面关于WebView的使用就只有一步了,那就是加载url,现在还没有的,去获取它。

三、获取新闻详情

  在聚合API中获取新闻详情是另一个接口,在写这个接口之前,先写一个返回的新闻详情数据。

① 新闻详情数据

在model包下新增一个NewsDetailResponse类,里面的代码如下:

public class NewsDetailResponse 

    private String reason;
    private ResultBean result;
    private Integer error_code;

    public String getReason() 
        return reason;
    

    public void setReason(String reason) 
        this.reason = reason;
    

    public ResultBean getResult() 
        return result;
    

    public void setResult(ResultBean result) 
        this.result = result;
    

    public Integer getError_code() 
        return error_code;
    

    public void setError_code(Integer error_code) 
        this.error_code = error_code;
    

    public static class ResultBean 
        private String uniquekey;
        private DetailBean detail;
        private String content;

        public String getUniquekey() 
            return uniquekey;
        

        public void setUniquekey(String uniquekey) 
            this.uniquekey = uniquekey;
        

        public DetailBean getDetail() 
            return detail;
        

        public void setDetail(DetailBean detail) 
            this.detail = detail;
        

        public String getContent() 
            return content;
        

        public void setContent(String content) 
            this.content = content;
        

        public static class DetailBean 
            private String title;
            private String date;
            private String category;
            private String author_name;
            private String url;
            private String thumbnail_pic_s;
            private String thumbnail_pic_s02;
            private String thumbnail_pic_s03;

            public String getTitle() 
                return title;
            

            public void setTitle(String title) 
                this.title = title;
            

            public String getDate() 
                return date;
            

            public void setDate(String date) 
                this.date = date;
            

            public String getCategory() 
                return category;
            

            public void setCategory(String category) 
                this.category = category;
            

            public String getAuthor_name() 
                return author_name;
            

            public void setAuthor_name(String author_name) 
                this.author_name = author_name;
            

            public String getUrl() 
                return url;
            

            public void setUrl(String url) 
                this.url = url;
            

            public String getThumbnail_pic_s() 
                return thumbnail_pic_s;
            

            public void setThumbnail_pic_s(String thumbnail_pic_s) 
                this.thumbnail_pic_s = thumbnail_pic_s;
            

            public String getThumbnail_pic_s02() 
                return thumbnail_pic_s02;
            

            public void setThumbnail_pic_s02(String thumbnail_pic_s02) 
                this.thumbnail_pic_s02 = thumbnail_pic_s02;
            

            public String getThumbnail_pic_s03() 
                return thumbnail_pic_s03;
            

            public void setThumbnail_pic_s03(String thumbnail_pic_s03) 
                this.thumbnail_pic_s03 = thumbnail_pic_s03;
            
        
    


② 新闻详情数据API

	/**
     * 聚合新闻数据详情
     */
    @GET("/toutiao/content?key=99d3951ed32af2930afd9b38293a08a2")
    Observable<NewsDetailResponse> newsDetail(@Query("uniquekey") String uniquekey);

这个接口用于请求新闻详情数据,返回值将会解析成NewsDetailResponse。

③ WebRepository

  数据有了,API接口有了,下面就是去调用的地方了,在repository包下新增一个WebRepository类,里面的代码如下:

@SuppressLint("CheckResult")
public class WebRepository 
    
    final MutableLiveData<NewsDetailResponse> newsDetail = new MutableLiveData<>();

    public final MutableLiveData<String> failed = new MutableLiveData<>();

    /**
     * 获取新闻详情数据
     * @param uniquekey 新闻ID
     * @return newsDetail
     */
    public MutableLiveData<NewsDetailResponse> getNewsDetail(String uniquekey) 
        NetworkApi.createService(ApiService.class, 2).
                newsDetail(uniquekey).compose(NetworkApi.applySchedulers(new BaseObserver<NewsDetailResponse>() 
            @Override
            public void onSuccess(NewsDetailResponse newsDetailResponse) 
                if (newsDetailResponse.getError_code() == 0) 
                    newsDetail.setValue(newsDetailResponse);
                 else 
                    failed.postValue(newsDetailResponse.getReason());
                
            

            @Override
            public void onFailure(Throwable e) 
                failed.postValue("NewsDetail Error: " + e.toString());
            
        ));
        return newsDetail;
    

很简单的代码,和之前的地方基本上没啥差别。

④ WebViewModel

  数据获取有了,下面就是通过ViewModel去关联Activity。在viewmodels包下新建一个WebViewModel,里面的代码如下:

public class WebViewModel extends BaseViewModel 

    public LiveData<NewsDetailResponse> newsDetail;

    public void getNewDetail(String uniquekey) 
        WebRepository webRepository = new WebRepository();
        failed = webRepository.failed;
        newsDetail = webRepository.getNewsDetail(uniquekey);
    

下面就是在WebActivity中去观察这个网络返回的数据了。

⑤ 页面数据处理

  打开WebActivity,实际上我们只需要修改onCreate中的代码就可以了,代码如下:

	@Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        ActivityWebBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_web);
        WebViewModel viewModel = new ViewModelProvider(this).get(WebViewModel.class);
        binding.webView.setWebViewClient(client);
        setStatusBar(true);
        // 在调用TBS初始化、创建WebView之前进行如下配置
        String uniquekey = getIntent().getStringExtra("uniquekey");
        if (uniquekey != null) 
            viewModel.getNewDetail(uniquekey);
            viewModel.newsDetail.observe(context, newsDetailResponse ->
                    binding.webView.loadUrl(newsDetailResponse.getResult().getDetail().getUrl()));
            viewModel.failed.observe(context, this::showMsg);
        
    

这里的代码很常规,首先是绑定布局,然后是ViewModel,再设置webView的配置客户端,设置状态栏,然后就是获取其他页面传递过来的参数,通过这个参数去请求接口,观察返回值,最后加载返回的url。

这里都完成了,下一步就是传递这个参数了,什么时候传递呢?当然是点击的时候了。

四、传递新闻参数

  在点击新闻列表中的某一项的时候传递参数到WebActivity中,在NewsAdapter类中添加如下代码:

	public static class ClickBinding 
        public void itemClick(NewsResponse.ResultBean.DataBean dataBean, View view) 
            if("1".equals(dataBean.getIs_content()))
                Intent intent = new Intent(view.getContext(), WebActivity.class);
                intent.putExtra("uniquekey", dataBean.getUniquekey());
                view.getContext().startActivity(intent);
             else 
                Toast.makeText(view.getContext(), "没有详情信息", Toast.LENGTH_SHORT).show();
            
        
    

当Is_content不为1的时候就表示没有详情信息,则提示一下即可。

然后在convert方法中添加一行代码,如下图所示:

最后就是修改item_newx.xml中的代码了,改动如下图所示:

由于我希望WebView可以沉浸式,因此我在AndroidManifest.xml中对这个WebActivity进行了主题设置,代码如下:

		<activity
            android:name=".ui.activity.WebActivity"
            android:theme="@style/SplashTheme" />

下面就可以运行了。

下面就是点击视频item打开视频的播放地址了。

五、热门视频播放

  这里首先要修改视频列表适配器中的内容,打开VideoAdapter,在里面增加如下代码:

	public static class ClickBinding 
        public void itemClick(@NotNull VideoResponse.ResultBean resultBean, View view) 
            if (resultBean.getShare_url() != null) 
                view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(resultBean.getShare_url())));
             else 
                Toast以上是关于Android MVVM框架搭建腾讯X5WebView + DrawerLayout + NavigationView的主要内容,如果未能解决你的问题,请参考以下文章

Android MVVM框架搭建OKHttp + Retrofit + RxJava

Android MVVM框架搭建OKHttp + Retrofit + RxJava

Android MVVM框架搭建ViewModel + LiveData + DataBinding

Android MVVM框架搭建ViewModel + LiveData + DataBinding

Android MVVM框架搭建高德地图定位天气查询BottomSheetDialog

Android MVVM框架搭建HiltViewBindingActivity Result API