В ImageView не загружается картинка по URL адресу
У меня есть RecyclerView в котором я отображаю фото и текст под фото через CardView. Данные получаю через Json файл. Текст отображается корректно, только вот картинка почему-то не грузится.
NewsAdapterRV:
package com.example.istrcheese;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
public class NewsAdapterRV extends RecyclerView.Adapter<NewsAdapterRV.MyViewClass> {
ArrayList<String> txt_news;
ArrayList<String> img_news;
Context context;
public NewsAdapterRV(ArrayList<String> txt_news, ArrayList<String> img_news, Context context) {
this.txt_news = txt_news;
this.img_news = img_news;
this.context = context;
}
@NonNull
@Override
public NewsAdapterRV.MyViewClass onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_news_card_view, parent, false);
return new MyViewClass(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewClass holder, int position) {
holder.txt_News.setText(txt_news.get(position));
holder.img_News.setImageDrawable(LoadImageFromWebOperations(img_news.get(position)));
holder.itemView.setOnClickListener(view ->
Toast.makeText(context, R.string.text_itemClicked, Toast.LENGTH_SHORT).show());
}
@Override
public int getItemCount() {
return txt_news.size();
}
public static class MyViewClass extends RecyclerView.ViewHolder {
TextView txt_News;
ImageView img_News;
public MyViewClass(View itemView) {
super(itemView);
txt_News = itemView.findViewById(R.id.item_news_CV_text);
img_News = itemView.findViewById(R.id.item_news_CV_image);
}
}
// Получение изображения по URL-адресу
public static Drawable LoadImageFromWebOperations(String url) {
try {
InputStream is = (InputStream) new URL(url).getContent();
return Drawable.createFromStream(is, "src name");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
HomeFragment:
package com.example.istrcheese;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Objects;
public class HomeFragment extends Fragment {
View view;
RecyclerView recyclerView;
ArrayList<String> txt_ns = new ArrayList<>();
ArrayList<String> img_ns = new ArrayList<>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_home, container, false);
recyclerView = view.findViewById(R.id.news_recyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(container.getContext().getApplicationContext());
linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
recyclerView.setLayoutManager(linearLayoutManager);
JSONObject jsonObject;
try {
jsonObject = new JSONObject(Objects.requireNonNull(JsonDataFromAsset("exampleNews.json")));
JSONArray jsonArray = jsonObject.getJSONArray("exampleNews");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject userData = jsonArray.getJSONObject(i);
txt_ns.add(userData.getString("text_news"));
img_ns.add(userData.getString("image_news"));
}
} catch (JSONException e) {
e.printStackTrace();
}
NewsAdapterRV newsAdapterRV = new NewsAdapterRV(txt_ns, img_ns, HomeFragment.this.getContext());
recyclerView.setAdapter(newsAdapterRV);
return view;
}
@Nullable
private String JsonDataFromAsset(String fileName) {
String json;
try {
InputStream inputStream = requireContext().getAssets().open(fileName);
int sizeOfFile = inputStream.available();
byte[] bufferData = new byte[sizeOfFile];
inputStream.read(bufferData);
inputStream.close();
json = new String(bufferData, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return json;
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.istrcheese">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.IstrCheese"
tools:targetApi="31">
<activity
android:name=".ForgetPasswordActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".AuthActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
</application>
<uses-permission
android:name="android.permission.INTERNET" />
</manifest>
Измененный HomeFragment:
package com.example.istrcheese;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Objects;
public class HomeFragment extends Fragment {
View view;
RecyclerView recyclerView;
ArrayList<String> txt_ns = new ArrayList<>();
ArrayList<Drawable> img_ns = new ArrayList<>();
String image_str;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_home, container, false);
recyclerView = view.findViewById(R.id.news_recyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(container.getContext().getApplicationContext());
linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
recyclerView.setLayoutManager(linearLayoutManager);
JSONObject jsonObject;
try {
jsonObject = new JSONObject(Objects.requireNonNull(JsonDataFromAsset("exampleNews.json")));
JSONArray jsonArray = jsonObject.getJSONArray("exampleNews");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject userData = jsonArray.getJSONObject(i);
txt_ns.add(userData.getString("text_news"));
image_str = userData.getString("image_news");
img_ns.add(LoadImageFromWebOperations(image_str));
}
} catch (JSONException e) {
e.printStackTrace();
}
NewsAdapterRV newsAdapterRV = new NewsAdapterRV(txt_ns, img_ns, HomeFragment.this.getContext());
recyclerView.setAdapter(newsAdapterRV);
return view;
}
@Nullable
private String JsonDataFromAsset(String fileName) {
String json;
try {
InputStream inputStream = requireContext().getAssets().open(fileName);
int sizeOfFile = inputStream.available();
byte[] bufferData = new byte[sizeOfFile];
inputStream.read(bufferData);
inputStream.close();
json = new String(bufferData, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return json;
}
public static Drawable LoadImageFromWebOperations(String url) {
try {
InputStream is = (InputStream) new URL(url).getContent();
return Drawable.createFromStream(is, "src name");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
ОБНОВЛЕНИЕ 2:
Адаптер
package com.example.istrcheese;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.RequestBuilder;
import java.util.ArrayList;
public class NewsAdapterRV extends RecyclerView.Adapter<NewsAdapterRV.MyViewClass> {
ArrayList<String> txt_news;
ArrayList<RequestBuilder<Drawable>> img_news;
Context context;
public NewsAdapterRV(ArrayList<String> txt_news, ArrayList<RequestBuilder<Drawable>> img_news, Context context) {
this.txt_news = txt_news;
this.img_news = img_news;
this.context = context;
}
@NonNull
@Override
public NewsAdapterRV.MyViewClass onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_news_card_view, parent, false);
return new MyViewClass(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewClass holder, int position) {
holder.txt_News.setText(txt_news.get(position));
holder.img_News.setImageURI(img_news.get(position)); // что здесь нужно писать?
holder.itemView.setOnClickListener(view ->
Toast.makeText(context, R.string.text_itemClicked, Toast.LENGTH_SHORT).show());
}
@Override
public int getItemCount() {
return txt_news.size();
}
public static class MyViewClass extends RecyclerView.ViewHolder {
TextView txt_News;
ImageView img_News;
public MyViewClass(View itemView) {
super(itemView);
txt_News = itemView.findViewById(R.id.item_news_CV_text);
img_News = itemView.findViewById(R.id.item_news_CV_image);
}
}
}
Ответы (1 шт):
Автор решения: woesss
→ Ссылка
Андроид запрещает выполнять сетевые операции в главном потоке.
Тема многопоточности сложная и в контексте андроида с жизненным циклом компонентов ещё сложнее.
Проще всего воспользоваться готовым решением: для работы с картинками наиболее популярны Glide, Picasso.
Минимальный пример для Picasso, мне она кажется попроще.
Добавить зависимость в gradle:
implementation 'com.squareup.picasso:picasso:2.8'
В адаптере:
@Override
public void onBindViewHolder(@NonNull MyViewClass holder, int position) {
holder.txt_News.setText(txt_news.get(position));
Picasso.get().load(img_news.get(position)).into(holder.img_News); // img_news - это список ссылок на картинки
holder.itemView.setOnClickListener(view ->
Toast.makeText(context, R.string.text_itemClicked, Toast.LENGTH_SHORT).show());
}