在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Android/ 創(chuàng)建RecyclerView Adapter
combineLatest
從列表創(chuàng)建一個Observable
RxJava的與眾不同之處
Schedulers
RxJava觀察者模式工具包
總結(jié)
工具
你什么時候使用觀察者模式?
GroupBy
App架構(gòu)
組合Observables
創(chuàng)建Activity類
StartWith
RX - 從.NET到RxJava
處理耗時的任務(wù)
過濾Observables
向響應(yīng)式世界問好
避免阻塞I/O的操作
Join
有且僅有一次
Schedulers-解決Android主線程問題
轉(zhuǎn)換Observables
啟動引擎
我們的第一個Observable
總結(jié)
StrictMode
Debounce
*map家族
創(chuàng)建RecyclerView Adapter
為什么是Observables?
Merge
再多幾個例子
總結(jié)
Buffer
Window
總結(jié)
Timeout
執(zhí)行網(wǎng)絡(luò)任務(wù)
項目目標(biāo)
來到Java世界 - Netflix RxJava
獲取我們需要的數(shù)據(jù)
Observable
過濾序列
非阻塞I/O操作
ZIP
總結(jié)
And,Then和When
觀察者模式
Retrofit
Cast
Skip and SkipLast
微軟響應(yīng)式擴(kuò)展
與REST無縫結(jié)合-RxJava和Retrofit
First and last
RxJava Essentials 中文翻譯版
Switch
ElementAt
總結(jié)
總結(jié)
總結(jié)
Sampling
SubscribeOn and ObserveOn
Subject = Observable + Observer

創(chuàng)建RecyclerView Adapter

我們從REST API獲取到數(shù)據(jù)后,我們需要把它綁定View上,并用一個適配器填充列表。我們的RecyclerView適配器是標(biāo)準(zhǔn)的。它繼承于RecyclerView.Adapter并指定它自己的ViewHolder

public static class ViewHolder extends RecyclerView.ViewHolder {
    @InjectView(R.id.name) TextView name;
    @InjectView(R.id.city) TextView city;
    @InjectView(R.id.reputation) TextView reputation;
    @InjectView(R.id.user_image) ImageView user_image;
    public ViewHolder(View view) { 
        super(view);
        ButterKnife.inject(this, view); 
    }
}

我們一旦收到來自API管理器的數(shù)據(jù),我們可以設(shè)置界面上所有的標(biāo)簽:name,cityreputation。

為了展示用戶的頭像,我們將使用Sergey Tarasevich寫的Universal Image Loader。實踐證明,UIL是非常有名的好用的圖片管理庫。我們也可以使用Square公司的Picasso,Glide或者Facebook公司的Fresco。取決于你自己的喜好。最關(guān)鍵的是無需重復(fù)造輪子:庫能夠方便開發(fā)者并讓他們更快速實現(xiàn)目標(biāo)。

在我們的適配器中,我們可以這樣:

@Override
public void onBindViewHolder(SoAdapter.ViewHolder holder, int position) {
    User user = mUsers.get(position);
    holder.setUser(user); 
}

ViewHolder,我們可以這樣:

public void setUser(User user) { 
    name.setText(user.getDisplayName());
    city.setText(user.getLocation());
    reputation.setText(String.valueOf(user.getReputation()));

    ImageLoader.getInstance().displayImage(user.getProfileImage(), user_image);
}

此時,我們可以允許代碼獲得一個用戶列表,正如下圖所示:

http://wiki.jikexueyuan.com/project/rxjava/images/chapter8_1.png" alt="" />

檢索天氣預(yù)報

我們加大難度,將當(dāng)?shù)爻鞘械奶鞖饧尤肓斜碇小?strong>OpenWeatherMap是一個靈活公共在線天氣API,我們可以查詢許多有用的預(yù)報信息。

和往常一樣,我們將使用Retrofit映射到API然后通過RxJava來訪問它。至于StackExchange API,我們將創(chuàng)建interface,RestAdapter和一個靈活的管理器:

public interface OpenWeatherMapService {
    @GET("data2.5/weather")
    Observable<WeatherResponse> getForecastByCity(@Query("q") String city);
}

這個方法用城市名字作為參數(shù)提供當(dāng)?shù)氐念A(yù)報信息。我們像下面這樣將接口和RestAdapter類綁定在一起:

RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint("http://api.openweathermap.org")
        .setLogLevel(RestAdapter.LogLevel.BASIC)
        .build();
mOpenWeatherMapService = restAdapter.create(OpenWeatherMapService.class);

像以前一樣,我們只有兩件事需要立馬去做:設(shè)置API端口和log級別。

OpenWeatherMapApiManager類將提供下面的方法:

public Observable<WeatherResponse> getForecastByCity(String city) {
    return mOpenWeatherMapService.getForecastByCity(city)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread());
}

現(xiàn)在,我們有了用戶列表,我們可以根據(jù)城市名來查詢OpenWeatherMap獲得天氣預(yù)報信息。下一步是修改我們的ViewHolder類來為每位用戶展示相應(yīng)的天氣圖標(biāo)。

我們使用這些工具方法先驗證用戶主頁信息并獲得一個合法的城市名字:

private boolean isCityValid(String location) {
    int separatorPosition = getSeparatorPosition(location);
    return !"".equals(location) && separatorPosition > -1; 
}

private int getSeparatorPosition(String location) { 
    int separatorPosition = -1;
    if (location != null) {
        separatorPosition = location.indexOf(","); 
    }
    return separatorPosition; 
}

private String getCity(String location, int position) {
    if (location != null) {
        return location.substring(0, position); 
    } else {
        return ""; 
    }
}

借助一個有效的城市名,我們可以用下面命令來獲得我們所需要天氣的所有數(shù)據(jù):

OpenWeatherMapApiManager.getInstance().getForecastByCity(city)

用天氣響應(yīng)的結(jié)果,我們可以獲得天氣圖標(biāo)的URL:

getWeatherIconUrl(weatherResponse);

用圖標(biāo)URL,我們可以檢索到圖標(biāo)本身:

private Observable<Bitmap> loadBitmap(String url) {
    return Observable.create(subscriber -> {
        ImageLoader.getInstance().displayImage(url,city_image, new ImageLoadingListener() { 
            @Override
            public void onLoadingStarted(String imageUri, View view) {
            }

            @Override
            public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                subscriber.onError(failReason.getCause()); 
            }

            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                subscriber.onNext(loadedImage);
                subscriber.onCompleted(); 
            }

            @Override
            public void onLoadingCancelled(String imageUri, View view) {
                subscriber.onError(new Throwable("Image loading cancelled"));
            }
         });
    });
}

這個loadBitmap()返回的Observable可以鏈接前面一個,并且最后我們可以為這個任務(wù)返回一個單獨的Observable:

if (isCityValid(location)) {
    String city = getCity(location, separatorPosition);
    OpenWeatherMapApiManager.getInstance().getForecastByCity(city)
        .filter(response -> response != null)
        .filter(response -> response.getWeather().size() > 0)
        .flatMap(response -> {
            String url = getWeatherIconUrl(response);
            return loadBitmap(url);
        })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<Bitmap>() {

        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable e) {
            App.L.error(e.toString()); 
        }

        @Override
        public void onNext(Bitmap icon) {
            city_image.setImageBitmap(icon); 
        }
    });
}

運行代碼,我們可以在下面列表中為每個用戶獲得新的天氣圖標(biāo): http://wiki.jikexueyuan.com/project/rxjava/images/chapter8_2.png" alt="" />

打開網(wǎng)站

使用用戶主頁包含的信息,我們將會創(chuàng)建一個onClick監(jiān)聽器來導(dǎo)航到用戶web頁面,如果有的話,否則打開在Stack Overflow上的個人主頁。

為了實現(xiàn)它,我們簡單實現(xiàn)Activity類的接口,用來在適配器觸發(fā)Android的onClick事件。

我們的Adapter ViewHolder指定這個接口:

public interface OpenProfileListener {
    public void open(String url); 
}

Activity實現(xiàn)它:

[...] implements SoAdapter.ViewHolder.OpenProfileListener { [...]
    mAdapter.setOpenProfileListener(this); 
[...]

@Override
public void open(String url) {
    Intent i = new Intent(Intent.ACTION_VIEW);
    i.setData(Uri.parse(url)); 
    startActivity(i);
}

Activity收到URL并用外部Android瀏覽器打開它。我們的ViewHolder負(fù)責(zé)在用戶列表的每個卡片上創(chuàng)建OnClickListener并檢查我們是打開Stack Overflow用戶主頁還是外部個人站:

mView.setOnClickListener(view -> { 
    if (mProfileListener != null) {
        String url = user.getWebsiteUrl();
        if (url != null && !url.equals("") && !url.contains("search")) {
            mProfileListener.open(url); 
        } else {
            mProfileListener.open(user.getLink()); 
        }
    }
)};

一旦我們點擊了,我們將直接重定向到預(yù)期的網(wǎng)站。在Android上,我們可以用RxAndroid的一種特殊形式(ViewObservable)以更加響應(yīng)式的方式實現(xiàn)同樣的結(jié)果。

ViewObservable.clicks(mView)
    .subscribe(onClickEvent -> {
    if (mProfileListener != null) {
        String url = user.getWebsiteUrl();
        if (url != null && !url.equals("") && !url.contains("search")) { 
            mProfileListener.open(url);
        } else {
            mProfileListener.open(user.getLink());
        } 
    }
});

上面兩塊代碼片段是等價的,你可以選擇最喜歡的方式來實現(xiàn)。