0

I'm getting an error in eclipse stating: "Cannot make a static reference to the non-static method invalidate() from the type View MainActivity.java" and I'm not sure exactly what I can do to resolve this. How can I either make invalidate() static or make View non-static?

SOURCE:

public class MainActivity extends Activity {
    private TextView textView;
    private Handler handler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.TextView01);
        handler = new Handler();
    }

    private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... urls) {
           // perform HTTP client operation
        }

        @Override
        protected void onPostExecute(final String title) {

            handler.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(title);
                        View.invalidate();
                    }
            });
        }
    }

    public void onClick(View view) {
        DownloadWebPageTask task = new DownloadWebPageTask();
        task.execute(new String[] { "http://www.google.com" });

    }
}

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" >

    <Button
        android:id="@+id/readWebpage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Load Webpage" >
    </Button>

    <TextView
        android:id="@+id/TextView01"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Placeholder" >
    </TextView>

</LinearLayout> 

FIRST SOLUTION ATTEMPT:

    public class MainActivity extends Activity {
    private TextView textView;
   // String response;
    public interface Callback {
        void onModifiedTextView(String value);
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.TextView01);
    }

    public void onModifiedTextView(final String title) {
        runOnUiThread(new Runnable() {
            public void run() {
                textView.setText(title);
                textView.invalidate(); // not even necessary
            }
        });
    }

    public class DownloadWebPageTask extends AsyncTask<String, Void, String> {
        public DownloadWebPageTask(MainActivity mainActivity) {
            this.callback = mainActivity;
        }

        private MainActivity callback;

        public DownloadWebPageTask() {
            // TODO Auto-generated constructor stub
        }

        public DownloadWebPageTask(TextView textView) {
            // TODO Auto-generated constructor stub
        }

        @Override
        protected String doInBackground(String... urls) {
            String response = "";

            for (String url : urls) {
                DefaultHttpClient client = new DefaultHttpClient();
                HttpGet httpGet = new HttpGet(url);
                try {
                     Document doc = Jsoup.connect("http://google.com")
                                .userAgent("Mozilla")
                                .get();
                    // get page title
                    String title = doc.title();
                    System.out.println("title : " + title);

                    // get all links
                    Elements links = doc.select("a[href]");
                    for (Element link : links) {

                        // get the value from href attribute
                        System.out.println("\nlink : " + link.attr("href"));
                        System.out.println("text : " + link.text());

                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }


            }
            callback.onModifiedTextView(response);
            return response;
        }

        @Override
        protected void onPostExecute(final String title) {
            callback.onModifiedTextView(title);
        }  
    }

    public void onClick(View view) {

        DownloadWebPageTask task = new DownloadWebPageTask(this);
        task.execute(new String[] { "http://www.google.com" });
    }
}

3 Answers3

4

View is a class. invalidate() is an instance method. You need to call it on an instance.

However, you need to perform UI modifications on the UI thread. I would make your Activity class implement a Callback interface with a method like

public interface Callback {
    void onModifiedTextView(String value);
}

Your class then implements it as

public void onModifiedTextView(final String title) {
    runOnUiThread(new Runnable() {
        public void run() {
            textView.setText(title);
            textView.invalidate(); // not even necessary
        }
    });
}

Then pass that to DownloadWebPageTask. In other words, create a constructor that accepts a Callback instance

public DownloadWebPageTask(Callback callback) {
    this.callback = callback;
}

private Callback callback;

...

protected void onPostExecute(final String title) {
    callback.onModifiedTextView(title);
}  

UI modifications need to be done of the UI thread. That's why you need the runOnUiThread() method.

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • It's actually a suggestion from another issue I'm having... this might shed a bit more light on the situation: http://stackoverflow.com/questions/18728984/cannot-parse-html-data-using-android-jsoup – OverflowCustodian Sep 11 '13 at 14:17
  • @OverflowCustodian That suggestion is bad and mine is just as bad. Create a callback so that the activity calls the invalidate() on the `TextView`, not the `DownloadWebPageTask`. – Sotirios Delimanolis Sep 11 '13 at 14:20
  • Thanks! I attempted to implement it (I updated my source above) but i'm getting an NPE on the line: callback.onModifiedTextView(title); – OverflowCustodian Sep 11 '13 at 14:34
  • @OverflowCustodian You forgot to pass the Activity instance in your constructor, `DownloadWebPageTask task = new DownloadWebPageTask(this);` otherwise the `callback` field is initialized to `null`. Get rid of your no-args constructor. – Sotirios Delimanolis Sep 11 '13 at 14:35
  • I'm afraid I'm not sure exactly what you mean by get rid my no-args constructor – OverflowCustodian Sep 11 '13 at 14:54
  • @OverflowCustodian You have a `DownloadWebPageTask` constructor that doesn't have any parameters. Remove it, you don't need it. This way you also can't confuse which constructor to use as there is only one. – Sotirios Delimanolis Sep 11 '13 at 14:57
0

Have a look at the Java tutorial on Instance and Class Methods, where this is explained thoroughly.

Also, see Another "Cannot make static reference..." Question, Java Error: Cannot make a static reference to the non-static method.

Community
  • 1
  • 1
s.d
  • 4,017
  • 5
  • 35
  • 65
0

invalidate() is a non static method in the VIEW class. you need to invoke that method after creating any instance of View or any of its child . In this case you can try invalidating the textView or root view of your activity.

Ritaban
  • 763
  • 4
  • 8