How can I store list items when there is no internet connection (data come from server) - java

Regarding
I have a listview contains 4 items 3 of them are texts and fourth is image
all data are on server within json
the code work correctly but when the internet is off all items and list does not appear how can make the list works with and without internet connection
because I add everyday new items to database
and this my code
requestQueue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("allstudents");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject respons = jsonArray.getJSONObject(i);
String id = respons.getString("id");
String name = respons.getString("name");
String info = respons.getString("info");
String img = respons.getString("img");
link = respons.getString("link");
voicelink = respons.getString("voicelink");
listitmes.add(new listitme(id, name, info, img, link, voicelink));
allitems();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", "ERROR");
}
}
);
requestQueue.add(jsonObjectRequest);
}
public void allitems() {
listAdapter lsadapter = new listAdapter(listitmes);
listView.setAdapter(lsadapter);
}
any solution please I searched a lot but no any answer
and I did not find any thing like here on StackOverflow.Com

Look at https://developer.android.com/reference/android/content/SharedPreferences.
With Shared SharedPreferences you can save the list and call it if there is no wifi!

what you can do is:
Save the data that you download, to a file (image)/properties (text) as soon as you receive data from Internet. ()
Display a message in your activity when the data was fetched (e.g. Last Synced : Timestamp).
If you can can't connect to Internet to get the new data, load the data from file/properties.
If you can't connect to Internet and don't have any saved data, display a message (e.g. can't connect to Internet - may be color it to highlight it's an error).
my 2 cents...

Related

How to Get Value from JSON in Firebase Remote Config

I am a novice to Android app development and Firebase.
I want to know how can I get the value (String & Int) in the JSONArray file stored in Firebase Remote Config?
I use Firebase Remote Config with the final goal to compare my app's version code and priority level with the one stored in Firebase Remote Config to determine initiation of App Update notification, but so far I still unable get Remote Config value.
I tried to parse the JSON using Volley (jsonParse in MainActivity2 class), but it also didn't work. (Error bad url)
I have several times tried to implement previous answers, but maybe because of my misunderstanding, all those came to no avail.
Can I declare an array to Firebase Remote config?
Can I get JSONObject from Default value of Firebase Remote Config
FirebaseRemoteConfig getString is empty
I also have read this interesting article about implementing in-app updates notifications with some specific criteria using Remote Config, but unfortunately for me, the codes are written in Kotlin.
https://engineering.q42.nl/android-in-app-updates/
test_json file stored in Firebase Remote Config.
[
{
"versionCode": "1",
"priorityLevel": 2
},
{
"versionCode": "2",
"priorityLevel": 4
},
{
"versionCode": "3",
"priorityLevel": 1
}
]
MainActivity2 class
remoteConfig = FirebaseRemoteConfig.getInstance();
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
.setFetchTimeoutInSeconds(2000)
.build();
remoteConfig.setConfigSettingsAsync(configSettings);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
remoteConfig.fetchAndActivate().addOnCompleteListener(new OnCompleteListener<Boolean>() {
#Override
public void onComplete(#NonNull Task<Boolean> task) {
if (task.isSuccessful()) {
String object = remoteConfig.getString("test_json");
//jsonParse(object);
Gson gson = new GsonBuilder().create();
ArrayList<Lessons> lessons = gson.fromJson(object,
new TypeToken<List<Lessons>>(){}.getType());
} else {
Toast.makeText(MainActivity2.this, "Fetch Failed!", Toast.LENGTH_SHORT).show();
}
}
});
}
});
private void jsonParse(String object) {
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, object, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("condition");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject condition = jsonArray.getJSONObject(i);
String versionCode = condition.getString("versionCode");
int priorityLevel = condition.getInt("priorityLevel");
textView.append(versionCode + "\n\n");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
mQueue.add(request);
}
Lessons class
public class Lessons {
String versionCode;
Int priorityLevel;
}
Any help would be greatly appreciated.
Thank you.
For me worked like that
import com.google.gson.annotations.SerializedName
data class VersionData(
#SerializedName("name")
val name: String,
#SerializedName("age")
var age: Int,
#SerializedName("isFemale")
var isFemale: Boolean
)
init {
remoteConfig.fetchAndActivate()
}
private val _mutableLiveData = MutableLiveData<VersionData>()
val remoteLiveData: LiveData<VersionData> = _mutableLiveData
fun remoteConfiguration() {
val gson = Gson()
val remote = remoteConfig.fetchAndActivate()
remote.addOnSuccessListener{
val stringJson = remoteConfig.getString("json_object_name")
if(stringJson.isNotEmpty()){
val jsonModel = gson.fromJson(stringJson, VersionData::class.java)
_mutableLiveData.value = VersionData(
name = jsonModel.name,
age = jsonModel.age,
isFemale = jsonModel.isFemale
)
}else{
// probably your remote param not exists
}
}
}
so observe in compose
val localLifecycle = LocalLifecycleOwner.current
myViewModel.remoteLiveData.observe(localLifecycle){
Log.d("remoteLiveData", "remoteLiveData: $it")
}
I recommend you use Gson.
data class Lessons(
val versionCode: String? = null,
val priorityLevel: Int? = null
)
and then, use getValue() or getString() to get the data.
val list = Gson().fromJson(getValue("test_json").asString(), Array<Lessons>::class.java)
In my case, getString() also worked.
val list = Gson().fromJson(getString("test_json"), Array<Lessons>::class.java)
This is simpler.

Java Android Studio cannot send ArrayList from another class to MainActivity

I try to add data from my object to ArrayList but it's not work.
This code read data from JSON and add to ArrayList in MySQLConnect.java like this.
private ComputerService computerservice;
public static ArrayList<ComputerService> computerServicesArrayList = new ArrayList<>();
private String URL = "http://10.200.100.10/", GET_URL = "android/get_data.php";
public MySQLConnect(){
main = null;
}
public MySQLConnect(Activity mainA){
main = mainA;
}
public List<ComputerService> getData(){
String url = URL + GET_URL;
StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
showJSON(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(main, error.getMessage().toString(), LENGTH_LONG).show();
}
}
);
RequestQueue requestQueue = Volley.newRequestQueue(main.getApplicationContext());
requestQueue.add(stringRequest);
return computerServicesArrayList;
}
public void showJSON(String response){
String data_mysql = "";
computerServicesArrayList.clear();
try{
JSONObject jsonObject = new JSONObject(response);
JSONArray result = jsonObject.getJSONArray("data");
for(int i=0; i < result.length(); i++){
JSONObject collectData = result.getJSONObject(i);
String id = collectData.getString("id");
String type = collectData.getString("type");
String address = collectData.getString("address");
computerservice = new ComputerService(id, type, address);
computerServicesArrayList.add(computerservice);
}
System.out.println("Size in class MySQLConnect");
System.out.println(computerServicesArrayList.size());
} catch (JSONException e) {
e.printStackTrace();
}
}
The MainActivity.java I show computerServicesArrayList.size() like this.
public static List<ComputerService> computerServicesArrayList;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mySQLConnect = new MySQLConnect(MainActivity.this);
update();
}
public void update(){
computerServicesArrayList = mySQLConnect.getData();
System.out.println("Size in MainActivity");
System.out.println(computerServicesArrayList.size());
}
The output show like this.
Size in MainActivity
0
Size in class MySQLConnect
83
From the code I can print computerServicesArrayList.size() the result is 83 but when I print from MainActivity why it show result 0. How to fix it?
I don't know the Volley framework/classes in detail. But it looks like you are creating an asynchronous request. So your rest-request gets send and when the response comes in your showJSON() method is called.
But you immediatley return the computerServicesArrayList result, which is empty because you don't have your response yet. This is also the reason why the print statement from your MainActivity is executed before the print from your showJSON method.
If you want to wait for the rest-response you have to do synchronous requests.
Maybe this can help you more about Volley and asyn/sync requests:
how to wait the volley response to finish it's work inside intentservice?
Can I do a synchronous request with volley?
But normally you would send an async-request and when you get the response you do your logic (update fields, store something in database, ...).
Your computerServicesArrayList is populated by callback from Volley (new Response.Listener()). This population happens correctly as you have verified. But it does take some time, for the network up/down travel. When your MainActivity's call to mySQLConnect.getData() returns this round trip is not complete yet; so you get an empty list in MainActivity.
The usual solution to this problem is to make the listener call methods in MainActivity. This can be done by making
class MainActivity implements Response.Listener<String> {
/* --- */
#Override
public void onResponse(String response) {
showJSON(response);
}
void showJSON(String response){
// Do the stuff here
}

How to make ListView to refresh after every 5 sec when data come from a server

I have ListView which have data . Data come from server and I want the ListView to update after every 5 sec. How to do this? I am new to android development. Please help me. Here is my code...
protected void showList() {
try {
JSONObject jsonObj = new JSONObject(myJSON);
peoples = jsonObj.getJSONArray(TAG_RESULTS);
for (int i = 0; i < peoples.length(); i++) {
JSONObject c = peoples.getJSONObject(i);
String data = c.getString(TAG_DATA);
final String dataaaa = rcdata.getText().toString().trim();
HashMap<String, String> user_data = new HashMap<String, String>();
user_data.put(TAG_DATA, data);
personList.add(user_data);
}
ListAdapter adapter = new SimpleAdapter(
DataSendActivity.this, personList, R.layout.layout_chat,
new String[]{TAG_DATA},
new int[]{R.id.data}
);
list.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
Use a Handler and its postDelayed method to invalidate the list's adapter as follows:
final Handler handler = new Handler();
handler.postDelayed( new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
handler.postDelayed( this, 5000 );
}
}, 5000 );
You must only update UI in the main (UI) thread.
you can see this question and comment How to refresh/Update Serialize Java Object in sharedPreferences. the user want the same. however it is good to use loader with service for that kind of problem calling asyncTask within minute is not good. also theres is a sample project you can check this https://github.com/Michenux/YourAppIdea also available in playstore which check for data changes from server.

Converting Android Volley Request to iOS NSURL asynchronous request

I have the following method in my Android app which I use for user login/registration.
public void registerUser(final String username, final String email, final String password) {
pDialog.setMessage("Signing Up...");
pDialog.show();
request = new StringRequest(Method.POST, SL_URL, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
pDialog.dismiss();
String[] split = s.split("Config.php");
String after = split[1];
try {
JSONObject jsonObject = new JSONObject(after);
boolean error = jsonObject.getBoolean("error");
if (error) {
String errorMsg = jsonObject.getString("error_msg");
Toast.makeText(getApplicationContext(),
errorMsg, Toast.LENGTH_LONG).show();
} else {
session.setLogin(true, username, email);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("tag", "login");
hashMap.put("username", name);
hashMap.put("password", password);
return hashMap;
}
};
queue.add(request);
}
Now I am writing my app for iOS and trying to replicate this in Swift. So far I have the following code:
let username = usernameTxt.text
let password = passwordTxt.text
let urlPath: String = "***"
let url: NSURL = NSURL(string: urlPath)!
let request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request1.HTTPMethod = "POST"
let stringPost="tag=login&username=" + username! + "&password=" + password! // Key and Value
NSLog(stringPost)
let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)
request1.timeoutInterval = 60
request1.HTTPBody=data
request1.HTTPShouldHandleCookies=false
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
var jsonResult: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
} catch _ {}
})
Now as someone new to iOS development and Swift in general, I have the following questions:
What is the best way to replicate the progressDialog I use in Java in Swift, it must be visible until the request is complete and then it should be dismissed. I'm guessing this should be placed in the completionHandler, however I'm not sure which UI element to use for the progress Dialog.
How do I obtain my response as a String and replicate the behaviour of the split function, and then convert the result of this into a jsonObject like I do in my Java code.
What is the best way to replicate the Toast used to show the error message. I don't think using a dialog which must be closed with a button would be optimal here.
Thank you.
I am also developing Applications for Android and IOS. Here i Answered your three Problems which is faced by me also as a beginner. I hope this would help you.
1) Use MBProgressHUD Link to replicate the progressDialog in Swift .There are two method to show and dismiss the progressDialog:
Use showLoadingHUD() before making HTTP request
private func showLoadingHUD() {
let hud = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
hud.labelText = "Loading..."
}
And hideLoadingHUD() after receiving the response from server
private func hideLoadingHUD() {
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
}
2) you can use Alamofire Link which can handle Network stuff And you can easily obtain response in String.
Example:
self.showLoadingHUD()
Alamofire.request(.GET, data, parameters: nil)
.response { (request, response, data, error) in
print(data) // if you want to check data in debug window.
let Result = NSString(data: data!, encoding: NSUTF8StringEncoding)
Result!.stringByReplacingOccurrencesOfString("\"", withString: "")
if(newResult == "1"){
self.navigationController!.popViewControllerAnimated(true)
JLToast.makeText("Success").show()
}
else if (newResult == "0"){
JLToast.makeText("Failed").show()
}
self.hideLoadingHUD()
3) mankee Toas are used for a purpose of displaying information for short period of time and disappear themselves. Here we can use Android like Toast which is JLToast. Available on github .
JLToast.makeText("Success").show()

Volley request too slow

My app crashes because the images ArrayList is empty when I set the adapter, I figured that out by putting a toast message right after I parse my JSON request, and a Toast message after I initialize my adapter, "second" gets printed first on screen and the app crashes right after, does it have to do with my internet? Or am I missing something, here's my code, thanks!
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_page);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mVolleySingleton = VolleySingleton.getInstance();
mRequestQueue = mVolleySingleton.getRequestQueue();
//First Toast message inside this method
sendAPIRequest();
//after you get the images
mCustomSwipeAdapter = new CustomSwipeAdapter(this, images);
//SECOND TOAST
Toast.makeText(getApplicationContext(), "Second", Toast.LENGTH_LONG).show();
mViewPager.setAdapter(mCustomSwipeAdapter);
mCustomSwipeAdapter.notifyDataSetChanged();
}
public void sendAPIRequest(){
String requestURL = "";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, requestURL, (String) null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
parseJSONResponse(response);
//FIRST TOAST : SHOULD BE CALLED FIRST
Toast.makeText(getApplicationContext(), "First", Toast.LENGTH_LONG).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
mRequestQueue.add(jsonObjectRequest);
}
public void parseJSONResponse(JSONObject response) {
if (response != null || response.length() != 0) {
try {
JSONObject GObject = response.getJSONObject("game");
String name = "N/A";
if (GObject.has("name") && !GObject.isNull("name")) { name = GObject.getString("name"); }
if (GObject.has("screenshots") && !GObject.isNull("screenshots")) {
JSONArray screenShotsArray = GObject.getJSONArray("screenshots");
for (int i = 0; i < screenShotsArray.length(); i++){
JSONObject screenshot = screenShotsArray.getJSONObject(i);
String screenshotURL = screenshot.getString("url");
images.add(screenshotURL);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Does it have to do with my internet? Or am I missing something ...
Both. It happens because you have a race condition.
From what I can make out, your images list is being populated asynchronously by the onResponse callback. Basically, that happens when your app gets the responses to the API requests that it is making. That is going to take at least milliseconds, and possibly seconds (or longer).
But your app is (so you say) crashing soon after the swipe adapter is registered, and the evidence is that the images list has not been populated.
There are three possibilities:
There is something wrong with the requests you are sending which is causing the API requests to not give you any response. (Hypothetically, you could have authentication wrong or something.)
The API requests are taking a long time because of internet connection speed, congestion, or the remote server being slow.
The API requests are taking a short time ... but the adapter registration is even quicker.
If (hypothetically) there is a problem with your requests you will need to fix that. But both of the other scenarios have to be fixed by:
modifying the code that uses the images to work properly if there are no images (yet), or
modifying the code to wait until the image loading has completed before registering the adapter.
Please use this code in your onResponse callback :
//after you get the images
mCustomSwipeAdapter = new CustomSwipeAdapter(this, images);
//SECOND TOAST
Toast.makeText(getApplicationContext(), "Second", Toast.LENGTH_LONG).show();
mViewPager.setAdapter(mCustomSwipeAdapter);
mCustomSwipeAdapter.notifyDataSetChanged();
Volley adds your requests in queue , so better do all the dependent tasks in Response or Error callback only.

Categories

Resources