美文网首页AndroidAndroid TVAndroid TV开发
[译]PicassoBackgroundManager - An

[译]PicassoBackgroundManager - An

作者: wenju_song | 来源:发表于2017-04-21 10:07 被阅读1053次

    版权声明:本文为博主原创翻译文章,转载请注明出处。

    推荐:
    欢迎关注我创建的Android TV 简书专题,会定期给大家分享一些AndroidTv相关的内容:
    http://www.jianshu.com/c/37efc6e9799b


    picassobackgroundmanager

    本篇目标
    实现背景图像更新功能。 应用程序没有背景的话显得很无聊,如果它有适当的背景,它变得非常好。
    设置背景其实很简单,本示例实现了根据选择的内容动态的去加载背景图。

    在实现背景更改之前,先开始介绍onItemSelected回调函数,以便在选择项目时拦截事件的通知。 接下来,我将展示简单的背景更改实现,然后使用picasso实现更好的性能。

    setOnItemViewSelectedListener 监听和onItemSelected回调

    当选择并单击itemview时,BrowseFragment支持设置侦听器。 当用户移动光标并更改项目的选择时,当前目标将被通知。
    为此,我们可以使用setOnItemViewSelectedListener(OnItemViewSelectedListener listener)函数。 在参数中,可以放置应该实现OnItemViewSelectedListener接口的监听器类,该接口也由leanback库提供。 然后,您可以实现onItemSelected回调函数,这是在选择项目时调用的函数。
    MainFragmet.java

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            Log.i(TAG, "onActivityCreated");
            super.onActivityCreated(savedInstanceState);
    
            setupUIElements();
    
            loadRows();
    
            setupEventListeners();
        }
        
        private void setupEventListeners() {
            setOnItemViewSelectedListener(new ItemViewSelectedListener());
        }
        
        private final class ItemViewSelectedListener implements OnItemViewSelectedListener {
            @Override
            public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, 
                                       RowPresenter.ViewHolder rowViewHolder, Row row) {
                // each time the item is selected, code inside here will be executed.
            }
        }
    

    我们将在下面继续实现背景改变功能。 在这里我创建SimpleBackgroundManager和PicassoBackgroundManager来处理背景图像(Android TV示例应用程序正在MainFragment.java中进行)。

    SimpleBackgroundManager

    官方开发者网站上有解释,请参阅Update the Background以供参考。
    我在下面写了一些测试代码。

    右键单击package name → New → class→ SimpleBackgroundManager

    SimpleBackgroundManager保留了BackgroundManager类的成员mBackgroundManager,它处理实际的背景更改。 BackgroundManager实例是一个可以通过BackgroundManager.getInstance()获得单例实例。

    package com.corochann.androidtvapptutorial;
    
    import android.app.Activity;
    import android.content.ContentResolver;
    import android.content.Context;
    import android.graphics.drawable.Drawable;
    import android.net.Uri;
    import android.support.v17.leanback.app.BackgroundManager;
    import android.util.DisplayMetrics;
    
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import java.net.URI;
    
    
    public class SimpleBackgroundManager {
    
        private static final String TAG = SimpleBackgroundManager.class.getSimpleName();
    
        private final int DEFAULT_BACKGROUND_RES_ID = R.drawable.default_background;
        private static Drawable mDefaultBackground;
    
        private Activity mActivity;
        private BackgroundManager mBackgroundManager;
    
        public SimpleBackgroundManager(Activity activity) {
            mActivity = activity;
            mDefaultBackground = activity.getDrawable(DEFAULT_BACKGROUND_RES_ID);
            mBackgroundManager = BackgroundManager.getInstance(activity);
            mBackgroundManager.attach(activity.getWindow());
            activity.getWindowManager().getDefaultDisplay().getMetrics(new DisplayMetrics());
        }
    
        public void updateBackground(Drawable drawable) {
            mBackgroundManager.setDrawable(drawable);
        }
    
        public void clearBackground() {
            mBackgroundManager.setDrawable(mDefaultBackground);
        }
    
    }
    

    首先,在构造函数中创建BackgroundManager的实例。 在更新背景之前必须附加到Window,这些初始化在构造函数中完成。

    updateBackground方法会改变背景,clearBackground方法会将背景更新为默认图像。 (添加了res / drawable / default_background.xml和更新的res / values / colors.xml。)

    这里MainFragment的修改很小。

    public class MainFragment extends BrowseFragment {
    
        ...
    
        private static SimpleBackgroundManager simpleBackgroundManager = null;
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
    
            ...
    
            simpleBackgroundManager = new SimpleBackgroundManager(getActivity());
        }
    
        private void setupEventListeners() {
            setOnItemViewSelectedListener(new ItemViewSelectedListener());
        }
    
        private final class ItemViewSelectedListener implements OnItemViewSelectedListener {
            @Override
            public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
                                       RowPresenter.ViewHolder rowViewHolder, Row row) {
                // each time the item is selected, code inside here will be executed.
                if (item instanceof String) { // GridItemPresenter row
                    simpleBackgroundManager.clearBackground();
                } else if (item instanceof Movie) { // CardPresenter row
                    simpleBackgroundManager.updateBackground(getActivity().getDrawable(R.drawable.movie));
                }
            }
        }
    

    编译并运行

    我们可以根据行的选择来检查背景是否更新。 当您返回到GridItemPresenter行时,“背景”也将恢复为默认值。


    background1

    Source code is on github.

    PicassoBackgroundManager

    我们来改进SimpleBackgroundManager的实现。 我们将会以下改进:
    1.延迟更新背景

    在以前的实现中,当用户移动光标时,主线程将始终尝试更新背景,并更改选择项目。 它很忙,可能会导致性能不佳。 下面我们将实现TimerTask等待一段时间从更新背景图像。

    2.使用Picasso library图像处理
    Picasso library是“Android的强大的图像下载和缓存库”。 我们将使用它更容易的图像资源处理。
    创建如下的PicassoBackgroundManager,实现如下:

    package com.corochann.androidtvapptutorial;
    
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.drawable.Drawable;
    import android.os.Handler;
    import android.os.Looper;
    import android.support.v17.leanback.app.BackgroundManager;
    import android.util.DisplayMetrics;
    import android.util.Log;
    
    import com.squareup.picasso.Picasso;
    import com.squareup.picasso.Target;
    
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.util.Timer;
    import java.util.TimerTask;
    
    
    public class PicassoBackgroundManager {
    
        private static final String TAG = PicassoBackgroundManager.class.getSimpleName();
    
        private static int BACKGROUND_UPDATE_DELAY = 500;
        private final int DEFAULT_BACKGROUND_RES_ID = R.drawable.default_background;
        private static Drawable mDefaultBackground;
        // Handler attached with main thread
        private final Handler mHandler = new Handler(Looper.getMainLooper());
    
        private Activity mActivity;
        private BackgroundManager mBackgroundManager = null;
        private DisplayMetrics mMetrics;
        private URI mBackgroundURI;
        private PicassoBackgroundManagerTarget mBackgroundTarget;
    
        Timer mBackgroundTimer; // null when no UpdateBackgroundTask is running.
    
        public PicassoBackgroundManager (Activity activity) {
            mActivity = activity;
            mDefaultBackground = activity.getDrawable(DEFAULT_BACKGROUND_RES_ID);
            mBackgroundManager = BackgroundManager.getInstance(activity);
            mBackgroundManager.attach(activity.getWindow());
            mBackgroundTarget = new PicassoBackgroundManagerTarget(mBackgroundManager);
            mMetrics = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
    
        }
    
        /**
         * if UpdateBackgroundTask is already running, cancel this task and start new task.
         */
        private void startBackgroundTimer() {
            if (mBackgroundTimer != null) {
                mBackgroundTimer.cancel();
            }
            mBackgroundTimer = new Timer();
            /* set delay time to reduce too much background image loading process */
            mBackgroundTimer.schedule(new UpdateBackgroundTask(), BACKGROUND_UPDATE_DELAY);
        }
    
    
        private class UpdateBackgroundTask extends TimerTask {
            @Override
            public void run() {
                /* Here is TimerTask thread, not UI thread */
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                         /* Here is main (UI) thread */
                        if (mBackgroundURI != null) {
                            updateBackground(mBackgroundURI);
                        }
                    }
                });
            }
        }
    
        public void updateBackgroundWithDelay(String url) {
            try {
                URI uri = new URI(url);
                updateBackgroundWithDelay(uri);
            } catch (URISyntaxException e) {
                /* skip updating background */
                Log.e(TAG, e.toString());
            }
        }
    
        /**
         * updateBackground with delay
         * delay time is measured in other Timer task thread.
         * @param uri
         */
        public void updateBackgroundWithDelay(URI uri) {
            mBackgroundURI = uri;
            startBackgroundTimer();
        }
    
        private void updateBackground(URI uri) {
            try {
                Picasso.with(mActivity)
                        .load(uri.toString())
                        .resize(mMetrics.widthPixels, mMetrics.heightPixels)
                        .centerCrop()
                        .error(mDefaultBackground)
                        .into(mBackgroundTarget);
            } catch (Exception e) {
                Log.e(TAG, e.toString());
            }
        }
    
        /**
         * Copied from AOSP sample code.
         * Inner class
         * Picasso target for updating default_background images
         */
        public class PicassoBackgroundManagerTarget implements Target {
            BackgroundManager mBackgroundManager;
    
            public PicassoBackgroundManagerTarget(BackgroundManager backgroundManager) {
                this.mBackgroundManager = backgroundManager;
            }
    
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
                this.mBackgroundManager.setBitmap(bitmap);
            }
    
            @Override
            public void onBitmapFailed(Drawable drawable) {
                this.mBackgroundManager.setDrawable(drawable);
            }
    
            @Override
            public void onPrepareLoad(Drawable drawable) {
                // Do nothing, default_background manager has its own transitions
            }
    
            @Override
            public boolean equals(Object o) {
                if (this == o)
                    return true;
                if (o == null || getClass() != o.getClass())
                    return false;
    
                PicassoBackgroundManagerTarget that = (PicassoBackgroundManagerTarget) o;
    
                if (!mBackgroundManager.equals(that.mBackgroundManager))
                    return false;
    
                return true;
            }
    
            @Override
            public int hashCode() {
                return mBackgroundManager.hashCode();
            }
        }
    
        
    }
    

    接下来,我们将把MainFragment.java中的SimpleBackgroundManager替换为PicassoBackgroundManager

    public class MainFragment extends BrowseFragment {
    
        ...
    
        private static PicassoBackgroundManager picassoBackgroundManager = null;
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
    
            ...
    
            picassoBackgroundManager = new PicassoBackgroundManager(getActivity());
        }
    
        private void setupEventListeners() {
            setOnItemViewSelectedListener(new ItemViewSelectedListener());
        }
    
        private final class ItemViewSelectedListener implements OnItemViewSelectedListener {
            @Override
            public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
                                       RowPresenter.ViewHolder rowViewHolder, Row row) {
                if (item instanceof String) {                    // GridItemPresenter
                    picassoBackgroundManager.updateBackgroundWithDelay("http://heimkehrend.raindrop.jp/kl-hacker/wp-content/uploads/2014/10/RIMG0656.jpg");
                } else if (item instanceof Movie) {              // CardPresenter
                    picassoBackgroundManager.updateBackgroundWithDelay(((Movie) item).getCardImageUrl());
                }
            }
        }
    
        ...
    
        private void loadRows() {
            mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
    
            ...
    
            for(int i=0; i<10; i++) {
                Movie movie = new Movie();
                if(i%3 == 0) {
                    movie.setCardImageUrl("http://heimkehrend.raindrop.jp/kl-hacker/wp-content/uploads/2014/08/DSC02580.jpg");
                } else if (i%3 == 1) {
                    movie.setCardImageUrl("http://heimkehrend.raindrop.jp/kl-hacker/wp-content/uploads/2014/08/DSC02630.jpg");
                } else {
                    movie.setCardImageUrl("http://heimkehrend.raindrop.jp/kl-hacker/wp-content/uploads/2014/08/DSC02529.jpg");
                }
                movie.setTitle("title" + i);
                movie.setStudio("studio" + i);
                cardRowAdapter.add(movie);
            }
    

    编译后运行

    由于定时器任务,我们可以在500 ms后检查后台是否更新。 而我们通过使用Picasso从网站获取背景图像。

    picassobackgroundmanager

    源代码在github上。

    到现在为止,我们无法单击item/card。 下一章,DetailsOverviewRowPresenter和FullWidthDetailsOverviewRowPresenter - Android TV应用程序的教程5,是实现一个onClickListener并通过DetailFragment显示内容详细信息。
    关注微信公众号,定期为你推荐移动开发相关文章。

    songwenju

    相关文章

      网友评论

      • 1699eef9a3fc:刚接触AndroidTV 非常感谢楼主的分享 还有就是想问一下ImageCardView 里面的标题和内容文字大小怎么设置

      本文标题:[译]PicassoBackgroundManager - An

      本文链接:https://www.haomeiwen.com/subject/umzjattx.html