Search code examples
androidnetwork-programmingandroid-asynctaskandroid-mvp

Getting problems when using MVP model to write a "login" App


I tried to write a "login" App using MVP model. And I use WAMP to build up my server. I'm sure that my php documents have no problem.

Here is the structure of my App: enter image description here

And here are the files:

User.java

package com.example.android.login.mvp;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.example.android.login.R;
import com.example.android.login.mvp.bean.User;
import com.example.android.login.mvp.presenter.UserLoginPresenter;
import com.example.android.login.mvp.view.IUserLoginView;

public class UserLoginActivity extends AppCompatActivity implements IUserLoginView
{


    private EditText mEtUsername, mEtPassword;
    private Button mBtnLogin, mBtnClear;
    private ProgressBar mPbLoading;

    private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this);

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

        initViews();
    }

    private void initViews()
    {
        mEtUsername = (EditText) findViewById(R.id.id_et_username);
        mEtPassword = (EditText) findViewById(R.id.id_et_password);

        mBtnClear = (Button) findViewById(R.id.id_btn_clear);
        mBtnLogin = (Button) findViewById(R.id.id_btn_login);

        mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading);

        mBtnLogin.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mUserLoginPresenter.login();
            }
        });

        mBtnClear.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mUserLoginPresenter.clear();
            }
        });
    }


    @Override
    public String getUserName()
    {
        return mEtUsername.getText().toString();
    }

    @Override
    public String getPassword()
    {
        return mEtPassword.getText().toString();
    }

    @Override
    public void clearUserName()
    {
        mEtUsername.setText("");
    }

    @Override
    public void clearPassword()
    {
        mEtPassword.setText("");
    }

    @Override
    public void showLoading()
    {
        mPbLoading.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading()
    {
        mPbLoading.setVisibility(View.GONE);
    }

    @Override
    public void toMainActivity(User user)
    {
        Toast.makeText(this, user.getUsername() +
                " login success , to MainActivity", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailedError()
    {
        Toast.makeText(this,
                "login failed", Toast.LENGTH_SHORT).show();
    }
}

IUserBiz.java

package com.example.android.login.mvp.biz;

/**
 * Created by zhy on 15/6/19.
 */
public interface IUserBiz
{
    public void login(String username, String password, OnLoginListener loginListener);
}

OnLoginListener.java

package com.example.android.login.mvp.biz;

import com.example.android.login.mvp.bean.User;

/**
 * Created by zhy on 15/6/19.
 */
public interface OnLoginListener
{
    void loginSuccess(User user);

    void loginFailed();
}

UserBiz.java

package com.example.android.login.mvp.biz;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.example.android.login.R;
import com.example.android.login.mvp.bean.User;

/**
 * Created by zhy on 15/6/19.
 */
public class UserBiz extends AppCompatActivity implements IUserBiz
{
    private User user;
    private OnLoginListener loginListener;

    @Override
    public void login(final String username, final String password, final OnLoginListener mLoginListener)
    {
        user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setStatus(0);
        loginListener = mLoginListener;

        LoginAsyncTask task = new LoginAsyncTask();
        String test1Url = getString(R.string.server_ip)+"/server/login.php";
        task.execute(test1Url);
    }

    /**
     * Update the UI with the given earthquake information.
     */
    private void updateUi(User mUser) {
        if (mUser.getStatus()==1)
        {
            loginListener.loginSuccess(user);
        } else
        {
            loginListener.loginFailed();
        }
    }

    private class LoginAsyncTask extends AsyncTask<String, Void, User> {

        @Override
        protected User doInBackground(String... urls) {
            if (urls.length < 1 || urls[0] == null) {
                return null;
            }
            // Perform the HTTP request for earthquake data and process the response.
            User mUser = Utils.fetchEarthquakeData(urls[0],user);
            return mUser;
        }

        @Override
        protected void onPostExecute(User result) {
            if(result==null){
                return;
            }
            updateUi(result);
        }
    }

}

Utils.java

package com.example.android.login.mvp.biz;

import android.text.TextUtils;
import android.util.Log;

import com.example.android.login.mvp.bean.User;

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;

/**
 * Utility class with methods to help perform the HTTP request and
 * parse the response.
 */
public final class Utils {

    /** Tag for the log messages */
    public static final String LOG_TAG = Utils.class.getSimpleName();

    /**
     * Query the USGS dataset and return an {@link User} object to represent a single earthquake.
     */
    public static User fetchEarthquakeData(String requestUrl, User user) {
        // Create URL object
        URL url = createUrl(requestUrl);

        // Perform HTTP request to the URL and receive a JSON response back
        String jsonResponse = null;
        try {
            jsonResponse = makeHttpRequest(url, user);
        } catch (IOException e) {
            Log.e(LOG_TAG, "Error closing input stream", e);
        }

        // Extract relevant fields from the JSON response and create an {@link User} object
        User earthquake = extractFeatureFromJson(jsonResponse);

        // Return the {@link User}
        return earthquake;
    }

    /**
     * Returns new URL object from the given string URL.
     */
    private static URL createUrl(String stringUrl) {
        URL url = null;
        try {
            url = new URL(stringUrl);
        } catch (MalformedURLException e) {
            Log.e(LOG_TAG, "Error with creating URL ", e);
        }
        return url;
    }

    /**
     * Make an HTTP request to the given URL and return a String as the response.
     */
    private static String makeHttpRequest(URL url, User user) throws IOException {
        String jsonResponse = "";

        // If the URL is null, then return early.
        if (url == null) {
            return jsonResponse;
        }

        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        try {
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setReadTimeout(10000 /* milliseconds */);
            urlConnection.setConnectTimeout(15000 /* milliseconds */);
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            String params="app_user_name="+user.getUsername()+'&'+"app_password="+user.getPassword();
            OutputStream out=urlConnection.getOutputStream();
            out.write(params.getBytes());//post提交参数
            out.flush();
            out.close();

            // If the request was successful (response code 200),
            // then read the input stream and parse the response.
            if (urlConnection.getResponseCode() == 200) {
                inputStream = urlConnection.getInputStream();
                jsonResponse = readFromStream(inputStream);
            } else {
                Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode());
            }
        } catch (IOException e) {
            Log.e(LOG_TAG, "Problem retrieving the earthquake JSON results.", e);
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return jsonResponse;
    }

    /**
     * Convert the {@link InputStream} into a String which contains the
     * whole JSON response from the server.
     */
    private static String readFromStream(InputStream inputStream) throws IOException {
        StringBuilder output = new StringBuilder();
        if (inputStream != null) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
            BufferedReader reader = new BufferedReader(inputStreamReader);
            String line = reader.readLine();
            while (line != null) {
                output.append(line);
                line = reader.readLine();
            }
        }
        return output.toString();
    }

    /**
     * Return an {@link User} object by parsing out information
     * about the first earthquake from the input earthquakeJSON string.
     */
    private static User extractFeatureFromJson(String earthquakeJSON) {
        // If the JSON string is empty or null, then return early.
        if (TextUtils.isEmpty(earthquakeJSON)) {
            return null;
        }

        try {
            JSONObject baseJsonResponse = new JSONObject(earthquakeJSON);

            // If there are results in the features array
            if (baseJsonResponse.length() > 0) {

                int status = baseJsonResponse.getInt("status");

                // Create a new {@link User} object
                User user=new User();
                user.setStatus(status);
                return user;
            }
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Problem parsing the earthquake JSON results", e);
        }
        return null;
    }
}

UserLoginPresenter.java

package com.example.android.login.mvp.presenter;

import com.example.android.login.mvp.bean.User;
import com.example.android.login.mvp.biz.IUserBiz;
import com.example.android.login.mvp.biz.OnLoginListener;
import com.example.android.login.mvp.biz.UserBiz;
import com.example.android.login.mvp.view.IUserLoginView;

/**
 * Created by zhy on 15/6/19.
 */
public class UserLoginPresenter {
    private IUserBiz userBiz;
    private IUserLoginView userLoginView;

    public UserLoginPresenter(IUserLoginView userLoginView) {
        this.userLoginView = userLoginView;
        this.userBiz = new UserBiz();
    }

    public void login() {
        userLoginView.showLoading();
        userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
            @Override
            public void loginSuccess(final User user) {
                userLoginView.toMainActivity(user);
                userLoginView.hideLoading();
            }

            @Override
            public void loginFailed() {
                userLoginView.showFailedError();
                userLoginView.hideLoading();
            }
        });
    }

    public void clear() {
        userLoginView.clearUserName();
        userLoginView.clearPassword();
    }


}

IUserLoginView.java

package com.example.android.login.mvp.view;

import com.example.android.login.mvp.bean.User;

/**
 * Created by zhy on 15/6/19.
 */
public interface IUserLoginView
{
    String getUserName();

    String getPassword();

    void clearUserName();

    void clearPassword();

    void showLoading();

    void hideLoading();

    void toMainActivity(User user);

    void showFailedError();

}

UserLoginActivity.java

package com.example.android.login.mvp;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.example.android.login.R;
import com.example.android.login.mvp.bean.User;
import com.example.android.login.mvp.presenter.UserLoginPresenter;
import com.example.android.login.mvp.view.IUserLoginView;

public class UserLoginActivity extends AppCompatActivity implements IUserLoginView
{


    private EditText mEtUsername, mEtPassword;
    private Button mBtnLogin, mBtnClear;
    private ProgressBar mPbLoading;

    private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this);

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

        initViews();
    }

    private void initViews()
    {
        mEtUsername = (EditText) findViewById(R.id.id_et_username);
        mEtPassword = (EditText) findViewById(R.id.id_et_password);

        mBtnClear = (Button) findViewById(R.id.id_btn_clear);
        mBtnLogin = (Button) findViewById(R.id.id_btn_login);

        mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading);

        mBtnLogin.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mUserLoginPresenter.login();
            }
        });

        mBtnClear.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mUserLoginPresenter.clear();
            }
        });
    }


    @Override
    public String getUserName()
    {
        return mEtUsername.getText().toString();
    }

    @Override
    public String getPassword()
    {
        return mEtPassword.getText().toString();
    }

    @Override
    public void clearUserName()
    {
        mEtUsername.setText("");
    }

    @Override
    public void clearPassword()
    {
        mEtPassword.setText("");
    }

    @Override
    public void showLoading()
    {
        mPbLoading.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading()
    {
        mPbLoading.setVisibility(View.GONE);
    }

    @Override
    public void toMainActivity(User user)
    {
        Toast.makeText(this, user.getUsername() +
                " login success , to MainActivity", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailedError()
    {
        Toast.makeText(this,
                "login failed", Toast.LENGTH_SHORT).show();
    }
}

But I got something wrong like this: enter image description here

I have no idea about it. How to solve it?


Solution

  • the issue is here this.userBiz = new UserBiz();

    UserBiz is an activity so activity gets their context when they are being started with Intent (by OS) but creating an object of an activity will not provide any contenxt hence the null exception at

      @Override
        public void login(final String username, final String password, final OnLoginListener mLoginListener)
        {
            user = new User();
            user.setUsername(username);
            user.setPassword(password);
            user.setStatus(0);
            loginListener = mLoginListener;
    
            LoginAsyncTask task = new LoginAsyncTask();
            String test1Url = getString(R.string.server_ip)+"/server/login.php";
            // no context here due to new UserBiz
            // getString required context
            task.execute(test1Url);
        }
    

    Solution : you can use enums or static final constants to avoid context and also would be wise to substitute UserBiz as separate class instead of an activity