我是Android开发的新手,我正在使用Onur Cinar的“Android Apps with Eclipse”一书来开始。
我已经完成了第6章开发了一个MoviePlayer应用程序(源代码:http://www.apress.com/9781430244349),但是当我在手机上运行应用程序时,我无法看到列出的电影的任何缩略图。当我使用手机录制新电影时,新电影将添加到电影列表中,默认的绿色Android图标作为缩略图,原始电影仍然没有缩略图标。
我的代码似乎与给定源代码的代码相匹配。书中给出的代码是否有问题,或者这是预期的行为?如果是后者,在什么情况下(非默认)缩略图图标会出现在电影列表中?
Movie.java:
package com.apress.movieplayer;
import android.database.Cursor;
import android.provider.MediaStore;
/**
* Movie file meta data.
*
* @author Josh
*/
public class Movie
{
/** Movie title */
private final String title;
/** Movie file */
private final String moviePath;
/** MIME type */
private final String mimeType;
/** Movie duration in ms */
private final long duration;
/** Thumbnail file */
private final String thumbnailPath;
/**
* Constructor.
*
* @param mediaCursor media cursor.
* @param thumbnailCursor thumbnail cursor.
*/
public Movie(Cursor mediaCursor, Cursor thumbnailCursor)
{
title = mediaCursor.getString(mediaCursor.getColumnIndexOrThrow(
MediaStore.Video.Media.TITLE));
moviePath = mediaCursor.getString(mediaCursor.getColumnIndex(
MediaStore.Video.Media.DATA));
mimeType = mediaCursor.getString(mediaCursor.getColumnIndex(
MediaStore.Video.Media.MIME_TYPE));
duration = mediaCursor.getLong(mediaCursor.getColumnIndex(
MediaStore.Video.Media.DURATION));
if ( (thumbnailCursor != null) && thumbnailCursor.moveToFirst() )
{
thumbnailPath = thumbnailCursor.getString(
thumbnailCursor.getColumnIndex(
MediaStore.Video.Thumbnails.DATA));
}
else
{
thumbnailPath = null;
}
}
/**
* Get the movie title.
*
* @return movie title.
*/
public String getTitle() {
return title;
}
/**
* Get the movie path.
*
* @return movie path.
*/
public String getMoviePath() {
return moviePath;
}
/**
* Get the MIME type.
*
* @return MIME type.
*/
public String getMimeType() {
return mimeType;
}
/**
* Get the movie duration.
*
* @return movie duration.
*/
public long getDuration() {
return duration;
}
/**
* Get the thumbnail path.
*
* @return thumbnail path.
*/
public String getThumbnailPath() {
return thumbnailPath;
}
/*
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return "Movie [title=" + title + ", moviePath=" + moviePath
+ ", mimeType=" + mimeType + ", duration=" + duration
+ ", thumbnailPath=" + thumbnailPath + "]";
}
}
MovieListAdapter.java:
package com.apress.movieplayer;
import java.util.ArrayList;
import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Movie list view adapter.
*
* @author Josh
*/
public class MovieListAdapter extends BaseAdapter
{
/** Context instance */
private final Context context;
/** Movie list */
private final ArrayList<Movie> movieList;
/**
* Constructor.
*
* @param context context instance.
* @param movieList movie list.
*/
public MovieListAdapter(Context context, ArrayList<Movie> movieList)
{
this.context = context;
this.movieList = movieList;
}
/**
* Gets the number of elements in movie list.
*
* @see BaseAdapter#getCount()
*/
public int getCount() {
return movieList.size();
}
/**
* Gets the movie item at given position.
*
* @param position item position.
* @see BaseAdapter#getItem(int)
*/
public Object getItem(int position) {
return movieList.get(position);
}
/**
* Gets the movie id at given position.
*
* @param position item position.
* @return movie id.
* @see BaseAdapter#getItemId(int)
*/
public long getItemId(int position) {
return position;
}
/**
* Gets the item view for given position.
*
* @param position item position.
* @param convertView existing view to use.
* @param parent parent view to use.
*/
public View getView(int position, View convertView, ViewGroup parent) {
// check if convert view exists or inflate the layout
if (convertView == null)
{
LayoutInflater layoutInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.movie_item, null);
}
// Get the movie at given position
Movie movie = (Movie) getItem(position);
// Set thumbnail
ImageView thumbnail = (ImageView) convertView.findViewById(
R.id.thumbnail);
if (movie.getThumbnailPath() != null)
{
thumbnail.setImageURI(Uri.parse(movie.getThumbnailPath()));
}
else
{
thumbnail.setImageResource(R.drawable.ic_launcher);
}
// Set title
TextView title = (TextView) convertView.findViewById(R.id.title);
title.setText(movie.getTitle());
// Set duration
TextView duration = (TextView) convertView.findViewById(R.id.duration);
duration.setText(getDurationAsString(movie.getDuration()));
return convertView;
}
private static String getDurationAsString(long duration)
{
// Calculate milliseconds
long milliseconds = duration % 1000;
long seconds = duration / 1000;
// Calculate seconds
long minutes = seconds / 60;
seconds %= 60;
// Calculate hours and minutes
long hours = minutes / 60;
minutes %= 60;
// Build the duration string
String durationString = String.format("%1$02d:%2$02d:%3$02d.%4$03d",
hours, minutes, seconds, milliseconds);
return durationString;
}
}
MoviePlayerActivity.java:
package com.apress.movieplayer;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
//import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
/**
* Movie Player.
*
* @author Josh
*
*/
public class MoviePlayerActivity extends Activity implements OnItemClickListener
{
/** Log tag. */
private static final String LOG_TAG = "MoviePlayer";
/**
* On create lifecycle method.
*
* @param savedInstanceState saved state.
* @see Activity#onCreate(Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_player);
ArrayList<Movie> movieList = new ArrayList<Movie>();
// Media columns to query
String[] mediaColumns = {
MediaStore.Video.Media._ID,
MediaStore.Video.Media.TITLE,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.DATA,
MediaStore.Video.Media.MIME_TYPE };
// Thumbnail columns to query
String[] thumbnailColumns = { MediaStore.Video.Thumbnails.DATA };
// Query external movie content for selected media columns
Cursor mediaCursor = getContentResolver().query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
mediaColumns, null, null, null);
/*managedQuery(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI, mediaColumns,
null, null, null);*/
// Loop through media results
if ( (mediaCursor != null) && mediaCursor.moveToFirst() )
{
do
{
// Get the video id
int id = mediaCursor.getInt(mediaCursor
.getColumnIndex(MediaStore.Video.Media._ID));
// Get the thumbnail associated with the video
Cursor thumbnailCursor = getContentResolver().query(
MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI,
thumbnailColumns, MediaStore.Video.Thumbnails.VIDEO_ID
+ "=" + id, null, null);
/*managedQuery(
MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI,
thumbnailColumns, MediaStore.Video.Thumbnails.VIDEO_ID
+ "=" + id, null, null);*/
// New movie object from the data
Movie movie = new Movie(mediaCursor, thumbnailCursor);
Log.d(LOG_TAG, movie.toString());
// Add to movie list
movieList.add(movie);
}
while (mediaCursor.moveToNext());
}
// Define movie list adapter
MovieListAdapter movieListAdapter = new MovieListAdapter(this,
movieList);
// Set list view adapter to movie list adapter
ListView movieListView = (ListView) findViewById(R.id.movieListView);
movieListView.setAdapter(movieListAdapter);
// Set item click listener
movieListView.setOnItemClickListener(this);
}
@Override
/*public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_movie_player, menu);
return true;
}*/
/**
* On item click listener.
*/
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
// Gets the selected movie
Movie movie = (Movie) parent.getAdapter().getItem(position);
// Plays the selected movie
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(movie.getMoviePath()), movie.getMimeType());
startActivity(intent);
}
}
activity_movie_player.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/movieListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</ListView>
</LinearLayout>
movie_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:contentDescription="@string/thumbnail_description"
android:id="@+id/thumbnail"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginRight="16dp"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/thumbnail"
android:layout_toRightOf="@+id/thumbnail"
android:text="@string/large_text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/title"
android:layout_below="@+id/title"
android:text="@string/small_text"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
答案 0 :(得分:0)
鉴于代码,似乎这是Android OS的正常功能。一旦视频被其他视频播放应用程序打开,似乎缩略图是在这些更复杂的程序中生成的,并且可供其他应用程序(包括此演示电影播放器应用程序)使用。
如果有人可以详细说明这实际上是如何在“幕后”工作的话,我会很高兴,因为我的分析有些黑盒子。