I am trying to first use the Retrofit to get data to an course. But I figured out that my program is going to the "onFailure" option.
ERROR MESSAGE:
2020-03-07 18:54:04.499 17756-17756/com.example.apirequest I/MainActivity: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
Basically I'm trying to get firstly only the "launch_year" from API https://api.spacexdata.com/v3/launches/
Can someone help me to figure out the reason I can't get it right?
In grade I added:
implementation 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
My codes are bellow:
MainActivity:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Retrofit retrofit = new Retrofit.Builder().
baseUrl(APIService.urlBase)
.addConverterFactory(GsonConverterFactory.create()).
build();
APIService service = retrofit.create(APIService.class);
Call<rocketCatalog> requestModels = service.listCaralog();
requestModels.enqueue(new Callback<rocketCatalog>() {
#Override
public void onResponse(Call<rocketCatalog> call, Response<rocketCatalog> response) {
rocketCatalog catalog = response.body();
for (Rockets rocket : catalog.rocket){
Log.i(TAG,String.format("%s",rocket.getLaunch_date()));
}
}
#Override
public void onFailure(Call<rocketCatalog> call, Throwable t) {
Log.i(TAG,String.format("============= Failure =============="));
}
});
LinearLayoutManager layoutManager = new LinearLayoutManager(MainActivity.this);
}
}
APIService:
public interface APIService {
public static final String urlBase = "https://api.spacexdata.com/v3/";
#GET("launches")
Call<rocketCatalog> listCaralog();
}
rocketCatalog:
public class rocketCatalog {
public List<Rockets> rocket;
public List<Rockets> getRocket() {
return rocket;
}
public void setRocket(List<Rockets> rocket) {
this.rocket = rocket;
}
}
Rockets:
public class Rockets {
String launch_date;
public String getLaunch_date() {
return launch_date;
}
public void setLaunch_date(String launch_date) {
this.launch_date = launch_date;
}
}
Your endpoint returns a List so you need a List type for your response.
public static final String urlBase = "https://api.spacexdata.com/v3/";
#GET("launches")
Call<List<Rockets>> listCaralog();
also make sure the field launch_date in your Rockets Class exists in the response.
with your help I figured it out what was happening.
Indeed I was receiving a List, but I had to re struct, I've made what Mohamed Mohsin suggested and modified my rocketCatalog.java to:
rocketCatalog:
String launch_year;
public String getLaunch_year() {
return launch_year;
}
public void setLaunch_year(String launch_date) {
this.launch_year = launch_date;
}
}
Also, I changed "launch_date" which was wrong to "launch_year"
Thank you so much, again!
Related
I am trying to develop an android app, I am using Retrofit2 for handling all my network stuff and communication with the server.
I have a main activity and I also have login activity.
I am initializing the Retrofit on the main activity and I am trying to send the login activity the retrofit initialized interface and then things got hard.
According to a little research I can't just send the retrofit stuff to the new activity with '.putextra(...)' function.
I will be happy to get some help with that.
My Main Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final UserService userConnection;
userConnection = ApiUtils.getUserService();
Toolbar toolBar = (Toolbar)findViewById(R.id.app_bar);
toolBar.setTitle("Welcome #PlaceHolder");
setSupportActionBar(toolBar);
startActivity(new Intent(MainActivity.this,LoginActivity.class));
// Intent i = new Intent(this, LoginActivity.class);
// i.putExtra("userConnection", (Serializable) userConnection);
// startActivity(i);
ScrollView feed = (ScrollView)findViewById(R.id.feedView);
//LinearLayOut Setup
LinearLayout feed1 = (LinearLayout)findViewById(R.id.feed);
Feed feed2 = new Feed(this,feed1);
feed1 = feed2.getFeed();
//***************************************************//
Call call = userConnection.getResponse();
call.enqueue(new Callback() {
#Override
public void onResponse(Call call, Response response) {
if(response.isSuccessful()){
ResObj resObj = (ResObj) response.body();
if(resObj.getpostID().equals("12Aa")){
//login start main activity
//Intent intent = new Intent(MainActivity.this, MainActivity.class);
// intent.putExtra("username", "tomer");
//startActivity(intent);
Log.e("Error is blabla: ","Yes");
} else {
Toast.makeText(MainActivity.this, "The username or password is incorrect", Toast.LENGTH_SHORT).show();
Log.e("Error is blabla: ",response.toString());
}
Log.e("Error is blabla: ",response.message().toString());
} else {
Toast.makeText(MainActivity.this, "Error! Please try again!", Toast.LENGTH_SHORT).show();
Log.e("Error is blabla: ",response.toString());
}
}
#Override
public void onFailure(Call call, Throwable t) {
Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("Error is blabla: ",t.toString());
}
});
}
}
My Login Activity:
public class LoginActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Intent intent = getIntent();
final UserService userConnection =(UserService)getIntent.getSerializableExtra("userConnection");
Button loginBtn = (Button)findViewById(R.id.loginButton);
EditText emailBox = (EditText) findViewById(R.id.emailBox);
EditText passBox = (EditText) findViewById(R.id.passBox);
final String email = emailBox.getText().toString();
final String password = passBox.getText().toString();
loginBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Call login = userConnection.login(email,password);
login.enqueue(new Callback() {
#Override
public void onResponse(Call call, retrofit2.Response response) {
if(response.isSuccessful())
{
ResObj resObj = (ResObj) response.body();
if(resObj.loginStatus().equals("connected")){
Log.e("Login Status: ","Success");
finish();
}
else {
Log.e("Login Status: ","Wrong Password or Email");
}
}
}
#Override
public void onFailure(Call call, Throwable t) {
Log.e("Login Status: ","Faild To Recieve Server Message");
}
});
}
});
Button registerBtn = (Button)findViewById(R.id.registerButton);
registerBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v){
startActivity(new Intent(LoginActivity.this,RegisterActivity.class));
}
});
}
}
The UserService Interface:
public interface UserService{
#GET("/testDB")
Call<ResObj> getResponse(
);
#POST("/login")
Call<ResObj> login(#Query("userEmail") String userEmail,
#Query("userPassword") String userPassword);
}
The ApiUtiles Class:
public class ApiUtils {
public static final String BASE_URL = "http://**.***.***.***:****";
public static UserService getUserService(){
return RetrofitClient.getClient(BASE_URL).create(UserService.class);
}
}
I will be happy to get solution or guide of how to send retrofit interfaces between activities :)
This is code I got online for sending mail in android studio using the Gmail API, but I need to fixed sender and mail I need to send at the same time as like sender hazem#gmail.com and receiver will be hazem11#gmail.com without showing which account I need to send mail and which mail I should have added to send.
public class MainActivity extends AppCompatActivity {
FloatingActionButton sendFabButton;
EditText edtToAddress, edtSubject, edtMessage, edtAttachmentData;
Toolbar toolbar;
GoogleAccountCredential mCredential;
ProgressDialog mProgress;
private static final String PREF_ACCOUNT_NAME = "accountName";
private static final String[] SCOPES = {
GmailScopes.GMAIL_LABELS,
GmailScopes.GMAIL_COMPOSE,
GmailScopes.GMAIL_INSERT,
GmailScopes.GMAIL_MODIFY,
GmailScopes.GMAIL_READONLY,
GmailScopes.MAIL_GOOGLE_COM
};
private InternetDetector internetDetector;
private final int SELECT_PHOTO = 1;
public String fileName = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
findViewById(R.id.attachment).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Utils.checkPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, SELECT_PHOTO);
} else {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, SELECT_PHOTO);
}
}
});
findViewById(R.id.changeAccount).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Utils.checkPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
startActivityForResult(mCredential.newChooseAccountIntent(), Utils.REQUEST_ACCOUNT_PICKER);
} else {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, SELECT_PHOTO);
}
}
});
sendFabButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getResultsFromApi(view);
}
});
}
I am trying to create this Volley project as my second activity which fetches a JSON feed from Yahoo Pipe and display in a ListView from here. The code works perfectly fine. However, I have encountered these problems:
When I have not turned the Internet on, the activity displays the loading ProgressDialog. However, pressing the Back button on my emulator or actual device does not dismiss the ProgressDialog. The activity did not respond to the Back action.
I tried this code, but it does not work or maybe I'm not doing it right:
#Override
public void onDestroy() {
super.onDestroy();
dismissPd();
}
private void dismissPd() {
if (pd != null) {
pd.dismiss();
pd = null;
}
}
In case of an Internet connection error, how do I display the error message in this activity as a toast?
The following is my code:
public class Trending extends ActionBarActivity {
private String TAG = this.getClass().getSimpleName();
private ListView lstView;
private RequestQueue mRequestQueue;
private ArrayList<NewsModel> arrNews ;
private LayoutInflater lf;
private VolleyAdapter va;
private ProgressDialog pd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.trending);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Intent newActivity3=new Intent();
setResult(RESULT_OK, newActivity3);
lf = LayoutInflater.from(this);
arrNews = new ArrayList<NewsModel>();
va = new VolleyAdapter();
lstView = (ListView) findViewById(R.id.listView);
lstView.setAdapter(va);
mRequestQueue = Volley.newRequestQueue(this);
String url = "http://pipes.yahooapis.com/pipes/pipe.run?_id=giWz8Vc33BG6rQEQo_NLYQ&_render=json";
pd = ProgressDialog.show(this,"Loading...","Please Wait...");
try {
Thread.sleep(2000);
} catch(Exception e) {
}
JsonObjectRequest jr = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i(TAG,response.toString());
parseJSON(response);
va.notifyDataSetChanged();
pd.dismiss();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i(TAG,error.getMessage());
}
});
mRequestQueue.add(jr);
}
#Override
public void onDestroy() {
super.onDestroy();
dismissPd();
}
private void dismissPd() {
if (pd != null) {
pd.dismiss();
pd = null;
}
}
private void parseJSON(JSONObject json){
try {
JSONObject value = json.getJSONObject("value");
JSONArray items = value.getJSONArray("items");
for (int i=0; i<items.length(); i++) {
JSONObject item = items.getJSONObject(i);
NewsModel nm = new NewsModel();
nm.setTitle(item.optString("title"));
nm.setDescription(item.optString("description"));
nm.setLink(item.optString("link"));
nm.setPubDate(item.optString("pubDate"));
arrNews.add(nm);
}
}
catch(Exception e){
e.printStackTrace();
}
}
class NewsModel {
private String title;
private String link;
private String description;
private String pubDate;
void setTitle(String title) {
this.title = title;
}
void setLink(String link) {
this.link = link;
}
void setDescription(String description) {
this.description = description;
}
void setPubDate(String pubDate) {
this.pubDate = pubDate;
}
String getLink() {
return link;
}
String getDescription() {
return description;
}
String getPubDate() {
return pubDate;
}
String getTitle() {
return title;
}
}
class VolleyAdapter extends BaseAdapter {
#Override
public int getCount() {
return arrNews.size();
}
#Override
public Object getItem(int i) {
return arrNews.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder vh;
if (view == null) {
vh = new ViewHolder();
view = lf.inflate(R.layout.row_listview,null);
vh.tvTitle = (TextView) view.findViewById(R.id.txtTitle);
vh.tvDesc = (TextView) view.findViewById(R.id.txtDesc);
vh.tvDate = (TextView) view.findViewById(R.id.txtDate);
view.setTag(vh);
} else {
vh = (ViewHolder) view.getTag();
}
NewsModel nm = arrNews.get(i);
vh.tvTitle.setText(nm.getTitle());
vh.tvDesc.setText(nm.getDescription());
vh.tvDate.setText(nm.getPubDate());
return view;
}
class ViewHolder {
TextView tvTitle;
TextView tvDesc;
TextView tvDate;
}
}
}
try this one then back button is working while dialog is running
pd = ProgressDialog.show(this,"Loading...","Please Wait...");
pd.setCancelable(true);
By use asynctask you write code like this way
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = ProgressDialog.show(ctx, null, "fetching ...");
pd.setCancelable(true);
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
try {
//fetch response from internet and process here
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
pd.cancel();
//do next action here
super.onPostExecute(result);
}
You have to execute the JSON part of the code in AsyncTask.
Define doInBackground to return a String type. From doInBackground, handle the errors, like internet error or json error and accordingly return a suitable error message "internet error" or "json error".
This error will be available as input to onPostExecute (results). In onPostExecute, you can run a Switch Statement to handle each of the conditions. If "internet error", then pd.dismiss() and do a toast.
For a working version of the code, you can refer here...
How we can execute a javascript function and get a return value in our android appplication ?
We want to execute a javascript on a button press event, we need to pass parameters to the script and get return values, So we are using "WebChromeClient" to implement this,
But we got Exception is "SyntaxError: Parse error at undefined:1"
Following is my code
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
public class FirstTab extends Activity
{
private WebView webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.regis);
try{
webView = (WebView) findViewById(R.id.webView1);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new MyWebChromeClient());
String customHtml = "<html><head><title>iSales</title><script type=\"text/javascript\"> function fieldsOnDelete(){ var x=123; return \"JIJO\"; } </script></head><body>hi</body></html>";
webView.loadData(customHtml, "text/html","UTF-8");
}catch(Exception e)
{
Log.v("JAC LOG",e.toString());
}
}
public void onResume()
{
super.onResume();
final Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try{
webView.loadUrl("javascript:alert(javascript:fieldsOnDelete())");
}
catch(Exception e)
{
Log.v("JAC LOG",e.toString());
}
}
});
}
final class MyWebChromeClient extends WebChromeClient {
#Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.v("LogTag", message);
result.confirm();
return true;
}
}
}
you can use mWebView.loadUrl("javascript:checkName"); to call the method...
Then you can use addJavascriptInterface() to add a Java object to the Javascript environment. Have your Java script call a method on that Java object to supply its "return value".
EDIT1: Or you can use following hack:
Add this Client to your WebView:
final class MyWebChromeClient extends WebChromeClient {
#Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
}
Now in your java script call do:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Now in the onJsAlert call "message" will contain the returned value.
Edit2:
So it does not work if we call javascript method just after call to load the URL since the page loads take time. So I created a test program to test that...
Following is my html file (named test.html) store in the assets folder:
<html>
<head>
<script language="javascript">
function fieldsOnDelete(message) {
alert("i am called with " + message);
window.myjava.returnValue(message + " JIJO");
}
</script>
<title>iSales android</title>
</head>
<body></body>
</html>
</body>
</html>
Following is my java class that would get that i would add to java script as interface and it would receive the return value:
public class MyJS {
public void returnValue(String string){
Log.d(this.getClass().getSimpleName(), string);
}
}
And following is my activity class:
public class CheckWebView extends Activity {
private WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_check_web_view);
webView = (WebView) findViewById(R.id.webview);
webView.setWebChromeClient(new WebChromeClient() {
#Override
public void onConsoleMessage(String message, int lineNumber,
String sourceID) {
super.onConsoleMessage(message, lineNumber, sourceID);
Log.d(this.getClass().getCanonicalName(), "message " + message
+ " :::line number " + lineNumber + " :::source id "
+ sourceID);
}
#Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
// TODO Auto-generated method stub
onConsoleMessage(consoleMessage.message(),
consoleMessage.lineNumber(), consoleMessage.sourceId());
Log.d(this.getClass().getCanonicalName(), "message::::: "
+ consoleMessage.message());
return super.onConsoleMessage(consoleMessage);
}
});
webView.addJavascriptInterface(new MyJS(), "myjava");
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setPluginsEnabled(true);
webView.getSettings().setAllowFileAccess(true);
webView.loadUrl("file:///android_asset/test.html");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_check_web_view, menu);
return true;
}
/* (non-Javadoc)
* #see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
webView.loadUrl("javascript:fieldsOnDelete('name');");
return super.onOptionsItemSelected(item);
}
}
The key here is that there should be some time interval between the call to load html file from assets folder and the call to javascript:method. Here I am calling it from onOptionsItemSelected and it is working fine.. if I move the webView.loadUrl("javascript:fieldsOnDelete('name');"); to the end of the onCreate() method the it shows the error that it can not find fieldsOnDelete() method...
Hope it Helps...
EDIT3:
Replace following in your code
webView.loadUrl("javascript:alert(javascript:fieldsOnDelete())");
with
webView.loadUrl("javascript:alert(fieldsOnDelete())");
and try...
In Android KitKat there is a new method evaluateJavascript that has a callback for a return value. The callback returns a JSON value, object or array depending on what you return.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// In KitKat+ you should use the evaluateJavascript method
mWebView.evaluateJavascript(javascript, new ValueCallback<String>() {
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onReceiveValue(String s) {
JsonReader reader = new JsonReader(new StringReader(s));
// Must set lenient to parse single values
reader.setLenient(true);
try {
if(reader.peek() != JsonToken.NULL) {
if(reader.peek() == JsonToken.STRING) {
String msg = reader.nextString();
if(msg != null) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
}
}
} catch (IOException e) {
Log.e("TAG", "MainActivity: IOException", e);
} finally {
try {
reader.close();
} catch (IOException e) {
// NOOP
}
}
}
});
}
You can see a full example here: https://github.com/GoogleChrome/chromium-webview-samples/tree/master/jsinterface-example
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
web = (WebView) findViewById(R.id.webview1);
web.setWebChromeClient(new MyWebChromeClient());
web.addJavascriptInterface(new DemoJavaScriptInterface(), "temp_1");
web.loadUrl("file:///android_asset/temp_1.html");
}
}
final class DemoJavaScriptInterface {
private Handler mHandler = new Handler();
WebView web;
DemoJavaScriptInterface() {
}
public void clickOnAndroid() {
mHandler.post(new Runnable() {
public void run() {
web.loadUrl("javascript:init();");
}
});
}
}
final class MyWebChromeClient extends WebChromeClient {
private static final String LOG_TAG = "WebViewDemo";
#Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.e(LOG_TAG, message);
result.confirm();
return true;
}
}
Try to write this line
web = (WebView) findViewById(R.id.webview1);
web.setWebChromeClient(new MyWebChromeClient());
web.getSettings().setJavaScriptEnabled(true);
web.addJavascriptInterface(new DemoJavaScriptInterface(), "temp_1");
web.loadUrl("file:///android_asset/temp_1.html");
[2]: Both Elements are coming from html file ,when going to click on "Click It" nothing happens instead of displaying xml data that i want