我的Listview似乎两次显示我的列表项目,对于我的生活,我无法找到问题所在。我已经用推荐的 artistsAlbum.clear()(artistsAlbum是一个ArrayList)替换了我的代码中的语句。我甚至用“ artistsAlbum = new ArrayList()”这句话取代了artistAlbum.clear(),但它有效,但由于显而易见的原因,我不相信这是一个解决方案,因为我每次重新显示Listview时都会创建更多引用。 任何人都可以提供帮助。
MainActivity:
package com.example.richard.webapitest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import com.example.richard.webapitest.model.ArtistsAlbum;
import com.example.richard.webapitest.service.APIService;
import java.util.ArrayList;
import kaaes.spotify.webapi.android.models.ArtistsPager;
import kaaes.spotify.webapi.android.models.Image;
import retrofit.Callback;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Response;
public class MainActivity extends ActionBarActivity {
public final static String EXTRA_MESSAGE = "com.example.richard.webapitest.MESSAGE";
public final static String EXTRA_ARTIST = "com.example.richard.webapitest.NAME";
public final static int MY_CHILD_ACTIVITY = 0;
static final String LOG_TAG = MainActivity.class.getSimpleName();
static final String END_POINT = "https://api.spotify.com/v1";
final String[] Url = new String[1];
static ArrayList<ArtistsAlbum> artistsAlbums;
ArrayList<ArtistsAlbum> testAlbums;
ArtistsAlbum album;
String url;
String name;
String id;
String mUrl;
String mName;
String mId;
int count;
APIService service;
ListView mListView;
AlbumsAdapter mAdapter;
boolean listViewRefresh = false;
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(EXTRA_ARTIST,name);
super.onSaveInstanceState(outState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if( savedInstanceState != null ) {
name = savedInstanceState .getString(EXTRA_ARTIST);
}
artistsAlbums = new ArrayList<ArtistsAlbum>();
final RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(END_POINT)
.build();
service = adapter.create(APIService.class);
EditText tview = (EditText) findViewById(R.id.artist_field);
tview.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
Log.v("LOG_TAG", s + " onTextChanged() " + " start: " + start + " count: " + count + " after: " + after);
listViewRefresh = (start == 0) && (count == 1) && (after == 0);
}
@Override
public void afterTextChanged(Editable s) { //aftertextchanged{
Log.v("LOG_TAG", s + " afterTextChanged()");
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
name = s.toString();
Log.v("LOG_TAG", s.length() + " onTextChanged() " + " start: " + start + " before: " + before + " count:" + count);
if ((start == 0) && (before == 1) && (count == 0)) { //if .. 7
if (mAdapter != null) {
mAdapter.clear();
mAdapter.notifyDataSetChanged();
}
} else {
//======================================A R T I S T S=====================================m============
service.searchArtists(name, new Callback<ArtistsPager>() {
@Override
public void success(ArtistsPager artistsPager, Response response) {
Image image;
if (artistsPager.artists.items != null) {//for .. 6
if (mAdapter != null) {
mAdapter.clear();
mAdapter.notifyDataSetChanged();
}
artistsAlbums.clear();
for (int i = 0; i < artistsPager.artists.items.size(); i++) { //for .. 1
try { // try .. 1
mName = artistsPager.artists.items.get(i).name; //Breakpoint here!!
mId = artistsPager.artists.items.get(i).id;
int size = artistsPager.artists.items.get(i).images.size();
if (size == 0) {
//------------------------------------------
album = new ArtistsAlbum();
album.setName(mName);
album.setId(mId);
artistsAlbums.add(i,album);
//------------------------------------------
} else {
for (int j = 0; j < size; j++) {
if (80 > artistsPager.artists.items.get(i).images.get(j).width) {
mUrl = artistsPager.artists.items.get(i).images.get(j).url;
album = new ArtistsAlbum();
album.setUrl(mUrl);
album.setName(mName);
album.setId(mId);
artistsAlbums.add(i,album);
}
}
}
} catch (IndexOutOfBoundsException e) { //try .. 1
e.printStackTrace();
}
}// for .. 1
displayItems();
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(final AdapterView<?> parent, final View view,
int position, long id) {
final ArtistsAlbum item = (ArtistsAlbum) parent.getItemAtPosition(position);
// System.out.println("LOG_TAG" + "name: " + item.getName() + " id: " + item.getId() + " Url: " + item.getUrl());
sendMessage(item.getId());
}
});
Log.v(LOG_TAG,"=======================================================================================");
for (ArtistsAlbum obj : artistsAlbums)
System.out.println("LOG_TAG" + "name: " + obj.getName() + " id: " + obj.getId() + " Url: " + obj.getUrl());
Log.v(LOG_TAG, "=======================================================================================");
} //for..6
}
@Override
public void failure (RetrofitError error){
}
}
);
}//if .. 7
} //aftertextchanged
});
}
public void sendMessage(String message) {
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra(EXTRA_MESSAGE, message);
startActivityForResult(intent, MY_CHILD_ACTIVITY);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case (MY_CHILD_ACTIVITY) : {
if (resultCode == Activity.RESULT_OK) {
// TODO Extract the data returned from the child Activity.
}
break;
}
}
}
private void displayItems() {
//Use FlowerAdapter to display data
if (mAdapter == null) {
Log.v(LOG_TAG,"in displayItems" + count++);
mAdapter = new AlbumsAdapter(getBaseContext(), R.layout.item_flower, artistsAlbums);
mListView = (ListView) findViewById(android.R.id.list);
mListView.setAdapter(mAdapter);
} else {
mAdapter.addAll(artistsAlbums);
mAdapter.notifyDataSetChanged();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
AlbumsAdapter:
package com.example.richard.webapitest;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.richard.webapitest.model.ArtistsAlbum;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
public class AlbumsAdapter extends ArrayAdapter<ArtistsAlbum> {
private Context context;
private List<ArtistsAlbum> albumsList;
private LruCache<String, Bitmap> imageCache;
public AlbumsAdapter(Context context, int resource, List<ArtistsAlbum> objects) {
super(context, resource, objects);
this.context = context;
this.albumsList = objects;
final int maxMemory = (int)(Runtime.getRuntime().maxMemory() /1024);
final int cacheSize = maxMemory / 8;
imageCache = new LruCache<>(cacheSize);
}
@Override
public int getCount() {
return albumsList.size();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.item_flower, parent, false);
//Display album name in the TextView widget
ArtistsAlbum album = albumsList.get(position);
TextView tv = (TextView) view.findViewById(R.id.textView1);
tv.setText(album.getName());
//Display album image in ImageView widget
Bitmap bitmap = imageCache.get(album.getId());
if (bitmap != null) {
ImageView image = (ImageView) view.findViewById(R.id.imageView1);
//image.setImageBitmap(album.getBitmap());
image.setImageBitmap(bitmap);
}
else {
AlbumAndView container = new AlbumAndView();
container.album = album;
container.view = view;
ImageLoader loader = new ImageLoader();
loader.execute(container);
}
return view;
}
class AlbumAndView {
public ArtistsAlbum album; //ArtistAlbum class
public View view;
public Bitmap bitmap;
}
private class ImageLoader extends AsyncTask<AlbumAndView, Void, AlbumAndView> {
@Override
protected AlbumAndView doInBackground(AlbumAndView... params) {
AlbumAndView container = params[0];
ArtistsAlbum album = container.album;
try {
//String imageUrl = MainActivity.PHOTOS_BASE_URL + album.getPhoto();
String imageUrl = album.getUrl();
if (null!=imageUrl) {
//Log.v("LOG_TAG", "image: " + imageUrl);
InputStream in = (InputStream) new URL(imageUrl).getContent();
Bitmap bitmap = BitmapFactory.decodeStream(in);
//Log.v("LOG_TAG", "bitmap size: "+bitmap.getByteCount());
// album.setBitmap(bitmap); //WHAT DOES THIS LINE DO?
in.close();
container.bitmap = bitmap;
} else {
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.record_icon);
container.bitmap = bitmap;
}
return container;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(AlbumAndView result) {
ImageView image = (ImageView) result.view.findViewById(R.id.imageView1);
//Log.v("LOG_TAG", "image: " + image);
if (null!=result.bitmap) {
image.setImageBitmap(result.bitmap);
imageCache.put(result.album.getId(), result.bitmap);
}
}
}
}
ArtistsAlbum(模特):
package com.example.richard.webapitest.model;
import android.graphics.Bitmap;
/**
* Created by richard on 25/06/15.
*/
public class ArtistsAlbum {
private String name; //Name of album.
private String id; //Id - used later to get the top 10 items and
//used as a key to store/retrieve the bitmap image in cache.
private String url; //url of thumb nail.
public Bitmap bitmap; //The bitmap of the thumb nail.
public String getId(){ return id;}
public void setId(String id) {this.id = id;}
public String getName() {return name;}
public void setName(String name){this.name = name;}
public String getUrl() {return url;}
public void setUrl(String url) {this.url = url;}
public void setBitmap(Bitmap bitmap) {this.bitmap = bitmap;}
public Bitmap getBitmap() { return bitmap;}
}
APIService(Spotify服务):
package com.example.richard.webapitest.service;
import kaaes.spotify.webapi.android.models.Albums;
import kaaes.spotify.webapi.android.models.AlbumsPager;
import kaaes.spotify.webapi.android.models.Artist;
import kaaes.spotify.webapi.android.models.Artists;
import kaaes.spotify.webapi.android.models.ArtistsPager;
import kaaes.spotify.webapi.android.models.Tracks;
import kaaes.spotify.webapi.android.models.TracksPager;
import retrofit.Callback;
import retrofit.http.GET;
import retrofit.http.Path;
import retrofit.http.Query;
public interface APIService {
/**
* The maximum number of objects to return..
*/
public static final String LIMIT = "limit";
/**
* The index of the first playlist to return. Default: 0 (the first object).
* Use with limit to get the next set of objects (albums, playlists, etc).
*/
public static final String OFFSET = "offset";
/**
* A comma-separated list of keywords that will be used to filter the response.
* Valid values are: {@code album}, {@code single}, {@code appears_on}, {@code compilation}
*/
public static final String ALBUM_TYPE = "album_type";
/**
* The country: an ISO 3166-1 alpha-2 country code.
* Limit the response to one particular geographical market.
* Synonym to {@link #COUNTRY}
*/
public static final String MARKET = "market";
/**
* Same as {@link #MARKET}
*/
public static final String COUNTRY = "country";
/**
* The desired language, consisting of a lowercase ISO 639 language code
* * and an uppercase ISO 3166-1 alpha-2 country code, joined by an underscore.
* For example: es_MX, meaning "Spanish (Mexico)".
*/
public static final String LOCALE = "locale";
/************
* Profiles *
************/
/**
* Get Spotify catalog information about albums that match a keyword string.
*
* @param q The search query's keywords (and optional field filters and operators), for example "roadhouse+blues"
* @param callback Callback method.
* @see <a href="https://developer.spotify.com/web-api/search-item/">Search for an Item</a>
*/
@GET("/search?type=album")
public void searchAlbums(@Query("q") String q, Callback<AlbumsPager> callback);
/**
* Get Spotify catalog information about artists that match a keyword string.
*
* @param q The search query's keywords (and optional field filters and operators), for example "roadhouse+blues"
* @param callback Callback method.
* @see <a href="https://developer.spotify.com/web-api/search-item/">Search for an Item</a>
*/
@GET("/search?type=artist")
public void searchArtists(@Query("q") String q, Callback<ArtistsPager> callback);
/**
* Get Spotify catalog information for several artists based on their Spotify IDs.
*
* @param artistIds A comma-separated list of the Spotify IDs for the artists
* @param callback Callback method
* @see <a href="https://developer.spotify.com/web-api/get-several-artists/">Get Several Artists</a>
*/
@GET("/artists")
public void getArtists(@Query("ids") String artistIds, Callback<Artists> callback);
/**
* Get Spotify catalog information for a single artist identified by their unique Spotify ID.
*
* @param artistId The Spotify ID for the artist.
* @see <a href="https://developer.spotify.com/web-api/get-artist/">Get an Artist</a>
*/
@GET("/artists/{id}")
public Artist getArtist(@Path("id") String artistId);
/**
* Get Spotify catalog information about tracks that match a keyword string.
*
* @param q The search query's keywords (and optional field filters and operators), for example "roadhouse+blues"
* @param callback Callback method.
* @see <a href="https://developer.spotify.com/web-api/search-item/">Search for an Item</a>
*/
@GET("/search?type=track")
public void searchTracks(@Query("q") String q, Callback<TracksPager> callback);
/**
* Get Spotify catalog information for multiple albums identified by their Spotify IDs.
*
* @param albumIds A comma-separated list of the Spotify IDs for the albums
* @param callback Callback method
* @see <a href="https://developer.spotify.com/web-api/get-several-albums/">Get Several Albums</a>
*/
@GET("/albums")
public void getAlbums(@Query("ids") String albumIds, Callback<Albums> callback);
/**
* Get Spotify catalog information about an artist’s top tracks by country.
*
* @param artistId The Spotify ID for the artist.
* @param callback Callback method
* @see <a href="https://developer.spotify.com/web-api/get-artists-top-tracks/">Get an Artist’s Top Tracks</a>
*/
@GET("/artists/{id}/top-tracks?country=US")
public void getArtistTopTrack(@Path("id") String artistId, Callback<Tracks> callback);
}
答案 0 :(得分:0)
我敢打赌,这个问题在某种程度上,你是如何将新值传递给适配器的。这,我要做的是在你的适配器类中创建这种方法:
public class setData(List<ArtistsAlbum> albumsList) {
this.albumsList.clear();
this.albumsList.addAll(albumsList);
notifyDataSetChanged();
}
然后在MainAvtivity中我会将displayItems()
中的其他部分替换为:
} else {
mAdapter.setData(artistsAlbums);
}
现在,为什么会这样发生。我们必须记住,它是异步发生的,在进行调用之前,并且执行请求有一些时间+事情可以并行完成,所以即使你正在进行一些清算,它们也不会被应用。