-
獲取阿里雲圖片的過程
服務器返回圖片地址——請求服務器返回圖片真實地址——獲取圖片 -
目前遇到的問題
重複進行1的過程影響性能,實現圖片加速加載。 -
在實際開發中的表現
·滑動列表時滑出去的item再次顯示時會重複上述過程。
·反覆查看某張圖片。 -
實現過程
4.1 已經完成的實現
let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};
// network是封裝的聯網請求
let result = await network({
type: "POST",
url: '/mobile/oss/signForAppPic',
param: params
}, token);
let reSetResult = result.response ? result.response : result;
let realPaths = reSetResult.result;
實現了在加載圖片之前,從服務器獲取真實的圖片地址realPaths,然後再交給Image組件展示。發現真實的圖片路徑:https://gysy-picture.oss-cn-beijing.aliyuncs.com/app/x61tnmfx/BGQZ/ba112d3b-d41c-438a-ae88-002069a71aac.jpg?Expires=1543212261&OSSAccessKeyId=**********&Signature=*********&x-oss-process=image%2Fresize%2Cm_fixed%2Cw_100%2Ch_100
。
有一個參數Expires是該圖片在阿里雲失效的時間秒數。因此,出現了一個解決思路就是:緩存真實的圖片地址,每次加載圖片時先看是否有緩存,緩存的圖片是否在有效期內,如果是就直接加載圖片;否的話,獲取圖片真實地址,再加載圖片並緩存。
4.2 實現步驟
-
圖片地址的緩存,實現包括:初始化緩存對象、獲取緩存中的值、設置緩存中的值。通過這幾個方式實現了緩存的管理。(見4.3使用)
-
有效期的判斷,通過Expires與當前時間的對比。在已實現代碼前添加判斷,添加後:
let realPaths;
if (isValid(cacheRealPaths) && this.state ) {
realPaths = cacheRealPaths;
return;
}
let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};
// network是封裝的聯網請求,可以根據實際的聯網請求進行更改
let result = await network({
type: "POST",
url: '/mobile/oss/signForAppPic',
param: params}, token);
let reSetResult = result.response ? result.response : result;
realPaths = reSetResult.result;
4.3 使用
將使用的方法封裝到了ALiYunImageCache.js中。
/**
* 初始化緩存對象
* @param arr
* @returns {*}
*/
let initCache = (arr) => {
if (arr) {
return new Array(arr.length);
} else {
return null;
}
};
/**
* 獲取緩存中的值
* @param arr
* @param index
* @returns {*}
*/
let getCache = (arr, index) => {
if (arr && arr.length > index) {
return arr[index];
} else {
return arr;
}
};
/**
* 設置緩存中的值
* @param arr
* @param index
* @param newItem
* @returns {*}
*/
let setCache = (arr, index, newItem) => {
if (arr && arr.length > index) {
return arr[index] = newItem;
} else {
return newItem;
}
};
/**
* 驗證緩存是否有效
* @param cacheRealPaths
* @returns {boolean}
*/
let isValid = (cacheRealPaths) => {
if (cacheRealPaths && cacheRealPaths.length > 0) {
let start = cacheRealPaths[0].indexOf('=') + 1;
let end = cacheRealPaths[0].indexOf('&');
let validTime = parseInt(cacheRealPaths[0].substring(start, end));
let curTime = (new Date().getTime()) / 1000;
if (validTime > curTime) {
return true;
}
}
return false;
};
module.exports = {initCache, getCache, setCache, isValid};
- 初始化
構造方法裏和緩存對象變化時,使用其中的initCache(arr)方法,返回保存的變量。arr:緩存的對象是列表時,傳入對應的數組;否則傳服務器返回的圖片地址。 - 獲取緩存對象
給展示圖片的組件使用,getCache(arr, index)。arr是第一步保存的變量,index:緩存的對象是數組時,傳入list中對應的索引;否則不傳。 - 更新緩存
使用setCach(arr, index, newItem)。arr是第一步保存的變量,index:緩存的對象是數組時,傳入list中對應的索引;否則傳null。newItem:傳新需要緩存的圖片地址。
- 例子(一個列表每個item包含多張圖片)
export default class demo extends Component {
constructor(props) {
super(props);
// 初始化
this.cacheRealPaths = initCache(props.connectListData);
}
componentWillReceiveProps(props) {
if (props.dataList !== this.props.dataList) {
// 所對應list數據變化時,重新初始化緩存
this.cacheRealPaths = initCache(props.dataList);
}
};
renderItem = ({item, index}) => (
<DemoItem
index={index}
data={item}
cacheRealPaths={getCache(this.cacheRealPaths, index)} // 獲取該index對應的緩存
updateCacheRealPath={(index, arr) => setCache(this.cacheRealPaths, index, arr)} // 設置index對應的緩存
/>
);
render() {
return (
<View>
<FlatList
data={this.props.dataList}
keyExtractor={(item) => this.keyExtractor(item)}
renderItem={this.renderItem}
/>
</View>
);
}
}
class DemoItem extends Component {
render() {
return (
<View>
<PhotoHorizontalScroll
paths={this.props.data.pictures}
cacheRealPaths={this.props.cacheRealPaths}
updateCacheRealPath={(arr) => this.props.updateCacheRealPath(this.props.index, arr)}
</View>
)
}
}
export default class PhotoHorizontalScroll extends Component {
// 構造
constructor(props) {
super(props);
this.state = {
paths: []
};
...
this.newPaths = null;
}
...
showPictures = async (paths, cacheRealPaths) => {
this.newPaths = paths;
if (paths && paths.length > 0) {
// 添加有效判斷
if (isValid(cacheRealPaths) && this.state ) {
this.setState({paths: cacheRealPaths});
return;
}
let userInfo = await getUserInfo();
let token = '';
if (userInfo) {
token = userInfo.access_token;
}
let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};
let result = await network({
type: "POST",
url: '/mobile/oss/signForAppPic',
param: params
}, token);
let reSetResult = result.response ? result.response : result;
// 通知父組件更新緩存
this.props.updateCacheRealPath && this.props.updateCacheRealPath(reSetResult.result);
if (this.newPaths === paths && this.state) {
this.setState({
paths: reSetResult.result
})
}
}
else {
if (this.state) {
this.setState({
paths: []
})
}
}
};
...
render() {
return (
<ScrollView style={[this.props.style]}
horizontal={true}
showsHorizontalScrollIndicator={false}
>
<View style={{flexDirection: 'row'}}>
{this.renderImages(this.state.paths)}
</View>
</ScrollView>
);
}
}