/*
* Tencent is pleased to support the open source community by making
* Tencent GT (Version 2.4 and subsequent versions) available.
*
* Notwithstanding anything to the contrary herein, any previous version
* of Tencent GT shall not be subject to the license hereunder.
* All right, title, and interest, including all intellectual property rights,
* in and to the previous version of Tencent GT (including any and all copies thereof)
* shall be owned and retained by Tencent and subject to the license under the
* Tencent GT End User License Agreement (http://gt.qq.com/wp-content/EULA_EN.html).
*
* Copyright (C) 2015 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.wstt.gtdemo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.SimpleAdapter;
import android.widget.SimpleAdapter.ViewBinder;
import android.widget.Toast;
import com.tencent.wstt.gt.client.GT;
public class GTDemoActivity extends Activity implements UserStrings {
private Button showImg;
private GridView gridview;
private ArrayList<Map<String, Object>> lstImageItem = new ArrayList<Map<String, Object>>();
private Map<String, Object> map;
private SimpleAdapter saImageItems;
private final int CLEAR_GRIDVIEW = 0;
private final int LOAD_IMG_OK = 1;
private final int LOAD_IMG_ERROR = -1;
// 本demo显示的图片数目
private static final int img_Count = 9;
/*
* 需要输出参数动态调整的属性
*/
private int max_thread_num = 1;
private int con_timeOut = 60 * 1000;
private int read_timeOut = 60 * 1000;
private boolean flag_keepAliave = true;
// 图片解码操作的线程池
private ExecutorService decodePool = Executors.newFixedThreadPool(img_Count);
private Bitmap[] bitmaps = new Bitmap[img_Count];
private String[] urls = new String[img_Count];
/*
* GT观察用变量
*/
AtomicInteger completeSum = new AtomicInteger(); // 已完成下载的图片数,需并发安全
long startTime; // 本次下载图片的开始时间
long endTime; // 本次下载完所有图片的结束时间
long totalTime; // 已完成下载的图片的总耗时
AtomicLong totalSize = new AtomicLong(); // 已完成下载的图片的总大小
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gt_demo);
showImg = (Button)findViewById(R.id.showimg);
showImg.setOnClickListener(showImage);
gridview = (GridView)findViewById(R.id.gridview);
saImageItems = new SimpleAdapter(getApplicationContext(), lstImageItem,
R.layout.gt_gridview_item, new String[]{"img"}, new int[]{R.id.ItemImage});
}
@Override
protected void onResume() {
super.onResume();
gridview.setAdapter(saImageItems);
// 10k大小左右的图片
urls[0] = "http://111.161.48.64/sosopic/0/1420666048153445210/320";
urls[1] = "http://111.161.48.64/sosopic/0/9869660902850290294/320";
urls[2] = "http://111.161.48.64/sosopic/0/7906532888606229180/320";
urls[3] = "http://111.161.48.64/sosopic/0/9416045979901772820/320";
urls[4] = "http://111.161.48.64/sosopic/0/10614843762795705578/320";
urls[5] = "http://111.161.48.64/sosopic/0/8025199124411859454/320";
urls[6] = "http://111.161.48.64/sosopic/0/5054744870201991274/320";
urls[7] = "http://111.161.48.64/sosopic/0/12417944983283013250/320";
urls[8] = "http://111.161.48.64/sosopic/0/14359830428608672234/320";
// urls[9] = "http://111.161.48.64/sosopic/0/5476654313994007188/320";
}
OnClickListener showImage = new OnClickListener() {
@Override
public void onClick(View v) {
handler.sendEmptyMessage(CLEAR_GRIDVIEW);
/*
* GT usage
* GT init start 每次执行前,初始化统计用的变量与输出参数值
*/
completeSum.set(0);
totalTime = 0;
totalSize.set(0);
startTime = endTime = 0;
GT.setOutPara(下载耗时, "");
GT.setOutPara(NumberOfDownloadedPics, "");
GT.setOutPara(实际带宽, "");
GT.setOutPara(singlePicSpeed, "");
/*GT init end*/
Thread thread = new Thread(new LoadPics());
thread.start();
}
};
Handler handler = new Handler(){
public void handleMessage(Message msg) {
GT.setOutPara(NumberOfDownloadedPics, completeSum.get());
switch(msg.what){
case CLEAR_GRIDVIEW:
lstImageItem.clear();
for(int i = 0 ; i < img_Count ; i++){
map = new HashMap<String, Object>();
map.put("img", R.drawable.background);
lstImageItem.add(map);
}
gridview.setAdapter(saImageItems);
break;
case LOAD_IMG_OK:
int picId = msg.getData().getInt("picId");
for(int i = 0 ; i < img_Count ; i++){
if(picId == i){
map = lstImageItem.get(i);
map.put("img", bitmaps[picId]);
break;
}
}
saImageItems.setViewBinder(new ViewBinder() {
@Override
public boolean setViewValue(View view, Object data,
String textRepresentation) {
if(view instanceof ImageView && data instanceof Bitmap){
ImageView iv = (ImageView) view;
iv.setImageBitmap((Bitmap)data);
return true;
}else{
return false;
}
}
});
gridview.setAdapter(saImageItems);
/*GT Usage start*/
GT.endTime(下载完成后到UI展示, String.valueOf(picId));
if (completeSum.get() == img_Count && totalTime > 0) {
long tempTime = (endTime - startTime)/1000000; // 纳秒转毫秒
if (tempTime > 0) {
double second = div(tempTime, 1000L, 3);
GT.setOutPara(下载耗时, second + "s");
long speed = totalSize.get() / tempTime;
GT.setOutPara(实际带宽, speed + "k/s");
}
}
GT.logI(UI处理图片, "按成功情况处理图片完成:" + picId);
/*GT Usage end*/
break;
case LOAD_IMG_ERROR:
int erro_picId = msg.getData().getInt("picId");
for(int i = 0 ; i < img_Count ; i++){
if(erro_picId == i){
map = lstImageItem.get(i);
map.put("img", R.drawable.error);
}
}
gridview.setAdapter(saImageItems);
Toast.makeText(getApplicationContext(),
"Download Error,picId:" + erro_picId, Toast.LENGTH_SHORT)
.show();
GT.logE(UI处理图片, "按失败情况处理图片完成:" + erro_picId);
break;
}
};
};
class LoadPics implements Runnable{
@Override
public void run() {
/*
* GT usage
* 使用输入参数"开启线程数"初始化线程池,默认线程数为代码逻辑的原值max_thread_num
* 当输入参数设置失效时,默认值取max_thread_num就不会改变原有代码业务逻辑
*/
max_thread_num = GT.getInPara(并发线程数, max_thread_num);
ExecutorService t = Executors.newFixedThreadPool(max_thread_num);
/*GT start*/
if (startTime == 0)
{
startTime = System.nanoTime();
}
/*GT end*/
for (int i = 0; i < urls.length; i++)
{
t.execute(new Task(urls[i], i));
}
t.shutdown();
}
}
class Task implements Runnable {
private String url;
private int picId;
Task(String url, int picId){
this.url = url;
this.picId = picId;
}
@Override
public void run() {
// GT usage
GT.startTimeInThread(线程内统计, 图片下载);
InputStream is = getInputStream(url);
try
{
// 下载
final byte[] data = getBytesFromIS(is);
/*GT usage start*/
endTime = System.nanoTime();
totalSize.addAndGet(data.length);
GT.logI(速度统计, "length=" + data.length + "Byte totalSize=" + totalSize + "Byte");
long et = GT.endTimeInThread(线程内统计, 图片下载);
GT.logI(图片下载, "完成图片下载并渲染步骤(失败或成功),id:" + picId);
et = et/1000000; // endTime取回来的是纳秒级,转成毫秒级别
totalTime += et;
GT.logI(速度统计, "pic" + picId + "=" + et + "ms" + " total=" + totalTime + "ms");
if (et > 0) {
long speed = data.length / et;
GT.setOutPara(singlePicSpeed, speed + "k/s");
}
completeSum.incrementAndGet();
/*GT usage end*/
// 独立线程解码图片
decodePool.execute(new Runnable() {
@Override
public void run() {
try{
bitmaps[picId] = BitmapFactory.decodeByteArray(data, 0, data.length);
Message msg = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt("picId", picId);
msg.setData(bundle);
msg.what = LOAD_IMG_OK;
/*GT start*/
GT.startTime(下载完成后到UI展示, String.valueOf(picId));
/*GT end*/
msg.sendToTarget();
}
catch(Exception e)
{
GT.logE(图片下载, "图片解码失败:" + picId);
e.printStackTrace();
}
}});
}
catch(Exception e)
{
handleLoadPicException(picId);
}
}
}
private byte[] getBytesFromIS(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = 0;
while ((b = is.read()) != -1)
{
baos.write(b);
}
return baos.toByteArray();
}
private void handleLoadPicException(int picId)
{
/*GT start*/
endTime = System.nanoTime();
long et = GT.endTimeInThread(线程内统计, 图片下载);
et = et/1000000; // endTime取回来的是纳秒级,转成毫秒级别
totalTime += et;
GT.logE(速度统计, "下载图片失败:" + picId);
if (et > 0) {
GT.setOutPara(singlePicSpeed, "--");
}
completeSum.incrementAndGet();
/*GT end*/
Message msg = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt("picId", picId);
msg.setData(bundle);
msg.what = LOAD_IMG_ERROR;
msg.sendToTarget();
}
private InputStream getInputStream(String imagePath){
URL url;
try {
url = new URL(imagePath);
HttpURLConnection conn;
// 对每个图片的连接速度进行性能统计
conn = (HttpURLConnection) url.openConnection();
// 使用输入参数"超时时间"确定是连接的超时时间
con_timeOut = GT.getInPara(连接超时, 60000);
conn.setConnectTimeout(con_timeOut);
read_timeOut = GT.getInPara(读超时, 60000);
conn.setReadTimeout(read_timeOut);
// 使用输入参数"维持长链接"确定是长连接还是短连接
flag_keepAliave = GT.getInPara(KeepAlive, true);
if(!flag_keepAliave){
conn.setRequestProperty("Connection", "close");
System.setProperty("http.keepAlive", "false");
}
conn.setRequestMethod("GET");
/*GT start*/
GT.startTimeInThread(线程内统计, Http响应耗时);
int resCode = -1;
try{
resCode = conn.getResponseCode();
}
catch(Exception e)
{
GT.logE(速度统计, "Http连接异常:" + e.getMessage());
}
GT.endTimeInThread(线程内统计, Http响应耗时);
/*GT end*/
if(200 == resCode){
InputStream inputStream = conn.getInputStream();
return inputStream;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* double 除法
*
* @param d1
* @param d2
* @param scale
* 四舍五入 小数点位数
* @return
*/
public static double div(double d1, double d2, int scale) {
// 当然在此之前,你要判断分母是否为0,
// 为0你可以根据实际需求做相应的处理
BigDecimal bd1 = new BigDecimal(Double.toString(d1));
BigDecimal bd2 = new BigDecimal(Double.toString(d2));
// return bd1.divide(bd2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
// 直接向下取整,保持和UI展示一致
return bd1.divide(bd2, scale, BigDecimal.ROUND_DOWN).doubleValue();
}
}