使用SurfaceView播放视频,其实很简单,但是经常会碰见有声音没图像的问题.
其实使用SurfaceView播放视频只需要主要下面几个地方就可以了
1. surfaceChanged也就是Suface是否创建成功
2. onPrepared 也就是MideoPlayer是否加载并准备完成
3. surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
类型必须是SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS
package VideoTest.Test; import java.io.FileDescriptor; import android.app.Activity; import android.content.res.AssetFileDescriptor; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnBufferingUpdateListener; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnPreparedListener; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; public class VideoTest extends Activity implements SurfaceHolder.Callback, OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener{ private SurfaceView surfaceView; private SurfaceHolder surfaceHolder; private MediaPlayer mediaPlayer; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.surfaceView = new SurfaceView(this); this.surfaceHolder = this.surfaceView.getHolder(); this.surfaceHolder.addCallback(this); //类型必须设置成SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS this.surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); setContentView(this.surfaceView); } @Override public void onDestroy() { super.onDestroy(); if (this.mediaPlayer != null) { this.mediaPlayer.release(); this.mediaPlayer = null; } } public void PlayVideo(){ try { //视频文件放在 assert中 AssetFileDescriptor aFD = this.getAssets().openFd("welcome.3gp"); FileDescriptor fileDescriptor = aFD.getFileDescriptor(); this.mediaPlayer = new MediaPlayer(); this.mediaPlayer.setDataSource(fileDescriptor, aFD.getStartOffset(), aFD.getLength()); aFD.close(); //视频放在SDCard中 //File sdFile = Environment.getExternalStorageDirectory(); //this.mediaPlayer = new MediaPlayer(); //this.mediaPlayer.setDataSource(sdFile.getAbsoluteFile() + File.separator + "welcome.3gp"); //视频放在res中 //this.mediaPlayer = MediaPlayer.create(this, R.raw.welcome); //网上的视频,没有测试 //this.mediaPlayer // .setDataSource("http://xy2.163.com/download/down/wukong.mp3"); this.mediaPlayer.setDisplay(this.surfaceHolder); this.mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); //准备完成后才可以播放,另外如果文件特别大或者从网上获得的资源 //会在这里等待时间过长,造成堵塞,这样的话就得用 //this.mediaPlayer.prepareAsync(),然后监听是否准备完毕在开始 this.mediaPlayer.prepare(); this.mediaPlayer.start(); } catch (Exception e) { // TODO: handle exception } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { //SurfaceCreated 创建成功才可以播放视频 PlayVideo(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { } //@Override public void onBufferingUpdate(MediaPlayer mp, int percent) { // TODO Auto-generated method stub } //@Override public void onCompletion(MediaPlayer mp) { // TODO Auto-generated method stub } //@Override public void onPrepared(MediaPlayer mp) { //MediaPlayer加载准备完毕才能开始播放 //mp.start(); } }
但是,对于一些人可能会产生另一个问题就是
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
在设置成SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS类型后,无法画图了
SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS的意思是创建一个"PUSH"surface,这个surface没有自己的缓冲区,没有自己的缓冲Buffer.
这里我也还没有发现如何去自行 获取、修改、重绘图像。
继续跟踪!!!
我該怎麼做 ??
我試過用 animation , 外面再加個 layer , matrix
都沒有效果
不知道版主是否有建議
謝謝
tocute520@gmail.com
创建AVD 2.0时报错:could not write to 'sdcard.img', aborting...
即在创建模拟器时SD卡创建失败,原因竟然是磁盘空间不够了
发现是 Symantec这个软件在 Application Data\Symantec\Symantec Endpoint Protection\xfer路径下生成大量的东西,真郁闷,现在还没删掉,挨千刀的赛门铁克
用GridView实现Gallery的效果(转)
在实现横向的类似Gallery的效果中做了实现Gallery的尝试,但是效果不好。使用的是TableLayout,出现了横向拖动图片的时候,因为有倾斜(轻微的竖向拖动),会整个列表竖向滚动。其实这个问题可以将TableRow中条目设置为clickable来解决。但是效果依然不好。
这次尝试通过GridView来解决问题,效果很好,见截图:
基本思路是:
- 每个可选的图,包括文字部分,是GridView中的一个条目;
- 一个GridView条目是相对布局(RelativeLayout),里面包含一个图片(ImageView)和一个文字(TextView);
- 关键点是GridView如何保持横向,默认的情况下会折行的,首先要用一个HorizontalScrollView提供横向滚动容器,然后内部放置一个FrameLayout,如果不放置FrameLayout布局,直接放入下面的布局或者视图,GridView将会变成单列纵向滚动,在FrameLayout布局中加入横向的LinearLayout布局,要设置它的layout_width,要足够大,这样在其中加入GridView就能横向排列了。
首先看一下GridView中条目的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingBottom="10.0dip" android:layout_width="90.0dip"
android:layout_height="140.0dip">
<ImageView android:id="@+id/ItemImage" android:layout_width="80.0dip"
android:layout_height="108.0dip" android:layout_marginLeft="10.0dip"
android:layout_centerHorizontal="true">
</ImageView>
<TextView android:layout_below="@+id/ItemImage" android:id="@+id/ItemText"
android:ellipsize="end" android:layout_width="80.0dip"
android:layout_height="26.0dip" android:layout_marginTop="5.0dip"
android:singleLine="true" android:layout_centerHorizontal="true">
</TextView>
</RelativeLayout>
这里使用了相对布局的特性,android:layout_below,表示TextView在ImageView下面。这里的图都是用的res/drawable目录下的静态图形文件,正式情况下,应该是从网络获取,可参见用Java concurrent编写异步加载图片功能的原型实现,二者结合可用于正式生产环境。
ListView的Header使用了自定义视图,更简单的示例可参见为ListView增加Header。表头(ListView Header)的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="200dp">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="最近访问人物" />
<HorizontalScrollView android:layout_width="fill_parent"
android:layout_height="160dp">
<FrameLayout android:layout_width="fill_parent"
android:layout_height="match_parent">
<LinearLayout android:layout_width="1100dp"
android:layout_height="match_parent" android:orientation="horizontal">
<GridView android:id="@+id/grid" android:layout_width="fill_parent"
android:gravity="center" android:layout_height="fill_parent"
android:horizontalSpacing="1.0dip" android:verticalSpacing="1.0dip"
android:stretchMode="spacingWidthUniform" android:numColumns="auto_fit"
android:columnWidth="80dip">
</GridView>
</LinearLayout>
</FrameLayout>
</HorizontalScrollView>
</LinearLayout>
这是比较关键的布局文件,GridView能实现横向滚动主要靠它了。其中:
<LinearLayout android:layout_width="1100dp"
我是写死了1100dp,正式使用的时候,因为图片都可能是动态从服务器上获取的,可以根据数量以及图片的宽度,空白边动态计算这个长度。
GridView和ListView类似,都需要ViewAdapter来适配数据和视图。
见Activity的源代码:
package com.easymorse.grid.demo;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class GridDemoActivity extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LayoutInflater layoutInflater = (LayoutInflater) this
.getSystemService("layout_inflater");
View headerView=layoutInflater.inflate(R.layout.list_header, null);
setGridView(headerView);
ListView listView=(ListView) this.findViewById(android.R.id.list);
listView.addHeaderView(headerView);
listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,new String[]{"隋","唐","宋","元","明","清"}));
}
private void setGridView(View view) {
GridView gridView = (GridView) view.findViewById(R.id.grid);
gridView.setNumColumns(10);
ArrayList<HashMap<String, Object>> items = new ArrayList<HashMap<String, Object>>();
for (int i = 0; i < 10; i++) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("ItemImage", R.drawable.k);
map.put("ItemText", "清.康熙" + "(" + i + ")");
items.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(this, items, R.layout.item,
new String[] { "ItemImage", "ItemText" }, new int[] {
R.id.ItemImage, R.id.ItemText });
gridView.setAdapter(adapter);
}
}
全部源代码:
http://easymorse.googlecode.com/svn/tags/grid.demo-0.1.0/