[译]PicassoBackgroundManager - An
版权声明:本文为博主原创翻译文章,转载请注明出处。
推荐:
欢迎关注我创建的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显示内容详细信息。
关注微信公众号,定期为你推荐移动开发相关文章。