Swipe to refresh

907 Views Asked by At

I'm new to Java and Android Development.

Stuck with implementing "SWIPE TO REFRESH" in android. I'm trying to access a method that is in other class. I will highlight the error that android studio gives in blockquote. Help is much appreciated.

MainActivity.java

import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;

public class MainActivity extends AppCompatActivity{

private String TAG = MainActivity.class.getSimpleName();

private SwipeRefreshLayout swipeRefreshLayout;
private ProgressDialog pDialog;
private ListView lv;

// URL to get contacts JSON
private static String url = "http://hooman.com/hoo.php";

ArrayList<HashMap<String, String>> contactList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    contactList = new ArrayList<>();
    swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swiperefresh);


    lv = (ListView) findViewById(R.id.list);
    swipeRefreshLayout.setOnRefreshListener(this);
    swipeRefreshLayout.post(new Runnable() {
                                @Override
                                public void run() {
                                    swipeRefreshLayout.setRefreshing(true);
                                    doInBackground();
                                }
                            }
    );
    new GetContacts().execute();
}
@Override
public void onRefresh() {
    doInBackground();
}
/**
 * Async task class to get json by making HTTP call
 */
private class GetContacts extends AsyncTask<Void, Void, Void> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // Showing progress dialog
        pDialog = new ProgressDialog(MainActivity.this);
        pDialog.setMessage("Please wait...");
        pDialog.setCancelable(false);
        pDialog.show();

    }

    @Override
    protected Void doInBackground(Void... arg0) {
        HttpHandler sh = new HttpHandler();
        swipeRefreshLayout.setRefreshing(true);
        // Making a request to url and getting response
        String jsonStr = sh.makeServiceCall(url);

        Log.e(TAG, "Response from url: " + jsonStr);

        if (jsonStr != null) {
            try {

                JSONArray contacts = new JSONArray(jsonStr);

                // looping through All Contacts
                for (int i = 0; i < contacts.length(); i++) {
                    JSONObject c = contacts.getJSONObject(0);

                    String kw = c.getString("kw");
                    String kva = c.getString("kva");
                    String pf = c.getString("pf");

                    // tmp hash map for single contact
                    HashMap<String, String> contact = new HashMap<>();

                    // adding each child node to HashMap key => value
                    contact.put("kw", kw);
                    contact.put("kva", kva);
                    contact.put("pf", pf);

                    // adding contact to contact list
                    contactList.add(contact);

                    // stopping swipe refresh
                    swipeRefreshLayout.setRefreshing(false);
                }
            } catch (final JSONException e) {
                Log.e(TAG, "Json parsing error: " + e.getMessage());
                Log.e("JSON Parser", "Error parsing data " + e.toString());
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(),
                                "Json parsing error: " + e.getMessage(),
                                  Toast.LENGTH_LONG)
                                .show();
                    }
                });

            }
        } else {
            Log.e(TAG, "Couldn't get json from server.");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(),
                            "Couldn't get json from server. Check LogCat for possible errors!",
                            Toast.LENGTH_LONG)
                            .show();
                    // stopping swipe refresh
                    swipeRefreshLayout.setRefreshing(false);
                }
            });

        }

        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
        // Dismiss the progress dialog
        if (pDialog.isShowing())
            pDialog.dismiss();
        /**
         * Updating parsed JSON data into ListView
         * */
        ListAdapter adapter = new SimpleAdapter(
                MainActivity.this, contactList,
                R.layout.list_item, new String[]{"kw", "kva",
                "pf"}, new int[]{R.id.kw,
                R.id.kva, R.id.pf});

        lv.setAdapter(adapter);
    }

}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<ListView
    android:id="@+id/list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</android.support.v4.widget.SwipeRefreshLayout>

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:id="@+id/kw"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="2dip"
        android:paddingTop="6dip"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="16sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/kva"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="2dip"
        android:textColor="@color/colorAccent" />

    <TextView
        android:id="@+id/pf"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#5d5d5d"
        android:textStyle="bold" />
</LinearLayout>

Thanks in advance.

2

There are 2 best solutions below

0
On BEST ANSWER

Firstly, you have circular dependencies. The AsyncTask cannot reference swipeRefreshLayout view in the Activity, and the Activity would need an instance of the task before you could call task.doInBackground() (which you should never do any way). Only need to use execute() and very rarely execute().get()

What you could do is override the postExecute function within the activity

swipeRefreshLayout.post(new Runnable() {
        @Override
        public void run() {
            swipeRefreshLayout.setRefreshing(true);

            // Showing progress dialog
            final ProgressDialog pDialog = new ProgressDialog(MainActivity.this);
            pDialog.setMessage("Please wait...");
            pDialog.setCancelable(false);
            pDialog.show();

            contactList.clear();

            new GetContacts() {

              @Override
              protected void onPostExecute(Void result) {
                  // stopping swipe refresh
                  swipeRefreshLayout.setRefreshing(false);

                  // Dismiss the progress dialog
                  if (pDialog.isShowing())
                      pDialog.dismiss();

                  ListAdapter adapter = new SimpleAdapter(
                  MainActivity.this, contactList, R.layout.list_item, 
                  new String[]{"kw", "kva", "pf"}, 
                  new int[]{R.id.kw,R.id.kva, R.id.pf});

                  lv.setAdapter(adapter);  

                }
            }.execute();
        }
    }
);
0
On

First things first, do not call UI Views from doInBackground() method.

you can call them from onPreExcute() method or onPostExecute method.

but since AsyncTask is in other file, you cannot directly call them as well.


Since you want to execute AsyncTask code on refreshing SwipeRefreshLayout.

There are 2 ways :

1st : Make AsyncTask class an inner class of the calling activity. (Only useful if you are going to use this Asynctask only in this activity.

2nd: Implement callbacks into the AsyncTask How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?

3 : Use Volley / Retrofit(Library). (Since you are only Calling an API and getting JSON data, they use "Other thread than main threads" by default and have built in JSON support too.