突然想写一篇博客,于是就产生了这篇博客。很多地方都没有理解源码也没有点进去看,所以之后也会继续修改补全。如果对你有一点帮助,或者说你有神马想法或者困惑都可以留言


一直以来的习惯,拿到一个项目,我就会先去看清单文件,所以先分析一下清单文件吧。

<uses-permission android:name="android.permission.INTERNET" />   //这是申请网络的权限
<uses-permission android:name="android.permission.RECORD_AUDIO" />  //这是申请开发音频的权限

<uses-feature
    android:name="android.hardware.touchscreen"
    android:required="false" />           //因为电视一般不支持触屏,所以需要声明一下权限
<uses-feature
    android:name="android.software.leanback"
    android:required="true" />     //使用一些TV下面的控件时,需要的声明
 
<activity
    android:name=".MainActivity"
    android:banner="@drawable/app_icon_your_company"
    android:icon="@drawable/app_icon_your_company"
    android:label="@string/app_name"
    android:logo="@drawable/app_icon_your_company"
    android:screenOrientation="landscape">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />    
        <category android:name="android.intent.category.LEANBACK_LAUNCHER" />  //这个地方与手机端开发区别较大,这个主要是声明了这是一个TV项目,如果不加这个,那么运行在TV上时,是找不到这个应用的运行图标的
    </intent-filter>
</activity>

  然后我就打开了MainActivity,然后我发现里面竟然是空的。随后我就打开了MainActivity的资源文件。

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_browse_fragment"
    android:name="com.example.administrator.myfirst.MainFragment"  //这里是关键点,原来里面是引用了一个碎片。
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.administrator.myfirst.MainActivity"  
    tools:deviceIds="tv"
    tools:ignore="MergeRootFrame" />

 然后就可以打开MainFragment。里面有四个方法,我们一一来分析一下。

public void onActivityCreated(Bundle savedInstanceState) {
    Log.i(TAG, "onCreate");
    super.onActivityCreated(savedInstanceState);

    prepareBackgroundManager();

    setupUIElements();

    loadRows();

    setupEventListeners();
}
这里大家一看就明白这个方法的作用,初始化。
private void prepareBackgroundManager() {

    mBackgroundManager = BackgroundManager.getInstance(getActivity());
    mBackgroundManager.attach(getActivity().getWindow());
    mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
    mMetrics = new DisplayMetrics();
    getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
}
private void setupUIElements() {
    // setBadgeDrawable(getActivity().getResources().getDrawable(
    // R.drawable.videos_by_google_banner));
    setTitle(getString(R.string.browse_title)); // Badge, when set, takes precedent
    // over title
    setHeadersState(HEADERS_ENABLED);
    setHeadersTransitionOnBackEnabled(false); //这里是设置左边引导的显示与否。

    // set fastLane (or headers) background color
    setBrandColor(getResources().getColor(R.color.background_gradient_start));  //设置左边引导的背景色
    // set search icon color
    setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
}
这个方法主要作用是产生页面数据
 
private void loadRows() {
    List<Movie> list = MovieList.setupMovies();  //Movie一个实现了序列化的Bean。setupMovies()是产生movie数据的方法

    mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());  //页面数据的适配器
    CardPresenter cardPresenter = new CardPresenter();         //这个比较重要下面贴上源码

    int i;
    for (i = 0; i < NUM_ROWS; i++) {    

        if (i != 0) {
            Collections.shuffle(list);   //打乱list里的数据
        }
        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);  //里面要传一个Persenter类型的,Persenter里面有三个抽象方法,复写了Adapter
        for (int j = 0; j < NUM_COLS; j++) {
            listRowAdapter.add(list.get(j % 5));    //添加Movie,产生页面右边的15个数据
        }
        HeaderItem header = new HeaderItem(i, MovieList.MOVIE_CATEGORY[i]);  //产生左边的标题数据
        mRowsAdapter.add(new ListRow(header, listRowAdapter));   //listRowAdapter是页面右边的数据
                                                               // new ListRow(header, listRowAdapter)这里绑定左边主标题和右边子数据  }  
  HeaderItem gridHeader = new HeaderItem(i, "PREFERENCES");   
 GridItemPresenter mGridPresenter = new GridItemPresenter();  
  ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter); //里面传了一个Presenter 
gridRowAdapter.add(getResources().getString(R.string.grid_view));   
 gridRowAdapter.add(getString(R.string.error_fragment));   
 gridRowAdapter.add(getResources().getString(R.string.personal_settings));    
mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));  //看了这个应该很清晰了   
 setAdapter(mRowsAdapter); //最后将mRowsAdapter设置}
主要就是实现了每个控件的绑定,设置数据
public class CardPresenter extends Presenter {
    private static final String TAG = "CardPresenter";

    private static final int CARD_WIDTH = 313;
    private static final int CARD_HEIGHT = 176;
    private static int sSelectedBackgroundColor;
    private static int sDefaultBackgroundColor;
    private Drawable mDefaultCardImage;

    private static void updateCardBackgroundColor(ImageCardView view, boolean selected) {
        int color = selected ? sSelectedBackgroundColor : sDefaultBackgroundColor;
        // Both background colors should be set because the view's background is temporarily visible
        // during animations.
        view.setBackgroundColor(color);
        view.findViewById(R.id.info_field).setBackgroundColor(color);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent) {
        Log.d(TAG, "onCreateViewHolder");

        sDefaultBackgroundColor = parent.getResources().getColor(R.color.default_background);
        sSelectedBackgroundColor = parent.getResources().getColor(R.color.selected_background);
        /*
         * This template uses a default image in res/drawable, but the general case for Android TV
         * will require your resources in xhdpi. For more information, see
         * https://developer.android.com/training/tv/start/layouts.html#density-resources
         */
        mDefaultCardImage = parent.getResources().getDrawable(R.drawable.movie);

        ImageCardView cardView = new ImageCardView(parent.getContext()) {
            @Override
            public void setSelected(boolean selected) {
                updateCardBackgroundColor(this, selected);  //这句很关键,它实现了当选择改变的时候,选中效果的出现
                super.setSelected(selected);
            }
        };
        cardView.setFocusable(true);
        cardView.setFocusableInTouchMode(true);
        updateCardBackgroundColor(cardView, false);
        return new ViewHolder(cardView);
    }

    @Override
    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
        Movie movie = (Movie) item;
        ImageCardView cardView = (ImageCardView) viewHolder.view;

        Log.d(TAG, "onBindViewHolder");
        if (movie.getCardImageUrl() != null) {
            cardView.setTitleText(movie.getTitle());
            cardView.setContentText(movie.getStudio());
            cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT);
            Glide.with(viewHolder.view.getContext())
                    .load(movie.getCardImageUrl())
                    .centerCrop()
                    .error(mDefaultCardImage)
                    .into(cardView.getMainImageView());
        }
    }

    @Override
    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
        Log.d(TAG, "onUnbindViewHolder");
        ImageCardView cardView = (ImageCardView) viewHolder.view;
        // Remove references to images so that the garbage collector can free up memory
        cardView.setBadgeImage(null);
        cardView.setMainImage(null);
    }
}
这个方法设置了监听
private void setupEventListeners() {
    setOnSearchClickedListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            Toast.makeText(getActivity(), "Implement your own in-app search", Toast.LENGTH_LONG)
                    .show();
        }
    });

    setOnItemViewClickedListener(new ItemViewClickedListener());
    setOnItemViewSelectedListener(new ItemViewSelectedListener());
}
这次就先写到这了
Logo

智屏生态联盟致力于大屏生态发展,利用大屏快应用技术降低开发者开发、发布大屏应用门槛

更多推荐