I have a ListView with a custom adapter. Every row has an ImageView that I render using a Bitmap, but my current code blocks the UI thread as I am using get() after executing my AsyncTask that downloads the bitmaps. I would like to change my code and access the imageViews in the onPostExecute() or something similar. So that the rows already display without waiting for all sprites to load.
Adapter class (download is triggered here)
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;
}
}
Fragment with ListView
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);
}
}
}
Pokemon row 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>
You are having performance issues because you are calling the get() method on your AsyncTask. The get() method basically causes the main thread to wait until the code in the AsyncTask completes execution before the main thread continues executing other instructions. Why Google added this method is curious to say the least. So do this to fix your code.
Create a new Java class file. Name the file "DownloadImageTask" and add this code:
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);
}
}
If you have any issues adding the public interface to the "DownloadImageTask" Java file just create a separate Java file name "DownloadImageListener" and put the interface code in there.
Set your code to query the AsyncTask.
Change the Adapter code inside your getView() from this:
try {
Bitmap bm = new DownloadImageTask().execute(dataModel.getSpriteUrl()).get();
viewHolder.sprite.setImageBitmap(bm);
} catch (Exception e) {
e.printStackTrace();
}
to this:
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());
}
This allows your AsyncTask to execute and when the Bitmap is returned the listener is triggered in the onPostExecute() method sending the Bitmap to your ListView in the onCompletedImageDownload() callback method.
Additional Info:
To improve performance even further you could create a caching model to save and retrieve images from the device if you have already downloaded them in the past. But that requires some really advanced techniques--and gets really tricky when images you wish to download might change from time to time.
Related
https://launchlibrary.net/1.3/launch shows json data. If you paste the id after this url, there is more in depth information about the launch, for example https://launchlibrary.net/1.3/launch/2053.
I want to get the image url of the corresponding launch but it doesn't work how I'm doing it. This is the code from where I parse the JSON data.
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
v = inflater.inflate(R.layout.activity_launches, container, false);
myRecyclerView = (RecyclerView) v.findViewById(R.id.recycler_view);
myRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
launchesList = new ArrayList<>();
temporaryList = new ArrayList<>();
myRequestQueue = Volley.newRequestQueue(getContext());
parseJSON();
return v;
}
private void parseJSON(){
String url = "https://launchlibrary.net/1.3/launch";
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("launches");
for(int i = 0; i < jsonArray.length(); i++){
JSONObject launch = jsonArray.getJSONObject(i);
String launchName = launch.getString("name");
String launchDate = launch.getString("net");
launchId = launch.getString("id");
String imageUrl = getImageUrl();
Launch newLaunch = new Launch(launchName, launchDate, imageUrl);
launchesList.add(newLaunch);
}
myRecyclerViewAdapter = new RecyclerViewAdapter(getContext(), launchesList);
myRecyclerView.setAdapter(myRecyclerViewAdapter);
myRecyclerViewAdapter.setOnItemClickListener(LaunchesActivity.this);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
myRequestQueue.add(request);
}
public String getImageUrl(){
String url = "https://launchlibrary.net/1.3/launch/" + launchId;
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("launches");
JSONObject launch = jsonArray.getJSONObject(0);
JSONObject rocket = launch.getJSONObject("rocket");
String url = rocket.getString("imageURL");
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
myRequestQueue.add(request);
return url;
}
This is the adapter I created to change the text in the TextViews and ImageView.
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder>{
private Context myContext;
private ArrayList<Launch> launchList;
private OnItemClickListener myListener;
public interface OnItemClickListener{
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
myListener = listener;
}
public RecyclerViewAdapter(Context context, ArrayList<Launch> launchList){
myContext = context;
this.launchList = launchList;
}
#NonNull
#Override
public RecyclerViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(myContext).inflate(R.layout.launch_item, parent, false);
return new RecyclerViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull RecyclerViewHolder holder, int position) {
Launch currentItem = launchList.get(position);
String name = currentItem.getName();
String date = currentItem.getDate();
String imageUrl = currentItem.getImageUrl();
holder.myTextViewName.setText(name);
holder.myTextViewDate.setText(date);
Picasso.get().load(imageUrl).fit().centerInside().into(holder.myImageViewImage);
}
#Override
public int getItemCount() {
return launchList.size();
}
public class RecyclerViewHolder extends RecyclerView.ViewHolder{
public TextView myTextViewName;
public TextView myTextViewDate;
public ImageView myImageViewImage;
public RecyclerViewHolder(#NonNull View itemView) {
super(itemView);
myTextViewName = itemView.findViewById(R.id.launch_name);
myTextViewDate = itemView.findViewById(R.id.date);
myImageViewImage = itemView.findViewById(R.id.thumbnail);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(myListener != null){
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION){
myListener.onItemClick(position);
}
}
}
});
}
}
A launch object is just this:
public Launch(String name, String date, String imageUrl) {
this.name = name;
this.date = date;
this.imageUrl = imageUrl;
}
What am I doing wrong?
Recyclerview item layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginTop="5dp"
android:padding="8dp"
android:background="#323131">
<ImageView
android:id="#+id/thumbnail"
android:layout_width="100dp"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="130dp"
android:layout_margin="8dp"
android:orientation="vertical">
<TextView
android:id="#+id/launch_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Launch name"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#android:color/white"/>
<TextView
android:id="#+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="Date"
android:textColor="#android:color/white"/>
</LinearLayout>
Recyclerview layout
Recyclerview layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recycler_view"
android:background="#323131"/>
make getImage function get the index of array object and i will tell you why
String imageUrl = getImageUrl(i);
public String getImageUrl(final int index)
after getting url adding that
String url = rocket.getString("imageURL");
launchesList.get(index).imageUrl = url;
myRecyclerViewAdapter.notifyItemChanged(index);
now i tell the thread of get image get image and when finish notify adapter
it work for me
In your getImageUrl() you are returning the wrong url which is this:
String url = "https://launchlibrary.net/1.3/launch/" + launchId;
instead do this:
public String getImageUrl(){
String url = "https://launchlibrary.net/1.3/launch/" + launchId;
//add this
String imageURL = null;
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("launches");
JSONObject launch = jsonArray.getJSONObject(0);
JSONObject rocket = launch.getJSONObject("rocket");
imageURL = rocket.getString("imageURL");
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
myRequestQueue.add(request);
//return it here
return imageURL;
}
my friend above help u in parsing but let me know why you use two request one for parsing object and second one for get image but u should know that here you will use two thread so we will work on make them in one thread
and check if catch print any log
please send object in array to getImage function and continue to parse
String imageUrl = getImageUrl(launch );
and fix getImageUrl function
public String getImageUrl(JSONObject launch ){
JSONObject rocket = launch.getJSONObject("rocket");
String url = rocket.getString("imageURL");
return url;
}
try this if error still exist please inform me and i will try it on my code
So I put an images inside of gridview, it works fine when the beginning and showing 20 images but when I try to show less than that it won't updated.
there are a condition when the gridview updated, it's updated when I load 20 images but when I try to load less or zero it wont updated.
how do I resolve this ?
here is my code on the adapter
private final Context context;
private List<Movie> urls = new ArrayList<>();
public MovieGridViewAdapter(Context context, List<Movie> urls) {
this.context = context;
this.urls = urls;
}
#Override
public int getCount() {
if (urls.size() == 0){
return 0;
}
return urls.size();
}
#Override
public Movie getItem(int position) {
return urls.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View view, ViewGroup viewGroup) {
View gridView = view;
if (gridView == null) {
gridView = LayoutInflater.from(context)
.inflate(R.layout.item_poster, viewGroup, false);
}
ImageView posterImageView = (ImageView) gridView.findViewById(R.id.posterImageView);
// Get the image URL for the current position.
Movie movie = getItem(position);
//needed to append the image url
String imageBaseUrl = "http://image.tmdb.org/t/p/w185";
Picasso.with(context) //
.load(imageBaseUrl+movie.getPosterPath()) //
.placeholder(R.drawable.ic_hourglass_empty_black_24dp) //
.error(R.drawable.ic_error_black_24dp) //
.fit() //
.tag(context) //
.into(posterImageView);
Log.v("jalan ji", "jalan");
return gridView;
}
here is where I try to update the Gridview
List<Favorite> favorites = new ArrayList<>();
Cursor cursor = getContentResolver().query(MovieContract.MovieEntry.CONTENT_URI,
null,
null,
null,
MovieContract.MovieEntry.COLUMN_TITLE);
while(cursor.moveToNext()){
String id = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.COLUMN_MOVIE_ID));
String title = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.COLUMN_TITLE));
try{
Favorite fav = new Favorite();
fav.setId(id);
fav.setTitle(title);
favorites.add(fav);
}catch (Exception e){
e.printStackTrace();
}
}
for(Favorite favorite : favorites){
Call<MovieSingle> call = movieDbClient.getMovie(favorite.getId(), apiKey);
setTitle("Favorite Movies");
call.enqueue(new Callback<MovieSingle>() {
#Override
public void onResponse(#NonNull Call<MovieSingle> call, #NonNull Response<MovieSingle> response) {
Movie mov = new Movie();
mov.setBackdropPath(response.body().getBackdrop_path());
mov.setOverview(response.body().getOverview());
mov.setReleaseDate(response.body().getRelease_date());
mov.setTitle(response.body().getTitle());
mov.setVoteAverage(response.body().getVote_average());
mov.setPosterPath(response.body().getPoster_path());
movie.add(mov);
Log.v("berhasil", " "+response.body().getTitle());
}
#Override
public void onFailure(#NonNull Call<MovieSingle> call, #NonNull Throwable t) {
t.printStackTrace();
pbar.setVisibility(View.INVISIBLE);
Log.v("gagal", "berhasil");
showErrorMessage();
}
});
}
showGridView();
pbar.setVisibility(View.INVISIBLE);
MovieGridViewAdapter movieGridViewAdapter = new MovieGridViewAdapter(getApplicationContext(), movie);
Log.v("Test", movie.get(2).getTitle());
Log.v("Test", movie.get(2).getPosterPath());
movieGridViewAdapter.notifyDataSetChanged();
gridView.invalidateViews();
gridView.setAdapter(movieGridViewAdapter);
and the layout
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/bgdetail">
<GridView android:id="#+id/movieitem_grid"
android:layout_marginTop="50dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="165dp"
android:scrollbarStyle="insideOverlay"
android:scrollbars="none"
android:listSelector="#null"
android:numColumns="auto_fit"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tv_error"
android:layout_gravity="center"
android:textAlignment="center"
android:textColor="#color/textColor"
android:text="#string/error_msg"
android:visibility="invisible"
android:textSize="22sp"/>
<ProgressBar
android:layout_width="68dp"
android:layout_height="68dp"
android:layout_gravity="center"
android:id="#+id/progressbar"
android:visibility="invisible"/>
</FrameLayout>
Solved, I have to put the setAdapter method inside the loop and create new variable of list and make it final, can't use the global one. so the final code should look like this
List<Favorite> favorites = new ArrayList<>();
final List<Movie> movie1 = new ArrayList<>();
Cursor cursor = getContentResolver().query(MovieContract.MovieEntry.CONTENT_URI,
null,
null,
null,
MovieContract.MovieEntry.COLUMN_TITLE);
while(cursor.moveToNext()){
String id = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.COLUMN_MOVIE_ID));
String title = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.COLUMN_TITLE));
try{
Favorite fav = new Favorite();
fav.setId(id);
fav.setTitle(title);
favorites.add(fav);
}catch (Exception e){
e.printStackTrace();
}
}
for(Favorite favorite : favorites){
Call<MovieSingle> call = movieDbClient.getMovie(favorite.getId(), apiKey);
setTitle("Favorite Movies");
call.enqueue(new Callback<MovieSingle>() {
#Override
public void onResponse(#NonNull Call<MovieSingle> call, #NonNull Response<MovieSingle> response) {
Movie mov = new Movie();
mov.setBackdropPath(response.body().getBackdrop_path());
mov.setOverview(response.body().getOverview());
mov.setReleaseDate(response.body().getRelease_date());
mov.setTitle(response.body().getTitle());
mov.setVoteAverage(response.body().getVote_average());
mov.setPosterPath(response.body().getPoster_path());
movie1.add(mov);
showGridView();
pbar.setVisibility(View.INVISIBLE);
MovieGridViewAdapter movieGridViewAdapter = new MovieGridViewAdapter(getApplicationContext(), movie1);
movieGridViewAdapter.notifyDataSetChanged();
gridView.setAdapter(movieGridViewAdapter);
Log.v("berhasil", " "+movie1.get(0).getTitle());
}
#Override
public void onFailure(#NonNull Call<MovieSingle> call, #NonNull Throwable t) {
t.printStackTrace();
pbar.setVisibility(View.INVISIBLE);
Log.v("gagal", "berhasil");
showErrorMessage();
}
});
}
The App opens up fine with the First Fragment being displayed correctly. On swipe, next fragment layout comes on the screen. There, on clicking the button, the app crashes.
The error that I get is:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
Some of the top entries from error stack are as follows:
at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:401)
at android.widget.ArrayAdapter.getView(ArrayAdapter.java:369)
at android.widget.AbsListView.obtainView(AbsListView.java:2346)
at android.widget.ListView.makeAndAddView(ListView.java:1876)
at android.widget.ListView.fillDown(ListView.java:702)
at android.widget.ListView.fillFromTop(ListView.java:763)
at android.widget.ListView.layoutChildren(ListView.java:1685)
at android.widget.AbsListView.onLayout(AbsListView.java:2148)
at android.view.View.layout(View.java:16636)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
The app's main activity is as follows:
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager pager = (ViewPager) findViewById(R.id.viewPager);
pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0: return FirstFragment.newInstance("FirstFragment, Instance 1");
case 1: return SecondFragment.newInstance("SecondFragment, Instance 1");
default: return FirstFragment.newInstance("FirstFragment, Default");
}
}
}
}
SecondFragment.java is as follows:
public class SecondFragment extends ListFragment {
static public ArrayAdapter<String> adapter;
static String[] values = new String[3];
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.second_frag, container,
false);
final Button btn = (Button) rootView.findViewById(R.id.readWebpage);
if (btn != null) {
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v){
new HttpGetReq().execute("http://xxx.xxx.xxx.xxx");
adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
}
});
}
return rootView;
}
public static SecondFragment newInstance(String text) {
SecondFragment f = new SecondFragment();
Bundle b = new Bundle();
b.putString("msg", text);
f.setArguments(b);
return f;
}
}
On button click, HttpGetReq.java worker class gets data from the server and displays that to the list.
public class HttpGetReq extends AsyncTask<String , Void ,String> {
String server_response;
#Override
protected String doInBackground(String... strings) {
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(strings[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int responseCode = urlConnection.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK){
server_response = readStream(urlConnection.getInputStream());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.i("TAG", "Assigning new value");
SecondFragment.values[1] = server_response;
}
// Converting InputStream to String
private String readStream(InputStream in) {
BufferedReader reader = null;
StringBuffer response = new StringBuffer();
try {
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
response.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return response.toString();
}
}
second_Frag.xml is as follows:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/myView2">>
<Button
android:id="#+id/readWebpage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Refresh"
android:layout_gravity="center_horizontal">
</Button>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#id/android:list"
android:background="#color/background_Color"
android:layout_width="fill_parent"
android:gravity="center"
android:layout_height="fill_parent"/>
</LinearLayout>
new HttpGetReq().execute("http://xxx.xxx.xxx.xxx");
adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
Here, you're setting adapter before getting the data from HttpGetReq. Since HttpGetReq is an AsyncTask so it executes the line right after you call execute, remaining your value array empty. You should set the data in adapter after you get the data from onPostExecute of your HttpGetReq.
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.i("TAG", "Assigning new value");
SecondFragment.values[1] = server_response;
// Set your data here
}
So my problem is that I can generate the data in the AsyncTask, but I can't get the data to transfer back to the onCreateView. This is my first dive into fragments. Sorry if my code's ugly, I'm just trying to get this to work, and also I'm quite new to Android programming, so sorry if I made a stupid mistake somewhere. I'm not sure if I need to post my global variables. And I know some of my variables are weirdly named.
onCreateView portion
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_news,
container, false);
pb = (ProgressBar) getActivity().findViewById(R.id.progressBar2);
gv = (RecyclerView) view.findViewById(R.id.expandableListView);
swp = (SwipeRefreshLayout) getActivity().findViewById(R.id.activity_main_swipe_refresh_layout);
gv.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
gv.setLayoutManager(layoutManager);
swp.setEnabled(false);
hadapter = new NewsExpandableAdapter(getActivity(), m_hparts);
System.out.println(m_hparts.size());
gv.setAdapter(hadapter);
return view;
}
RecyclerView adapter
public class NewsExpandableAdapter extends RecyclerView.Adapter<NewsExpandableAdapter.ViewHolder> {
private Context context;
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView nameTextView;
public ImageView messageButton;
public ViewHolder(View itemView) {
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.title);
messageButton = (ImageView) itemView.findViewById(R.id.image);
}
}
private ArrayList<Model> mContacts;
public NewsExpandableAdapter(Context c, ArrayList<Model> contacts) {
this.context = c;
mContacts = (ArrayList<Model>) contacts;
}
#Override
public NewsExpandableAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View contactView = inflater.inflate(R.layout.expandable_list_item, parent, false);
ViewHolder viewHolder = new ViewHolder(contactView);
return viewHolder;
}
#Override
public void onBindViewHolder(NewsExpandableAdapter.ViewHolder viewHolder, int position) {
Model contact = mContacts.get(position);
TextView textView = viewHolder.nameTextView;
textView.setText(contact.getTitle());
ImageView image= viewHolder.messageButton;
Picasso.with(viewHolder.itemView.getContext())
.load(contact.getLink())
.into(image);
}
#Override
public int getItemCount() {
return mContacts.size();
}
}
Fragment XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.sample">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="#+id/expandableListView">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
RecyclerView XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="8dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/image"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/title"/>
</LinearLayout>
AsyncTask
public class Directory extends AsyncTask<Void, Void, String> {
String desc;
#Override
protected String doInBackground(Void... params) {
try {
Document document = Jsoup.connect(url + dateFormatYear.format(date)).get();
listing_latest = document.select(".title.page_title");
for (Element listing0 : listing_latest) {
Element hmonth = listing0.select("h3").first();
if(hmonth.text().equals(dateFormatMonth.format(date))){
month = hmonth.text();
hname = hmonth.parent().parent().parent().nextElementSibling();
releaseList = hname.select(".base_header.tc.m6");
for(Element block : releaseList){
name = block.select(".one_line.fs11 a").first();
image = block.select(".base_inner.h244.loading a img").first();
if(name != null){
hn = name.attr("title");
}
if(image != null){
hi = image.attr("abs:src");
}
m_hparts.add(new Model(hi));
}
}
}
} catch (IOException e1) {
e1.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
hadapter.notifyDataSetChanged();
m_hparts.add(new Model(hi));
}
}
Edit: I put the new Directory().execute(); in the onCreate() Still could not get data.
You need to add all of the new items to the data source, and then call notifyDataSetChanged() after the data source has been updated.
Make the return value of doInBackground() a list of your items, and return it to onPostExecute(). You will need to change the parameters of the AsyncTask generics and the parameter passed into onPostExecute() as well.
Assuming your data source looks like this:
List<Model> m_hparts = new ArrayList<>();
You could do something like this:
public class Directory extends AsyncTask<Void, Void, List<Model>> {
String desc;
#Override
protected List<Model> doInBackground(Void... params) {
//added:
List<Model> parts = new ArrayList<>();
try {
Document document = Jsoup.connect(url + dateFormatYear.format(date)).get();
listing_latest = document.select(".title.page_title");
for (Element listing0 : listing_latest) {
Element hmonth = listing0.select("h3").first();
if(hmonth.text().equals(dateFormatMonth.format(date))){
month = hmonth.text();
hname = hmonth.parent().parent().parent().nextElementSibling();
releaseList = hname.select(".base_header.tc.m6");
for(Element block : releaseList){
name = block.select(".one_line.fs11 a").first();
image = block.select(".base_inner.h244.loading a img").first();
if(name != null){
hn = name.attr("title");
}
if(image != null){
hi = image.attr("abs:src");
}
//m_hparts.add(new Model(hi));
//do this instead:
parts.add(new Model(hi));
}
}
}
} catch (IOException e1) {
e1.printStackTrace();
}
//return null;
//do this instead:
return parts;
}
#Override
protected void onPostExecute(List<Model> parts) {
super.onPostExecute(result);
for (Model h: parts) {
m_hparts.add(h);
}
hadapter.notifyDataSetChanged();
}
}
I am following this tutorial for implementing ViewPager in my project. I have done that using static images successfully. Now I want to change it so that images are retrieved from urls and displayed in ViewPager. Below is my code.
Where should I add the method for downloading images and how to set it
to my ViewPager?
Any help will be greatly appreciated.
MainActivity:
public class MainActivity extends AppCompatActivity {
private ArrayList<Integer> images;
private BitmapFactory.Options options;
private ViewPager viewPager;
private View btnNext, btnPrev;
private FragmentStatePagerAdapter adapter;
private LinearLayout thumbnailsContainer;
private final static int[] resourceIDs = new int[]{R.mipmap.a, R.mipmap.b,
R.mipmap.c, R.mipmap.d, R.mipmap.e, R.mipmap.f, R.mipmap.g};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
images = new ArrayList<>();
//find view by id
viewPager = (ViewPager) findViewById(R.id.view_pager);
thumbnailsContainer = (LinearLayout) findViewById(R.id.container);
btnNext = findViewById(R.id.next);
btnPrev = findViewById(R.id.prev);
btnPrev.setOnClickListener(onClickListener(0));
btnNext.setOnClickListener(onClickListener(1));
setImagesData();
// init viewpager adapter and attach
adapter = new ViewPagerAdapter(getSupportFragmentManager(), images);
viewPager.setAdapter(adapter);
inflateThumbnails();
}
private View.OnClickListener onClickListener(final int i) {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
if (i > 0) {
//next page
if (viewPager.getCurrentItem() < viewPager.getAdapter().getCount() - 1) {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
}
} else {
//previous page
if (viewPager.getCurrentItem() > 0) {
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
}
}
}
};
}
private void setImagesData() {
for (int i = 0; i < resourceIDs.length; i++) {
images.add(resourceIDs[i]);
}
}
private void inflateThumbnails() {
for (int i = 0; i < images.size(); i++) {
View imageLayout = getLayoutInflater().inflate(R.layout.item_image, null);
ImageView imageView = (ImageView) imageLayout.findViewById(R.id.img_thumb);
imageView.setOnClickListener(onChagePageClickListener(i));
options = new BitmapFactory.Options();
options.inSampleSize = 3;
options.inDither = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), images.get(i), options );
imageView.setImageBitmap(bitmap);
//set to image view
imageView.setImageBitmap(bitmap);
//add imageview
thumbnailsContainer.addView(imageLayout);
}
}
private View.OnClickListener onChagePageClickListener(final int i) {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
viewPager.setCurrentItem(i);
}
};
}
}
PageFragment class:
public class PageFragment extends Fragment {
private int imageResource;
private Bitmap bitmap;
public static PageFragment getInstance(int resourceID) {
PageFragment f = new PageFragment();
Bundle args = new Bundle();
args.putInt("image_source", resourceID);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
imageResource = getArguments().getInt("image_source");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_page, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inSampleSize = 4;
o.inDither = false;
bitmap = BitmapFactory.decodeResource(getResources(), imageResource, o);
imageView.setImageBitmap(bitmap);
}
#Override
public void onDestroy() {
super.onDestroy();
bitmap.recycle();
bitmap = null;
}
}
ViewPager Adapter class:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private List<Integer> images;
public ViewPagerAdapter(FragmentManager fm, List<Integer> imagesList) {
super(fm);
this.images = imagesList;
}
#Override
public Fragment getItem(int position) {
return PageFragment.getInstance(images.get(position));
}
#Override
public int getCount() {
return images.size();
}
}
To use ViewPager for images you have to make a adapter which extends PagerAdapter like as below:
public class ImagePagerAdapter extends PagerAdapter {
Context context;
LayoutInflater layoutInflater;
ArrayList<String> arrayList;
public ImagePagerAdapter(Context context, ArrayList<String> arrayList) {
this.context = context;
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.arrayList = arrayList;
}
#Override
public int getCount() {
if(arrayList != null){
return arrayList.size();
}
return 0;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((LinearLayout) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View itemView = layoutInflater.inflate(R.layout.image_viewpager_layout, container, false);
ImageView imageView = (ImageView) itemView.findViewById(R.id.viewPagerItem_image1);
Picasso.with(context).load(arrayList.get(position))
.placeholder(R.drawable.image_uploading)
.error(R.drawable.image_not_found).into(imageView);
container.addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((LinearLayout) object);
}
}
And xml layout for adapter is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/viewPagerItem_image1"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="fitXY"
android:src="#drawable/ic_launcher"/>
</LinearLayout>
For Download Images from URL you have to use AsyncTask.
For that follow below Example of DownloadImageFromAsyncTask.
new LoadImage().execute("http://www.sumtrix.com/images/sumtrix/Android-Wallpaper-HD.jpg");
Set your url to above url.
private class LoadImage extends AsyncTask<String, String, Bitmap> {
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("Loading Image...");
dialog.show();
}
#Override
protected Bitmap doInBackground(String... params) {
try {
bitmap = BitmapFactory.decodeStream((InputStream) new URL(params[0]).getContent());
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
if (result != null) {
img.setImageBitmap(result);
dialog.dismiss();
} else {
dialog.dismiss();
Toast.makeText(getApplicationContext(), "Image Does Not Exist...",
Toast.LENGTH_LONG).show();
}
}
}
for that you have to add permission in AndroidManifest.xml file
<uses-permission android:name="android.permission.INTERNET" />
IMO you should set your image here, your imageResource is your imgUrl and using a lib such as: UniversalImageLoader, Volley, Picasso... we have many libs to support loading image with url.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inSampleSize = 4;
o.inDither = false;
bitmap = BitmapFactory.decodeResource(getResources(), imageResource, o);
imageView.setImageBitmap(bitmap);
}
you should call the picdownloadertask in onViewCreated()
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
new PicDownladerTask().execute(url)
}
class PicDownloaderTask extends AsyncTask {
#Override
protected Bitmap doInBackground(String... strings) {
Bitmap bitmap = getBitmap(strings[0]);
return bitmap;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inSampleSize = 4;
o.inDither = false;
bitmap = BitmapFactory.decodeResource(getResources(), imageResource, o);
imageView.setImageBitmap(bitmap);
}
this is the method to get images from url
public static Bitmap getBitmap(String url)
{
try {
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(70000);
conn.setReadTimeout(70000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
// OutputStream os = new FileOutputStream(f);
// Utils.CopyStream(is, os);
// os.close();
bitmap = BitmapFactory.decodeStream(is);
conn.disconnect();
// bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex){
ex.printStackTrace();
if(ex instanceof OutOfMemoryError){}
// memoryCache.clear();
return null;
}
}
I use Picasso library when I need to show image from a URL. It is extremely simple to use.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
Picasso.with(this)
.load(image_url)
.into(imageView);
}
You can see references and download library from this, Picasso
Hope it's helpful.
Use this code to download and show on imageView.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout_here);
new DownloadImageTask((ImageView) findViewById(R.id.imageView1))
.execute("http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png");
}
public void onClick(View v) {
startActivity(new Intent(this, IndexActivity.class));
finish();
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
}
add internet permission in AndroidManifest.xml.
<uses-permission android:name="android.permission.INTERNET" />
see this link for more detail
create a async task and download the image in do in background
#Override
protected Bitmap doInBackground(String... url) {
this.url = url[0];
final DefaultHttpClient client = new DefaultHttpClient();
final org.apache.http.client.methods.HttpGet getRequest = new org.apache.http.client.methods.HttpGet(
url[0]);
try {
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
LoggerUtils.logWarn("ImageDownloader", "Error "
+ statusCode + " while retrieving bitmap from "
+ url[0]);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
final Bitmap bitmap = BitmapFactory
.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
getRequest.abort();
}