您好我创建了一个列表视图,在我夸大了四个布局中,我的数据集是图像,文本,音频和视频。所以我相应地给布局充气。一旦数据来自Api,图像被缓存,音频视频和文本分别存储在文件夹和sqlite中。但是当我第二次打开listview随机显示数据或有时无序时。甚至有时候没有显示整个数据。这是我的适配器代码。
public class ListViewAdapter extends BaseAdapter {
ArrayList<ListModel> myList = new ArrayList<ListModel>();
LayoutInflater inflater;
Context context;
int flag = 0;
private static final int TYPE_ITEM1 = 1;
private static final int TYPE_ITEM2 = 2;
private static final int TYPE_ITEM3 = 3;
private static final int TYPE_ITEM4 = 4;
private String url;
private String vPath;
private MediaPlayer mp;
public ListViewAdapter(Context context, ArrayList<ListModel> myList) {
this.myList = myList;
this.context = context;
inflater = LayoutInflater.from(this.context);
}
int type;
@Override
public int getItemViewType(int position) {
ListModel listModel = myList.get(position);
String data = listModel.getType();
/* if (data.equals("Text")) {
return type1;
} else if (data.equals("Image")) {
return type2;
}return 0;*/
if (data.equals("Text")) {
type = TYPE_ITEM1;
} else if (data.equals("Image")) {
type = TYPE_ITEM2;
} else if (data.equals("Audio")) {
type = TYPE_ITEM3;
}else if(data.contains("Video")){
type=TYPE_ITEM4;
}
return type;
}
@Override
public int getViewTypeCount() {
return myList.size() + 1;
}
@Override
public int getCount() {
return myList.size();
}
@Override
public ListModel getItem(int position) {
// return myList.get(position);
if (position >= myList.size()) {
return null;
}
return myList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View v, ViewGroup parent) {
ViewHolder holder = null;
TextView textView = null;
ImageView imageView = null;
VideoView vPlayer = null;
Button pause = null;
Button play = null;
int type = getItemViewType(position);
System.out.println("getView " + position + " " + v + " type = " + type);
if (v == null) {
holder = new ViewHolder();
if (type == TYPE_ITEM1) {
v = inflater.inflate(R.layout.list_text, null);
textView = (TextView) v.findViewById(R.id.text);
} else if (type == TYPE_ITEM2) {
v = inflater.inflate(R.layout.list_image, null);
imageView = (ImageView) v.findViewById(R.id.imgView);
} else if (type == TYPE_ITEM3) {
v = inflater.inflate(R.layout.list_audio, null);
play = (Button) v.findViewById(R.id.btn_play);
pause = (Button) v.findViewById(R.id.stop);
} else if (type == TYPE_ITEM4) {
v = inflater.inflate(R.layout.list_video, null);
vPlayer = (VideoView) v.findViewById(R.id.video_player);
}
holder.textView = textView;
holder.videoPlayer = vPlayer;
holder.imageView = imageView;
holder.play = play;
holder.stop = pause;
v.setTag(holder);
} else {
holder = (ViewHolder) v.getTag();
}
ListModel model = myList.get(position);
if (holder.play != null) {
holder.play.setId(position);
}if (holder.videoPlayer!=null){
holder.videoPlayer.setId(position);
}if (holder.stop!=null){
holder.stop.setId(position);
}
String datatype = model.getType();
if (datatype.equals("Text")) {
holder.textView.setText(model.getData());
} else if (datatype.equals("Image")) {
UrlImageViewHelper.setUrlDrawable(holder.imageView, model.getData());
} else if (datatype.equals("Audio")) {
url = model.getData();
}else if (datatype.equals("Video")){
vPath=model.getData();
}
if (holder.play != null) {
holder.play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int i = view.getId();
ListModel model = myList.get(i);
String audioUri = model.getData();
new PlayMusicFromPath().execute(audioUri);
}
});
if (holder.stop!=null){
holder.stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});}
if (holder.videoPlayer!=null) {
final ViewHolder finalHolder = holder;
holder.videoPlayer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int videoId = view.getId();
ListModel model1 = myList.get(videoId);
String videoUrl = model1.getData();
finalHolder.videoPlayer.setVideoPath(videoUrl);
}
});
}
}
return v;
}
public static class ViewHolder {
public TextView textView;
public ImageView imageView;
public Button play, stop;
public VideoView videoPlayer;
}
public void audioPlayer(String fileName) {
//set up MediaPlayer
mp = new MediaPlayer();
try {
mp.setDataSource(fileName);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
mp.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mp.start();
}
class PlayMusicFromPath extends AsyncTask<String, String, String> {
// Show Progress bar before downloading Music
@Override
protected void onPreExecute() {
super.onPreExecute();
// Shows Progress Bar Dialog and then call doInBackground method
}
// Download Music File from Internet
@Override
protected String doInBackground(String... f_url) {
audioPlayer(f_url[0]);
return null;
}
// Once Music File is downloaded
@Override
protected void onPostExecute(String file_url) {
System.out.print(file_url);
}
}
意见如下
list_Video包含一个视频视图
list_audio包含两个按钮播放和暂停。
list_text包含一个textView
和list_image包含一个imageview
Logcat
是
addInArray been called, this = android.widget.ListView{443bacd0 VFED.VC. .F....ID 0,0-540,838 #7f0a006d app:id/listview}call stack =
java.lang.Throwable: addInArray
at android.view.ViewGroup.addInArray(ViewGroup.java:3786)
at android.view.ViewGroup.addViewInner(ViewGroup.java:3740)
at android.view.ViewGroup.addViewInLayout(ViewGroup.java:3687)
at android.widget.ListView.setupChild(ListView.java:1862)
at android.widget.ListView.makeAndAddView(ListView.java:1815)
at android.widget.ListView.fillDown(ListView.java:698)
at android.widget.ListView.fillFromTop(ListView.java:759)
at android.widget.ListView.layoutChildren(ListView.java:1631)
at android.widget.AbsListView.onLayout(AbsListView.java:2150)
at android.view.View.layout(View.java:15131)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1877)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1653)
at android.view.View.layout(View.java:15131)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15131)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.support.v7.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:493)
at android.view.View.layout(View.java:15131)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15131)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1742)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1651)
at android.view.View.layout(View.java:15131)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15131)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2323)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2029)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1192)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6231)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788)
at android.view.Choreographer.doCallbacks(Choreographer.java:591)
at android.view.Choreographer.doFrame(Choreographer.java:560)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
我也看到这些线条..
myprojectname while﹕ A105 to many
答案 0 :(得分:1)
在视图类型计数中,您需要提供不同类型的视图计数而不是列表计数。在您的情况下,它应该是四(文本,图像,音频和视频)
@Override
public int getViewTypeCount() {
return 4;
}
答案 1 :(得分:0)
这是列表视图的常见问题。 首先要解释发生了什么。 当您的列表视图滚动时,它将尝试重用视图,而不是创建一个全新的视图。 如果位置1处的项目是图像,并且列表重新使用位置5处的视图,但位置5是视频数据,因此如果您不隐藏图像视图,则图像视图和视频视图都将显示。它似乎是随机的,但编程中的任何东西都是随机的,除非你按照这种方式编程。
这是我的建议。要使其与您所需的一致,您需要将视图持有者中的所有其他视图显式设置为visibility="gone"
,但该项目位置所需的视图除外。
holder.textView.setVisibility(View.GONE);
holder.imageView.setVisibility(View.GONE);
holder.vPlayer.setVisibility(View.GONE);
holder.play.setVisibility(View.GONE);
holder.pause.setVisibility(View.GONE);
if (datatype.equals("Text")) {
holder.textView.setText(model.getData());
holder.textView.setVisibility(View.VISIBLE);
} else if (datatype.equals("Image")) {
UrlImageViewHelper.setUrlDrawable(holder.imageView, model.getData());
holder.imageView.setVisibility(View.VISIBLE);
} else if (datatype.equals("Audio")) {
url = model.getData();
holder.play.setVisibility(View.VISIBLE);
holder.pause.setVisibility(View.VISIBLE);
}else if (datatype.equals("Video")){
vPath=model.getData();
holder.vPlayer.setVisibility(View.VISIBLE);
}
更好的解决方案是为每个视图使用回收站视图和不同的视图持有者。
以下是我的一个回收适配器的示例。你可以阅读它们here.
public class ProgramRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
/**
This is an abstract class that all of my viewholders inherit from.
This is a contract telling me that any subclasses that inherit from this
base class are required to write their own `public void bind(int position,
Program program);` method.
*/
abstract class ProgramBaseViewHolder extends RecyclerView.ViewHolder {
public ProgramBaseViewHolder(View itemView) {
super(itemView);
}
public abstract void bindDataToView(int position, Program program);
}
@Bind
和Butterknife.bind是名为Butterknife的视图绑定库的一部分。 “绑定”的使用等同于您的findViewById()
来电。
/**
This is the Airtime view that holds airtimes. It is a view holder that
inherits from my base view holder and implements its own version if bind.
*/
class AirtimeViewHolder extends ProgramBaseViewHolder {
@Bind(R.id.program_airtimes)
TextView mProgramAirtimes;
static final int viewType = 0;
public AirtimeViewHolder(View itemView) {
super(itemView);
/**This call to butterknife can be replaced with an
itemView.findViewById(R.id.yourview) */
ButterKnife.bind(this, itemView);
}
//This is where you set your text and hide or show your views.
@Override
public void bindDataToView(int position, Program program) {
List<Airtime> airtimes = program.getAirtimes();
if (!airtimes.isEmpty()) {
mProgramAirtimes.setText(Utils.getFriendlyAirtimes(airtimes));
} else {
mProgramAirtimes.setText(
Utils.getFriendlyAirTime(program.getAirtime()));
}
}
}
/**
This is the Description view that holds descriptions. It is a view holder
that inherits from my base view holder and implements its own version if
bind.
*/
class DescriptionViewHolder extends ProgramBaseViewHolder {
@Bind(R.id.description_card_layout)
TextView mProgramDescription;
static final int viewType = 1;
public DescriptionViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
@Override
public void bindDataToView(int position, Program program) {
mProgramDescription.setText(Html.fromHtml(program.getFullDescription()));
}
}
//This is another type of view with another different type of layout.
class HostsViewHolder extends ProgramBaseViewHolder {
@Bind(R.id.card_view_host_name)
TextView mProgramHostName;
static final int viewType = 2;
public HostsViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
@Override
public void bindDataToView(int position, Program program) {
mProgramHostName.setText(program.getHosts().get(position - 2).getDisplayName());
}
}
//Again another type of view extending my base view.
class CategoriesViewHolder extends ProgramBaseViewHolder {
@Bind(R.id.program_categories)
TextView mProgramCategories;
static final int viewType = 42;
public CategoriesViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
@Override
public void bindDataToView(int position, Program program) {
List<Category> categoryList = program.getCategories();
StringBuilder stringBuilder = new StringBuilder();
for (Category category : categoryList) {
stringBuilder.append(category.getTitle())
.append(" ");
}
mProgramCategories.setText(stringBuilder.toString());
}
}
//This is where the normal looking recycler view code comes in.
private Context mContext;
private LayoutInflater mInflater;
private Program mProgramData;
private int mNextProgramId;
public ProgramRecyclerAdapter(Context context) {
mContext = context;
mInflater = LayoutInflater.from(mContext);
}
在您的情况下,您可以通过查看数据来确定视图类型。我将我的视图类型基于位置和一些数据。
/**This method is where I am determining what view type each item in my list
will be. I wanted a single airtimes view followed by a single description
view and then X amount of hosts views and a single category view. I return
position in the third else if because the position helps me determine which
host name to display in the bindDataToViews call of the HostViewHolder.*/
@Override
public int getItemViewType(int position) {
if (position == AirtimeViewHolder.viewType) {
return AirtimeViewHolder.viewType;
} else if (position == DescriptionViewHolder.viewType) {
return DescriptionViewHolder.viewType;
} else if (position > DescriptionViewHolder.viewType
&& position <= DescriptionViewHolder.viewType + getHostsNum()) {
return position;
} else {
return CategoriesViewHolder.viewType;
}
}
//This method figures out how many hosts will be displayed
private int getHostsNum() {
if (mProgramData != null) {
return mProgramData.getHosts().size();
}
return 0;
}
// This method determines if I will show a category view or not.
private int getCategoriesNum() {
if (mProgramData != null && mProgramData.getCategories().size() > 0) {
return 1;
}
return 0;
}
/**This returns haw many items will be in the list. 1 Airtime view, 1
Description view, x amount of Host views and 0 or 1 category views */
@Override
public int getItemCount() {
return 2 + getHostsNum() + getCategoriesNum();
}
/** This returns the appropriate View holder for the requested view type that
was set by getItemViewType(). I pass the inflated parent view and the data.
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == AirtimeViewHolder.viewType) {
return new AirtimeViewHolder(mInflater.inflate(R.layout.airtime_card_layout, parent, false));
} else if (viewType == DescriptionViewHolder.viewType) {
return new DescriptionViewHolder(mInflater.inflate(R.layout.description_card_layout, parent, false));
} else if (viewType > DescriptionViewHolder.viewType
&& viewType <= DescriptionViewHolder.viewType + getHostsNum()) {
return new HostsViewHolder(mInflater.inflate(R.layout.hosts_card_layout, parent, false));
} else
return new CategoriesViewHolder(mInflater.inflate(R.layout.categories_card_layout, parent, false));
}
/*This method is what ties everything together. After I ensure that the data
is not null I call bindDataToView on a ProgramBaseViewHolder. Depending on
which type of subclass it is will determine which overridden bindData code to
use. */
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ProgramBaseViewHolder baseViewHolder = (ProgramBaseViewHolder) holder;
if (mProgramData != null) {
baseViewHolder.bindDataToView(position, mProgramData);
}
}
//This is used to set the data for this program
public void setProgramData(Program program) {
mProgramData = program;
}
public Program getProgramData() {
return mProgramData;
}
public boolean isEmpty() {
return mProgramData == null;
}
}
这是Airtime布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/airtimes_label"
android:textSize="18dp"
android:textStyle="bold"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/program_airtimes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
</LinearLayout>
这是我的主机布局。你会注意到我没有在这里使用大多数视图,因为这是一个正在进行的应用程序。
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/host_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin"
card_view:cardBackgroundColor="@color/white"
card_view:cardCornerRadius="2dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp" />
<ImageView
android:id="@+id/host_image"
android:layout_width="112dp"
android:layout_height="112dp"
android:layout_alignParentLeft="true"
android:visibility="gone"
android:layout_centerVertical="true"
android:layout_marginRight="8dp" />
<LinearLayout
android:id="@+id/details"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/host_image"
android:orientation="vertical">
<TextView
android:id="@+id/card_view_host_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_margin="16dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:layout_gravity="left" />
<TextView
android:id="@+id/card_view_hosts_programs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:textStyle="bold"
android:textSize="12sp"
android:layout_marginBottom="16dp"
android:layout_gravity="left"/>
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>