ventsi.slav
ventsi.slav

Reputation: 332

HTTP POST request in the UIThread

I`m pretty new in Android development and this is my first application.

The issue probably is very simple but I can`t find a solution.

This application is a simple ImageViewer where the app must connect to a server and depending on some data the server will return a particular image. That image is shown on the screen,click on it will get another. That`s it!

As I can see I can`t run a http post query from the UIThread and must do in the background. However the intent is when the user clicks on the image.

I have a AsyncTask where on create the application will be recognized by the server and they will exchange some data. Im using a library SmartImageViewer (making possible load images from a url). At the moment in my code Im loading the images by a counter++ and so far its working. But I need to get a image url every time when the user clicks it and show it on the screen.

public class MainActivity extends Activity implements OnClickListener {
SmartImageView imageSwitcher;
String SERVER_IP;
String APP_ID;
String DEVICE_ID;
Integer counter = 0;

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

    DB_Queries db = new DB_Queries(getApplicationContext());
    Cursor c = db.getServerIPAndAppId();
    StringBuilder app_id = new StringBuilder();
    StringBuilder server_ip = new StringBuilder();
    if (c.moveToFirst()) {
        do {
            server_ip.append(c.getString(c.getColumnIndex("server_ip")));
            app_id.append(c.getString(c.getColumnIndex("app_id")));
        } while (c.moveToNext());
    }
    db.close();

    SERVER_IP = server_ip.toString();
    APP_ID = app_id.toString();

    ServerConnect connect = new ServerConnect();
    connect.execute("http://" + server_ip + "/");

    SmartImageView image = (SmartImageView) this
            .findViewById(R.id.image_switcher);
    image.setImageUrl("http://localhost/public/albums/1/_(99).jpg");

    imageSwitcher = (SmartImageView) findViewById(R.id.image_switcher);
    imageSwitcher.setOnClickListener(this);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public void onClick(View v) {
    if (v.getId() == imageSwitcher.getId()) {
        counter++;
        Toast.makeText(getApplicationContext(), "Image is clicked",
                Toast.LENGTH_LONG).show();
        SmartImageView image = (SmartImageView) this
                .findViewById(R.id.image_switcher);
        image.setImageUrl("http://localhost/public/albums/1/_("
                + counter + ").jpg");
    }
}

private class ServerConnect extends AsyncTask<String, Void, Void> {

    @Override
    protected Void doInBackground(String... params) {
        String DEVICE_ID = Secure.getString(getContentResolver(),
                Secure.ANDROID_ID);
        DB_Queries db = new DB_Queries(getApplicationContext());
        Cursor c = db.getSettings();
        String APP_ID = null;
        String INSTALLED_AT = null;
        String TOKEN = null;
        if (c.moveToFirst()) {
            do {
                APP_ID = c.getString(c.getColumnIndex("app_id"));
                INSTALLED_AT = c
                        .getString(c.getColumnIndex("installed_at"));
                TOKEN = c.getString(c.getColumnIndex("token"));
            } while (c.moveToNext());
        }

        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(params[0]);
        post.addHeader("Content-type", "application/x-www-form-urlencoded");
        List<NameValuePair> pair = new ArrayList<NameValuePair>();
        pair.add(new BasicNameValuePair("device_id", DEVICE_ID));
        pair.add(new BasicNameValuePair("app_id", APP_ID.toString()));
        pair.add(new BasicNameValuePair("token", TOKEN.toString()));

        try {
            post.setEntity(new UrlEncodedFormEntity(pair));
            HttpResponse response = client.execute(post);
            InputStream is = response.getEntity().getContent();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            StringBuilder str = new StringBuilder();
            String chunk = null;

            while ((chunk = br.readLine()) != null) {
                str.append(chunk);
            }

            final String query_response = str.toString().trim();

            if (query_response.equals("HH@K2i")) {
                Cursor delete = db.updateAuth();
            }

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

        db.close();

        return null;
    }

}

}

Upvotes: 1

Views: 124

Answers (4)

athor
athor

Reputation: 6928

From your code it seems like you are already setting a new image in the onClick method.

If you are wanting to fetch a new URL from the server, and then display the image, you will need to use an asynctask. You can use the same one you have there already if it does what you want. Just start it from the onclick, e.g.

onClick(View v){
new MyAsynctask().execute();
}

Asynctasks have an onPostExecute method, which gets run after the doInbackground method gets run. The onPostExecute gets run on the UI thread. This is where you will set your new image from.

From your doInBackground method, you should return a String which is the URL. This gets passed to the onPostExecute method. Then just do a image.setImageUrl(url);.

Also one more thing, in your onClick you are binding the view every time:

  SmartImageView image = (SmartImageView) this
                .findViewById(R.id.image_switcher);

Do this once in your oncreate, and make image a field. Then you can access image from anywhere in your class. findViewById is an expensive call, so you only want to do it once.

Upvotes: 0

nidhi
nidhi

Reputation: 763

- Its always a good practice to keep the UI work on UI thread and Non-UI work on Non-UI thread, but from Android version Honey Comb it became a law.

- You can do the Network processing work on the background Non-UI thread.

- Use Thread with Handler to solve this task, or use what is called as PainLess Threading in android known as AsyncTask.

- Handler is used along with Thread in order to put the output from the background Non-UI thread to UI thread, similarly when you are using AsyncTask use the doInBackground() method to do the work in background and post its output on UI thread through onPostExecute() method.

Eg:

new AsyncTask<Params, Progress, Result>() {

            @Override
            protected Result doInBackground(Params... params) {

                                // --- Do your network task here

                return null;
            }

            protected void onPostExecute(Result result) {

                                // --- Show the output on UI thread from here

                       };
        };

Upvotes: 2

Yilmaz Guleryuz
Yilmaz Guleryuz

Reputation: 9765

you may also use WebImageView component for such purpose.
here are sample codes (adapted from different places)
WebImageView >>
WebService >>

and here is example project >>

Upvotes: 0

wazaminator
wazaminator

Reputation: 245

it is now impossible to run network operations in the main UIthread. you have to use another thread if you want to be abble to do a HTTP request. as raghunandan said, you should use asynctask for this

Upvotes: 1

Related Questions