转载请标明出处:http://blog.csdn.net/sk719887916/article/details/40049137,作者:skay
从上一篇学习中,学习了多媒体技术中的怎么去用josup加载一个网页并解析html标签的用法,今天就接着前篇 【安卓TV开发(七) 移动智能终端多媒体之在线解析网页视频源】 的学习。同时也了解下避免安卓内存溢出解决方式和安卓常用的几种UI更新的方式。
一 准备异步加载工具
1 新建 VideoLoaderTask 用来获取视频列表
-
-
-
-
- public class VideoLoaderTask extends
- AsyncTask<TvModle, String, List<TvTaiModel>> {
-
- @SuppressWarnings("unchecked")
-
- @Override
- protected List<TvTaiModel> doInBackground(TvModle... params) {
-
- return lists = DataVideoManager.getData(params[0]);
- }
-
- @Override
- protected void onPostExecute(final List<TvTaiModel> resList) {
-
- mAuthTask = null;
- showProgress(false);
- if (resList != null && resList.size() > 0) {
-
- adapter = new VideoWallAdapter(VideoInfoActivity.this, 0,
- resList, mPhotoWall);
-
- mPhotoWall.setAdapter(adapter);
-
- adapter.notifyDataSetChanged();
- } else {
- Toast.makeText(VideoInfoActivity.this, "失败", Toast.LENGTH_SHORT).show();
- }
- }
-
- @Override
- protected void onCancelled() {
- mAuthTask = null;
- showProgress(false);
-
- }
此类设计到安卓AsyncTask的用法,需要大家了解此Api,具体原理是利用Thead+ handler机制实现,实际开发中我们更新UI也可以用安卓自带的UI线程runOnUiThread 代码可以如下,具体执行动作在run()实现,不管是用哪种
的方式
更新UI,必须注意的是主线程不能执行网络耗时操作任务,容易出现ANR,(安卓4.0rom以后 主线程直接不能访问网络)。UI也必须由主线程来更新,子线程无UI操作权限。
1) 利用UI线程
- this.runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
-
-
- }
- });
2 ) 利用handler发送Message
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
-
- super.handleMessage(msg);
- }
- };
3) 利用view的post方法
- <span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14.7368421554565px; line-height: 35px;"> View.post(</span>new Runnable() {
-
- @Override
- public void run() {
-
-
- }
- }
)
4 )AsyncTask
AsyncTask.start() 一般用此类获取网络数据,但是本线程不能重复调用,不然会出异常,只有在task没有运行的情况下才能调用start()方法,多个线程同是调用其start() 也会出现线程安全问题。
2 因为网络任务还耗时的因此给Task加一个过渡loading
-
-
-
- @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
- private void showProgress(final boolean show) {
-
-
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
- int shortAnimTime = getResources().getInteger(
- android.R.integer.config_shortAnimTime);
-
- mLoginStatusView.setVisibility(View.VISIBLE);
- mLoginStatusView.animate().setDuration(shortAnimTime)
- .alpha(show ? 1 : 0)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mLoginStatusView.setVisibility(show ? View.VISIBLE
- : View.GONE);
- }
- });
-
- mPhotoWall.setVisibility(View.VISIBLE);
- mPhotoWall.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mPhotoWall.setVisibility(show ? View.GONE
- : View.VISIBLE);
- }
- });
- } else {
-
-
- mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
- mPhotoWall.setVisibility(show ? View.GONE : View.VISIBLE);
- }
- }
3 获取到网络数据必定含有图片 为了防止OOM,新建ImageLoader
当然目前已经有开源的图片缓存框架,但是我们必须懂期原理,为了防止图片内存溢出,我们必须合理利用安卓内存,熟悉安卓回收机制的朋友也非常了解安卓强引用和弱引用,所谓的一级缓存和二级缓存,开发中常用的缓存技术,一般是采用合理分配内存和适当过渡承载实现,具体可以获取手机当前的内存大小,合理设置本次图片请求的最大的负载内存,超过了缓存大小 移除使用频率较低的图片键值,一般是去sd卡读取资源,然后再内存,最后才去请求网络数据。当然请求的图片实际尺寸过大会导致oom。因此必要时还需要根据当前屏幕上所要展示ImageView的大小去缩放bitmap,本人平时喜欢绘制bitmap带自自定义控件上,不喜欢用安卓原生的图片控件。其利弊以后我再慢慢道来。
1 ), 具体缓存逻辑如下,
- public class ImageLoader {
-
-
-
-
- private static LruCache<String, Bitmap> mMemoryCache;
-
-
-
-
- private static ImageLoader mImageLoader;
-
- @SuppressLint("NewApi")
- private ImageLoader() {
-
- int maxMemory = (int) Runtime.getRuntime().maxMemory();
- int cacheSize = maxMemory / 8;
-
- mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
- @SuppressLint("NewApi")
- @Override
- protected int sizeOf(String key, Bitmap bitmap) {
- return bitmap.getByteCount();
- }
- };
- }
-
-
-
-
-
-
- public static ImageLoader getInstance() {
- if (mImageLoader == null) {
- mImageLoader = new ImageLoader();
- }
- return mImageLoader;
- }
-
-
-
-
-
-
-
-
-
- @SuppressLint("NewApi")
- public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
- if (getBitmapFromMemoryCache(key) == null) {
- mMemoryCache.put(key, bitmap);
- }
- }
-
-
-
-
-
-
-
-
- @SuppressLint("NewApi")
- public Bitmap getBitmapFromMemoryCache(String key) {
- return mMemoryCache.get(key);
- }
-
- public static int calculateInSampleSize(BitmapFactory.Options options,
- int reqWidth) {
-
- final int width = options.outWidth;
- int inSampleSize = 1;
- if (width > reqWidth) {
-
- final int widthRatio = Math.round((float) width / (float) reqWidth);
- inSampleSize = widthRatio;
- }
- return inSampleSize;
- }
-
- public static Bitmap decodeSampledBitmapFromResource(String pathName,
- int reqWidth) {
-
- final BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(pathName, options);
-
- options.inSampleSize = calculateInSampleSize(options, reqWidth);
-
- options.inJustDecodeBounds = false;
- return BitmapFactory.decodeFile(pathName, options);
- }
-
- }
4 新建请求图片的异步加载任务
-
-
-
-
-
- class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
-
-
-
-
- private String imageUrl;
-
- @Override
- protected Bitmap doInBackground(String... params) {
- imageUrl = params[0];
-
- Bitmap bitmap = downloadBitmap(params[0]);
- if (bitmap != null) {
-
- addBitmapToMemoryCache(params[0], bitmap);
- }
- return bitmap;
- }
-
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- super.onPostExecute(bitmap);
-
- ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl);
- if (imageView != null && bitmap != null) {
- imageView.setImageBitmap(bitmap);
- }
- taskCollection.remove(this);
- }
-
-
-
-
-
-
-
-
- private Bitmap downloadBitmap(String imageUrl) {
- Bitmap bitmap = null;
- HttpURLConnection con = null;
- try {
- URL url = new URL(imageUrl);
- con = (HttpURLConnection) url.openConnection();
- con.setConnectTimeout(5 * 1000);
- con.setReadTimeout(10 * 1000);
- bitmap = BitmapFactory.decodeStream(con.getInputStream());
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (con != null) {
- con.disconnect();
- }
- }
- return bitmap;
- }
-
- }
二 新建视图 activity
我们可以利用第五篇中实现的UI界面加以利用 点击去请求音悦台MV视频数据。
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_video_info);
- mContext = getBaseContext();
-
- mImageThumbSize = getResources().getDimensionPixelSize(
- R.dimen.image_thumbnail_size);
- mImageThumbSpacing = getResources().getDimensionPixelSize(
- R.dimen.image_thumbnail_spacing);
- mLoginStatusView = this.findViewById(R.id.login_status);
- mLoginStatusMessageView = (TextView) this
- .findViewById(R.id.login_status_message);
- mPhotoWall = (GridView) findViewById(R.id.video_info);
-
- mPhotoWall.setOnItemClickListener(this);
- if (getIntent().getExtras() != null) {
-
- modle = (TvModle) getIntent().getExtras().getSerializable(
- "TvModle");
- if (modle != null) {
- mUrl = modle.getUrl();
- }
-
- }
- mPhotoWall.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
-
- @Override
- public void onGlobalLayout() {
- final int numColumns = (int) Math.floor(mPhotoWall
- .getWidth()
- / (mImageThumbSize + mImageThumbSpacing));
- if (numColumns > 0) {
- int columnWidth = (mPhotoWall.getWidth() / numColumns)
- - mImageThumbSpacing;
-
- mPhotoWall.getViewTreeObserver()
- .removeGlobalOnLayoutListener(this);
- }
- }
- });
-
- attemptLoader();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- adapter.cancelAllTasks();
- }
-
-
-
-
-
-
- public void attemptLoader() {
- if (mAuthTask != null) {
- return;
- }
-
- boolean cancel = false;
-
- if (cancel) {
-
- } else {
-
-
- showProgress(true);
- mAuthTask = new VideoLoaderTask();
- mAuthTask.execute(modle);
- }
- }
三 增加控制逻辑
创建gridView适配器 VideoWallAdapter
- public class VideoWallAdapter extends ArrayAdapter<TvTaiModel> implements OnScrollListener {
-
-
-
-
- private Set<BitmapWorkerTask> taskCollection;
-
-
-
-
- private LruCache<String, Bitmap> mMemoryCache;
-
-
-
-
- private GridView mPhotoWall;
-
-
-
-
- private int mFirstVisibleItem;
-
-
-
-
- private int mVisibleItemCount;
-
-
-
-
- private boolean isFirstEnter = true;
-
- private List< TvTaiModel> lists = null;
-
- @SuppressLint("NewApi")
- public VideoWallAdapter(Context context, int textViewResourceId, List<TvTaiModel> taiModels,
- GridView photoWall) {
- super(context, textViewResourceId, taiModels);
-
- lists = taiModels;
- mPhotoWall = photoWall;
- taskCollection = new HashSet<BitmapWorkerTask>();
-
- int maxMemory = (int) Runtime.getRuntime().maxMemory();
- int cacheSize = maxMemory / 8;
-
- mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
- @Override
- protected int sizeOf(String key, Bitmap bitmap) {
- return bitmap.getByteCount();
- }
- };
- mPhotoWall.setOnScrollListener(this);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- final String url = lists.get(position).getImg();
- final String name = lists.get(position).getTitle();
-
- Log.e("VideoWallAdapter", url);
- View view;
- if (convertView == null) {
- view = LayoutInflater.from(getContext()).inflate(R.layout.vedio_item, null);
- } else {
- view = convertView;
- }
- final ImageView photo = (ImageView) view.findViewById(R.id.photo);
- final TextView title = (TextView) view.findViewById(R.id.title);
-
- photo.setTag(url);
- setImageView(url, photo);
- title.setText(name);
- return view;
- }
此时的我们的基础工具类已完成, 接下来 给我们的FocusView所在的acitity注册处理点击事件,用于获取当前TV的视频Url
- @Override
- public void onItemClick(FocusView mFocusView, View focusView,
- FocusItemModle<TvModle> focusItem, int Postion, int row, int col,
- long id) {
- Intent intent = new Intent();
- Bundle bundle = new Bundle();
- if (focusItem != null && focusItem.getModle() != null) {
- bundle.putSerializable("TvModle", focusItem.getModle());
- }
- intent.putExtras(bundle);
- intent.setClass(FocusUIActivity.this, values[0]);
- startActivity(intent);
- }
最后运行 效果如下
这样就把音悦台的MV资源给解析出来并展现到我们自己的APP上,下一篇会继续结合本篇的逻辑,实现点击具体视频获取真实地址 播放网络视频功能,欢迎大家阅读,如需转载请标明出处 http://blog.csdn.net/sk719887916/article/details/40049137,欢迎交流分享。