This question already has answers here:
How do I parse JSON in Android? [duplicate]
(3 answers)
Closed 6 years ago.
I found this code that I have modified to suit my needs. However I am facing a bit of an issue. It appears that the data is obtained from the remote host but cannot be parsed into adapter.
I have reviewed my entire code structure to ensure that everything is in place but I cant seem to find the problem. The ListView is inside of a Fragment that is part of a TabbedActivity.
This my code:
Fragment inside a Tabbed Activity
public class shops extends Fragment {
String url="http://link to remote webservice";
//FragmentManager fm;
//newInstance() method return reference to fragment
public static shops newInstance(){
shops fragment = new shops();
return fragment;
}
public shops() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//fm = getFragmentManager();
View view = inflater.inflate(R.layout.fragment_shops, container, false);
final ListView listView = (ListView)view.findViewById(R.id.shops_info);
final Downloader d =new Downloader(getActivity(),url,listView);
d.execute();
//calls DialoFragment
FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.fab_edset);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DialogFragment newEdQua = new createNewEdQua();
newEdQua.show(getActivity().getFragmentManager(), "createNewEdQua");
}
});
// Inflate the layout for this fragment
return view;
}
}
Downloader(receives data and parses in the same class)
public class Downloader extends AsyncTask<Void,Integer,String> {
Context c;
String retredq_url;
ListView listView;
String data;
ArrayList<String> shopl=new ArrayList<String>();//its the ArrayList that we bind to ListView
ProgressDialog pd;
public Downloader(Context c, String retredq_url, ListView listView){
this.c=c;
this.retredq_url=retredq_url;
this.listView=listView;
}
//Before job starts
#Override
protected void onPreExecute(){
super.onPreExecute();
pd=new ProgressDialog(c);
pd.setTitle("Refreshing List");
pd.setMessage("Please Wait...");
pd.show();
}
#Override
protected String doInBackground(Void... params) {
data=downloadData();
return data;
}
#Override
protected void onPostExecute(String s){
super.onPostExecute(s);
pd.dismiss();
if (s !=null){
try{
JSONArray ja=new JSONArray(data);
//JSONObject jo=null;
shopl.clear();//we need to add the data to ArrayList, so clear list first to avoid duplicates
for (int i=0;i<ja.length();i++){
String shops=ja.getJSONObject(i).getString("Qualification")+ ja.getJSONObject(i).get("eq_end_date")+
ja.getJSONObject(i).get("eq_loc_shops");//retrieve the column name into a string
shopl.add(shops);
ArrayAdapter<String> adapter=new ArrayAdapter<String>(c,R.layout.list_item_shopl,shopl);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Snackbar.make(view,shopl.get(i),Snackbar.LENGTH_LONG).show();
}
});
}
} catch (JSONException e) {
Log.e("Downloader", "Error", e);
}
/*
//call the Parser here to parse the JSON after we confirm string writer is not null
Parser p=new Parser(c,s,listView);
p.execute();*/
}else {
Toast.makeText(c,"Unable to download data", Toast.LENGTH_SHORT).show();
}
}
private String downloadData(){
//connect and get a stream
InputStream inputStream=null;
String line=null;
try{
URL url=new URL(retredq_url);
HttpURLConnection con=(HttpURLConnection) url.openConnection();
inputStream=new BufferedInputStream(con.getInputStream());
BufferedReader br=new BufferedReader(new InputStreamReader(inputStream));
StringBuffer sb=new StringBuffer();
if (br !=null){
while ((line=br.readLine()) !=null){
sb.append(line+"\n");
}
}else{return null;}
return sb.toString();
} catch (MalformlocRLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (inputStream !=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
JSON output (Checked with ARC plugin on Chrome)
{"qualifications":[{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"}],"success":1}
A slight difference from what ADM sees (The success message comes first here)
{"success":1,"qualifications":[{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"}]}
I defined the success message while struturing the array in php webservice
I intend use the Downloader class in several tabs for the same purpose(retrieve data from url parse and display in ListView). The urls and data are independent ot each other so I guess it should work...
Going over LogCat and reviewing JSON data obtained from server I was able to figure the problem. My previous code would have worked without any issues if the data was an Array with Objects in it. But I checked and the structure of the JSON was an Object with the Array inside.
What I had to do was get the Object with JSONObject then that Object retrieve the Array with JSONArray.. Like this:
JSONObject jsonObject=new JSONObject(data);
JSONArray jsonArray= jsonObject.getJSONArray("qualifications");
//now this Array has Objects needed
for (int i=0;i<jsonArray.length();i++){
String institution=jsonArray.getJSONObject(i).getString("Qualification");
edqua.add(institution);
}
//provide the ArrayAdapter<> needed
ArrayAdapter<String> adapter=new ArrayAdapter<String>(c,R.layout.list_item_edqua,edqua);
listView.setAdapter(adapter);
It should be in a try-catch block.. It is good to know the structure of the JSON that is expected. I was rather asking for an Array when Object was being offerd, hence the type mis-match error. I also realised that I will be unable to use the same class for different data sources, as the tables are completely. Any suggestions of how to use one class for different data urls will appreciated.
As the ArrayList<String> shows, the list item will be like
Qualification eq_end_date eq_loc_shops as a single string, so initialize the adapter like
adapter = new ArrayAdapter<>(context,android.R.layout.simple_list_item_1,shopl);
Most of your code can be reused but the part which starts from data generated by downloadData() to the JSONArrayObject that your listview needs.
So you can extract these code to an Interface(here called IPreParser)'s method (called JSONArrayObject arrayFromData(String)), like this:
public interface IPreParser{
JSONArrayObject arrayFromData(String data);
}
Your Downloader need hold a reference to IPreParser, and invoke its method in onPostExecute(). And you can initialize this reference by declaring doInBackground(IPreParser).
In anywhere you what download and parse your data, just implement IPreParser, and then execute your downloader with downloader.execute(yourImplementor);
I'm trying to load some images from my server to New App, but i don't have any result :
This is my MainActivity code :
import java.io.InputStream;
import static android.net.Uri.parse;
public class MainActivity extends Activity {
private ImageView iv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new DownloadImageTask((ImageView)findViewById(R.id.loadimg)).execute(getString(R.string.link));
private class DownloadImageTask extends AsyncTask<String,Void,Bitmap>{
private final ImageView bmImage;
ImageView bmImg;
public DownloadImageTask (ImageView bmImage){
this.bmImage=bmImage;
}
protected Bitmap doInBackground (String...urls){
String underplay = urls[0];
Bitmap mIcon11 =null;
try {
InputStream in =new java.net.URL(underplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e){
Log.e("Error",e.getMessage());
e.printStackTrace();
}
return mIcon11 ;
}
}
The Result in emulator is not appear any thing just my Button ?
Add the following dependency to your build.gradle file under app:
dependencies {
compile 'com.squareup.picasso:picasso:2.3.2'
}
Then in your code you can simply load a bitmap or image from a server like so:
Picasso.with(this)
.load(IMAGE_URL)
.into(yourImageView);
Where this is the activity context. IMAGE_URL is the url of the image, example: http://yourapi.com/image_1034.png, and yourImageView is the ImageView, ImageButton, or other Custom View where you want to upload the image into.
Doing it this way is considered best practice, and reduces a lot of the boilerplate code you've written. Try building a scalable app writing AsyncTasks for every time you upload a Bitmap.
In your AsyncTask you need to implement:
protected void onPostExecute(Bitmap icon) {
iv.setImageBitmap(icon)
}
Can you try this code?
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.image);
I have an Android application that loading some information and one picture like a blog, but sometimes I got duplicates picture, I don't know what is the problem, but sometimes it works good.
Someone here can help me ?
Here's the code below:
"endereco" is the URL of picture and "view" is the context that I pass on the class that extends activity"
public void loadImg(final View view , final String endereco){
Thread nova = new Thread()
{
public void run() {
Bitmap img = null;
try
{
URL url = new URL(endereco);
HttpURLConnection conexao = (HttpURLConnection) url.openConnection();
InputStream input = conexao.getInputStream();
img = BitmapFactory.decodeStream(input);
Log.i("Funcionou","Foto: " + endereco);
} catch (Exception ex){
Log.i("Erro",ex.toString());
}
final Bitmap imgAux = img;
handler.post(new Runnable() {
#Override
public void run() {
ImageView imageView = (ImageView) view.findViewById(R.id.txtfoto);
imageView.setImageBitmap(imgAux);
}
});
}
};
nova.start();
nova.currentThread().interrupt();
}
If you are downloading an image from a wbepage or server i wouldnt do it in a thread give it its own AsyncTask it gives you a whole load of methods that allow you to better control over what you are downloading and what to do with it after it has been downloaded.
Check out the Android dev Docs http://developer.android.com/reference/android/os/AsyncTask.html
Just two things, is this a good simple way to grab images? also when i do try it on the android AVD nothing gets displayed on screen as well as in log_cat, no errors or crashes. Here is my code:
public class MainActivity extends Activity {
Bitmap bitmap = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try{
bitmap = getBitmap("https://twimg0-a.akamaihd.net/profile_images/2275552571/image_normal.jpg");
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(bitmap);
}catch(Exception e){
}
}
public Bitmap getBitmap(String bitmapUrl) {
try {
URL url = new URL(bitmapUrl);
return BitmapFactory.decodeStream(url.openConnection().getInputStream());
}catch(Exception ex) {return null;}
}
}
try : http://code.google.com/p/android-imagedownloader/ .
You can download remote images synchronously, Asynchronously, etc. it works really good
ImageDownloader imageDownloader = new ImageDownloader();
imageDownloader.setMode(ImageDownloader.Mode.CORRECT);
ImageView imageView = (ImageView) rowView.findViewById(R.id.picture);
imageView.setLayoutParams(new GridView.LayoutParams(140, 140));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(4, 4, 4, 4);
List<ImageSize> images = this.pictures.get(position).getImages();
imageDownloader.download(images.get(images.size()-3).getSource(), imageView);
It doesn't work because your picture's url starts with HTTPS. Try to use HttpGet. Something like that.
This may be more of a Java question than an Android question, but I'm having trouble retrieving a Bitmap created within an AsyncTask to store in another class (an Activity) so that I can recycle it when I'm done using it.
The AsyncTask creates the Bitmap in doInBackground() and sets it as the bitmap for an ImageView in onPostExecute(), the ImageView being passed in through the constructor. But after completion I want the Bitmap to be accessible in the Activity. The Activity has an ArrayList of ImageViews and another of Bitmaps, but since the AsyncTask creates a new Bitmap, I can't find an easy way to get this new object in the ArrayList of Bitmaps in the Activity. Currently I have it working by passing in the ArrayList along with an index into the list to the AsyncTask constructor, and doInBackground just sets that entry in the array to the newly created bitmap.
I don't like this solution though, because I want to be able to use this AsyncTask for different things, perhaps where the Activity doesn't have an ArrayList of Bitmaps. And I can't simply give the AsyncTask constructor a Bitmap because Java passes the reference by value, and setting it to a new Bitmap object wouldn't allow access for the caller.
How can I do this more elegantly?
Here is the relevant code. Lines not pertaining to this question have been omitted for clarity.
public class LoadCachedImageTask extends AsyncTask<String, Void, Void> {
private Context context;
private ImageView image;
private ArrayList<Bitmap> bitmaps;
int index;
public LoadCachedImageTask(Context context, ImageView image, ArrayList<Bitmap> bitmaps, int index) {
this.context = context;
this.image = image;
this.bitmaps = bitmaps;
this.index = index;
}
protected Void doInBackground(String... urls) {
String url = urls[0];
Bitmap bitmap = null;
// Create the bitmap
File imageFile = new File(context.getCacheDir(), "test");
bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
// Set the bitmap to the bitmap list
bitmaps.set(index, bitmap);
return null;
}
protected void onPostExecute(Void arg) {
// Display the image
image.setImageBitmap(bitmaps.get(index));
}
protected void onCancelled() {
if (bitmaps.get(index) != null) {
bitmaps.get(index).recycle();
bitmaps.set(index, null);
}
}
}
And here's a sample Activity that uses it.
public class SampleActivity extends Activity {
private ArrayList<ImageView> images;
private ArrayList<Bitmap> bitmaps;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
images = new ArrayList<ImageView>();
bitmaps = new ArrayList<Bitmap>();
int numImages = 15;
// Create the images and bitmaps
for (int i = 0; i < numImages; i++) {
images.add(new ImageView(this));
bitmaps.add(null);
}
// Load the bitmaps
for (int i = 0; i < numImages; i++) {
new LoadCachedImageTask(this, images.get(i), bitmaps, i).execute("http://random.image.url");
}
}
}
I haven't tested the above code, so it might not work, but I think it gets the point across.
As I understand it, you're trying to load a large number of bitmaps into a large number of ImageViews asynchronously. I would think this can be done with a single AsyncTask class that you use multiple times for each ImageView.
You're AsyncTask should be something like this:
public class LoadCachedImageTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> mImgView;
public LoadCachedImageTask(ImageView image) {
mImageView = new WeakReference<ImageView>(image);
}
protected Void doInBackground(String... urls) {
if(urls == null || urls.length < 1)
return;
// Create the bitmap
final Bitmap bitmap = BitmapFactory.decodeFile(url);
return bitmap;
}
protected void onPostExecute(Bitmap bmp) {
// Display the image
if(bmp != null) {
final ImageView imageView = (ImageView) mImgView.get();
if(imageView != null) // needed in case the weakreference is removed
imageView.setImageBitmap(bmp);
}
}
Then to fill your array of ImageViews with something like this:
for(ImageView imgView : images) {
(new LoadCachedImageTask<String, Void, Bitmap>)(imgView).execute(getBitmapUrl());
}
The for-loop will iterate through each ImageView reference and pass it to a brand new AsyncTask reference. It will then execute the AsyncTask with the given url to whatever bitmap you need. The asynctask will hold on to a reference of the ImageView so long as the ImageView exists. If, for some reason, your ImageView got destroyed, the bitmap will still load then immediately get thrown away.