简体   繁体   中英

HTTPPost within Runnable Crashes

This problem piss me off. I am re-using this same code that works on other project/class but not on my current project. All I did was change the variable (POST values and EditText names). But it did not work.

import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;


import android.app.Activity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import android.preference.PreferenceManager;
import android.content.SharedPreferences;

public class LoginActivity extends BaseActivity implements OnClickListener {
    private SharedPreferences settings;
    private EditText email;
    private EditText epassword;
    private EditText password2;
    private EditText mobile;
    private EditText eusername;
    private EditText txtMessage;
    private Button sendBtn;
    //private String uriAPI =getString(R.string.loginurl);

    protected static final int REFRESH_DATA = 0x00000001;


    Handler mHandler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            switch (msg.what)
            {
            case REFRESH_DATA:
                String result = null;
                if (msg.obj instanceof String)
                    result = (String) msg.obj;
                if (result != null)
                    Toast.makeText(LoginActivity.this, result, Toast.LENGTH_LONG).show();


                break;
            }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        eusername = (EditText) findViewById(R.id.musername);
        epassword = (EditText) findViewById(R.id.mpassword);
        sendBtn = (Button) findViewById(R.id.loginnow_btn);

        if (sendBtn != null) {
            sendBtn.setOnClickListener(this);
        }

    }

    @Override
    public void onClick(View v)

    {
        //Toast.makeText(LoginActivity.this,"Button Clicked!", Toast.LENGTH_LONG).show();
        if (v == sendBtn)
        {
            String err= null;
            final String dusername = eusername.getEditableText().toString();
            final String dpassword = epassword.getEditableText().toString();

            Toast.makeText(LoginActivity.this, dusername, Toast.LENGTH_SHORT).show();
            if (dusername.isEmpty())
            {

                err = err + "Please Enter Email";
            }
            else if (dpassword.isEmpty()) {
                err = err + "Please enter password";
            }

            if (err==null) {

                Toast.makeText(LoginActivity.this, "About to run sendPostRunnable", Toast.LENGTH_LONG).show();      
                Thread gt = new Thread(new sendPostRunnable(dusername,dpassword));
                gt.start();
            }
            else {
                Toast.makeText(LoginActivity.this, err, Toast.LENGTH_LONG).show();              
            }
        }
    }

    class sendPostRunnable implements Runnable
    {
        String strTxt = null;
        String eusername = null;
        String epassword = null;
        public sendPostRunnable(String username, String password)
        {
            this.epassword = password;
            this.eusername = username;

            Toast.makeText(LoginActivity.this,this.eusername, Toast.LENGTH_SHORT).show();
            Toast.makeText(LoginActivity.this,this.epassword, Toast.LENGTH_SHORT).show();
        }

        @Override
        public void run()
        {
            Toast.makeText(LoginActivity.this,"SendPostDataToInternet entrance", Toast.LENGTH_LONG).show();
            String result = sendPostDataToInternet(eusername, epassword);
            //Toast.makeText(LoginActivity.this,"SendPostDataToInternet running", Toast.LENGTH_LONG).show();
            //Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();
            mHandler.obtainMessage(REFRESH_DATA, result).sendToTarget();
            //Toast.makeText(LoginActivity.this,"Obtainmessaged", Toast.LENGTH_LONG).show();
        }


    }

    private String sendPostDataToInternet(String username, String password)
    {
        String uriAPI =getString(R.string.loginurl);
        HttpPost httpRequest = new HttpPost(uriAPI);

        List<NameValuePair> params = new ArrayList<NameValuePair>();

        params.add(new BasicNameValuePair("email", username));
        params.add(new BasicNameValuePair("password", password));
        Toast.makeText(LoginActivity.this,"TT", Toast.LENGTH_LONG).show();
        try

        {



            httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

            HttpResponse httpResponse = new DefaultHttpClient()
                    .execute(httpRequest);

            if (httpResponse.getStatusLine().getStatusCode() == 200) {

                String strResult = EntityUtils.toString(httpResponse
                        .getEntity());

                return strResult;
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }


}

During debugging I realize the problem lies on the

gt.start();

Here is a log

03-06 02:39:35.134: E/AndroidRuntime(1916): FATAL EXCEPTION: Thread-140
03-06 02:39:35.134: E/AndroidRuntime(1916): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
03-06 02:39:35.134: E/AndroidRuntime(1916):     at android.os.Handler.<init>(Handler.java:197)
03-06 02:39:35.134: E/AndroidRuntime(1916):     at android.os.Handler.<init>(Handler.java:111)
03-06 02:39:35.134: E/AndroidRuntime(1916):     at android.widget.Toast$TN.<init>(Toast.java:324)
03-06 02:39:35.134: E/AndroidRuntime(1916):     at android.widget.Toast.<init>(Toast.java:91)
03-06 02:39:35.134: E/AndroidRuntime(1916):     at android.widget.Toast.makeText(Toast.java:238)
03-06 02:39:35.134: E/AndroidRuntime(1916):     at com.pbd.b_prototype.LoginActivity$sendPostRunnable.run(LoginActivity.java:162)
03-06 02:39:35.134: E/AndroidRuntime(1916):     at java.lang.Thread.run(Thread.java:856)

The problem is in the way you're calling sendPostDataToInternet() . You're creating a new thread to do the network communications, which is good:

Thread gt = new Thread(new sendPostRunnable(dusername,dpassword));

But you need a Looper in this thread for the handler. The short answer is to create your handler in a Looper , the documentation is pretty clear but it could be written thusly:

public class LooperThread extends Thread {

    @Override
    public void run() {
        Looper.prepare();

        Handler mHandler = new Handler()
        {
            @Override
            public void handleMessage(Message msg)
            {
                 // handle your message here
            }
        };
        Looper.loop();
    }
}

Your looper will handle the response from the server and can act on the data accordingly.

When your runnable is finished, post the Toast back to the UI thread using post.. or runOnUiThread:

LoginActivity.this.runOnUiThread(new Runnable() { Toast.makeText( ... ); });

Or, declare your ui controls as final and post to them from the async task:

final EditText someControl;
....

....
In async Task:
....
someControl.post(new Runnable() { Toast.makeText(...); });

You should convert your code so that an AsyncTask is used instead of implementing Runnable -- with an AsyncTask you can provide real time updates using the publishProgress(...) methods in conjunction with onProgressUpdate(...) Finally, you can use onPostExecute(...) to wrap things up and make calls upon the UI.

The example on

http://developer.android.com/reference/android/os/AsyncTask.html

Is relatively complete so I won't repost it here.

On a different note, you need to clean up your HTTP connections, make sure you call consumeContent() on your HTTP entities (every last one of them...).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM