gpt4 book ai didi

android - 为 RecyclerView 下载图片时出现性能问题

转载 作者:行者123 更新时间:2023-11-29 23:23:08 25 4
gpt4 key购买 nike

我有一个带有自定义适配器的 ListView。每行都有一个我使用位图呈现的 ImageView,但是我当前的代码在执行下载位图的 AsyncTask 后使用 get() 时阻塞了 UI 线程。我想更改我的代码并访问 onPostExecute() 或类似内容中的 imageViews。这样行就已经显示出来,而无需等待所有 Sprite 加载。

Adapter类(这里触发下载)

public class PokemonAdapter extends ArrayAdapter<PokemonPOJO> implements View.OnClickListener{

private ArrayList<PokemonPOJO> dataSet;
Context mContext;
private int lastPosition = -1;

// View lookup cache
private static class ViewHolder {
TextView txtName;
TextView txtCP;
TextView txtGenderShiny;
ImageView sprite;
Button btnDelete;
}

public PokemonAdapter(ArrayList<PokemonPOJO> data, Context context) {
super(context, R.layout.row_pokemon, data);
this.dataSet = data;
this.mContext=context;
}

@Override
public void onClick(View v) {

int position=(Integer) v.getTag();
Object object= getItem(position);
PokemonPOJO dataModel=(PokemonPOJO)object;

switch (v.getId())
{
case R.id.btn_delete:
FirebaseDatabase.getInstance().getReference("pokemons").child(dataModel.getUid()).removeValue();
Toast.makeText(getContext(), "Pokemon removed!", Toast.LENGTH_SHORT).show();
this.remove(dataModel);
break;
}
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
PokemonPOJO dataModel = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
ViewHolder viewHolder; // view lookup cache stored in tag

final View result;

if (convertView == null) {

viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.row_pokemon, parent, false);
viewHolder.txtName = (TextView) convertView.findViewById(R.id.text_name);
viewHolder.txtCP = (TextView) convertView.findViewById(R.id.text_cp);
viewHolder.txtGenderShiny = (TextView) convertView.findViewById(R.id.text_gendershiny);
viewHolder.sprite = (ImageView) convertView.findViewById(R.id.img_sprite);
viewHolder.btnDelete = (Button)convertView.findViewById(R.id.btn_delete);
result=convertView;

convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
result=convertView;
}

lastPosition = position;

viewHolder.txtName.setText(dataModel.getName());
viewHolder.txtCP.setText("CP: " + Integer.toString(dataModel.getCP()));
viewHolder.txtGenderShiny.setText(dataModel.getGender() + (dataModel.isShiny() ? " (Shiny)" : ""));
viewHolder.btnDelete.setOnClickListener(this);

try {
Bitmap bm = new DownloadImageTask().execute(dataModel.getSpriteUrl()).get();
viewHolder.sprite.setImageBitmap(bm);
} catch (Exception e) {
e.printStackTrace();
}
viewHolder.btnDelete.setTag(position);

// Return the completed view to render on screen
return convertView;
}

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {

@Override
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap bm = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
bm = BitmapFactory.decodeStream(in);
} catch (Exception e) {
e.printStackTrace();
}
return bm;
}

}

带有 ListView 的 fragment

public class MyPokemonFragment extends Fragment {

private FirebaseAuth auth;
private DatabaseReference pokemonDb;
private TextView text_noPokemon;
private ListView listViewPokemon;
private static PokemonAdapter adapter;
private populateListViewTask populateListView;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_mypokemon,null);
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);
auth = FirebaseAuth.getInstance();

listViewPokemon = view.findViewById(R.id.list_pokemon);
text_noPokemon= view.findViewById(R.id.text_noPokemon);

Query getUserPokemon = FirebaseDatabase.getInstance().getReference("pokemons").orderByChild("userUid").equalTo(auth.getCurrentUser().getUid());
getUserPokemon.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {

if(!snapshot.hasChildren()) {
text_noPokemon.setText("You have not added any Pokémon yet.");
}
else {
TreeMap<String, Pokemon> pokemons = new TreeMap<>();
for (DataSnapshot pokemon : snapshot.getChildren()) {
pokemons.put(pokemon.getKey(), pokemon.getValue(Pokemon.class));
}
populateListView = new populateListViewTask();
populateListView.execute(pokemons);
}
}

@Override
public void onCancelled(DatabaseError databaseError) { }
});

}

@Override
public void onDestroy() {
super.onDestroy();
if(populateListView != null && populateListView.getStatus() == AsyncTask.Status.RUNNING)
populateListView.cancel(true);
}

private class populateListViewTask extends AsyncTask<TreeMap<String, Pokemon>, Void, ArrayList<PokemonPOJO>> {

@Override
protected ArrayList<PokemonPOJO> doInBackground(TreeMap<String, Pokemon>... maps) {

ArrayList<PokemonPOJO> pojos = new ArrayList<>();
HttpURLConnection connection = null;
BufferedReader reader = null;

Iterator it = maps[0].entrySet().iterator();
while(it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
Pokemon p = (Pokemon)pair.getValue();
try {
URL url = new URL("https://pokeapi.co/api/v2/pokemon/" + p.getPokedexNr() + "/");
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}

JSONObject j = new JSONObject(buffer.toString());
String name = j.getString("name");
String spriteUrl = (p.isShiny() ? j.getJSONObject("sprites").getString("front_shiny") : j.getJSONObject("sprites").getString("front_default"));

PokemonPOJO pojo = new PokemonPOJO((String)pair.getKey(), p.getPokedexNr(), name, spriteUrl, p.isShiny(), p.getGender(), p.getCP());
pojos.add(pojo);
} catch (Exception e) {
e.printStackTrace();
} finally {
connection.disconnect();
try {
if (reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return pojos;
}

@Override
protected void onPostExecute (ArrayList < PokemonPOJO > pojos) {
adapter = new PokemonAdapter(pojos, getContext());
listViewPokemon.setAdapter(adapter);
}
}
}

宠物小 Sprite 行 XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<ImageView
android:id="@+id/img_sprite"
android:layout_width="96dp"
android:layout_height="96dp"
android:scaleType="fitCenter" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="left|center_vertical"
android:orientation="vertical">

<TextView
android:id="@+id/text_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="20sp"
android:textStyle="bold" />

<TextView
android:id="@+id/text_cp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp" />

<TextView
android:id="@+id/text_gendershiny"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="end"
android:orientation="vertical">

<Button
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:backgroundTint="@color/colorPrimary"
android:text="DELETE"
android:textColor="#ffffff"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>

</LinearLayout>

</android.support.v7.widget.CardView>

最佳答案

您遇到性能问题是因为您在 AsyncTask 上调用了 get() 方法。 get() 方法基本上会导致主线程等待,直到 AsyncTask 中的代码执行完毕,然后主线程才会继续执行其他指令。为什么谷歌添加这种方法至少可以说是好奇的。所以这样做是为了修复您的代码。

创建一个新的 Java 类文件。将文件命名为“DownloadImageTask”并添加以下代码:

public interface DownloadImageListener {
void onCompletedImageDownload(Bitmap bm);
}


public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {

private static final String TAG = DownloadImageTask.class.getSimpleName();

private DownloadImageListener mListener;
private String imageUrl = "";

public DownloadImageTask(String imageUrl, DownloadImageListener listener){
this.imageUrl = imageUrl;
this.mListener = listener;
}


@Override
protected Bitmap doInBackground(String... urls) {
Bitmap bm = null;
try {
InputStream in = new java.net.URL(imageUrl).openStream();
bm = BitmapFactory.decodeStream(in);
} catch (Exception e) {
e.printStackTrace();
}
return bm;
}

protected void onPostExecute(Bitmap bm) {
mListener.onCompletedImageDownload(bm);
}
}


如果您在将公共(public) interface 添加到“DownloadImageTask”Java 文件时遇到任何问题,只需创建一个单独的 Java 文件名称“DownloadImageListener”并将 interface 代码放在那里。


设置您的代码以查询AsyncTask
更改 getView() 中的 Adapter 代码:

try {
Bitmap bm = new DownloadImageTask().execute(dataModel.getSpriteUrl()).get();
viewHolder.sprite.setImageBitmap(bm);
} catch (Exception e) {
e.printStackTrace();
}

为此:

try {
DownloadImageListener listener = new DownloadImageListener() {
@Override
public void onCompletedImageDownload(Bitmap bm) {
if(bm != null){
viewHolder.sprite.setImageBitmap(bm);
}
}
};

String imageUrl = dataModel.getSpriteUrl();

DownloadImageTask downloadImageTask = new DownloadImageTask(imageUrl, listener);
downloadImageTask.execute();

} catch (Exception e) {
Log.e(TAG, e.getMessage());
}


这允许您的 AsyncTask 执行,当返回 Bitmap 时,监听器在 onPostExecute() 方法中被触发,发送 BitmaponCompletedImageDownload() 回调方法中的 ListView

附加信息:
为了进一步提高性能,您可以创建一个缓存模型来保存和检索设备中的图像(如果您过去已经下载过图像)。但这需要一些非常先进的技术——当您要下载的图像可能不时发生变化时,这会变得非常棘手。

关于android - 为 RecyclerView 下载图片时出现性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53905844/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com