I have a private app for work installed on a phone running Android 8 and a tablet running Android 8.1 and it's working fine on both but when I installed it on my new phone running Android 10, it gives me an JSON error. The rest of the app works fine but it's showing a JSONObject as null. Is this just a setting or has something changed with Android 10?
#Override
protected Void doInBackground(Void... arg0) {
HttpJsonParser httpJsonParser = new HttpJsonParser();
Map<String, String> httpParams = new HashMap<>();
JSONObject jsonObject = httpJsonParser.makeHttpRequest(GET_VERSION_URL, "GET", httpParams);
if (jsonObject != null) { // <- Returns fine on Android 8.1 but not Android 10
try {
...
} catch (final JSONException e) {
...
}
} else {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this,"Error.", Toast.LENGTH_LONG).show(); // <-Goes to this everytime
}
});
}
return null;
}
I don't think your problem is with JSONObject itself. More probably is has to do with changes and restrictions with how HTTP calls are made in Android. Some changes are introduced with newer version like:
Requiring all request to be made using HTTPS.
Deprecation of old HTTP Clients like Apache's one.
Some of those restrictions can be bypassed enabling a config flag, this will give you more time to update your implementation. But the recommended approach is to follow the new guidelines as stop using deprecated stuff.
Go here, and check the "Behavior changes for all apps" and "Behavior changes for apps targeting API XX+" pages for the version of Android where your app doesn't work. That will give you a clue about if this is the problem.
Related
I have a question. Some device has codename.
For example:
Redmi K20Pro has codename "raphael"
Samsung A02S has codename "A02q"
Bluestack 5 (my device need change android codename) has codename: "taimen"
...
So how I can change this codename through adb shell with root access, or terminal on mobile device, or something like this?
Cause I want to make my virtual device as real as possible. Some applications can only use login on previously logged in devices, but cannot log in on the second device except with the intervention of IT support. So I want to create a perfect 2nd instance to sign in on that device, making that device a perfect version of the first device.
private void writeSessionOS(String str) throws Exception {
final boolean isRooted = CommonUtils.isRooted(this.crashlyticsCore.getContext());
writeSessionPartFile(str, SESSION_OS_TAG, new CodedOutputStreamWriteAction() { // from class: com.crashlytics.android.core.CrashlyticsController.21
#Override // com.crashlytics.android.core.CrashlyticsController.CodedOutputStreamWriteAction
public void writeTo(CodedOutputStream codedOutputStream) throws Exception {
SessionProtobufHelper.writeSessionOS(codedOutputStream, Build.VERSION.RELEASE, Build.VERSION.CODENAME, isRooted);
}
});
writeFile(str, "SessionOS.json", new FileOutputStreamWriteAction() { // from class: com.crashlytics.android.core.CrashlyticsController.22
#Override // com.crashlytics.android.core.CrashlyticsController.FileOutputStreamWriteAction
public void writeTo(FileOutputStream fileOutputStream) throws Exception {
fileOutputStream.write(new JSONObject(new HashMap<String, Object>() { // from class: com.crashlytics.android.core.CrashlyticsController.22.1
{
put("version", Build.VERSION.RELEASE);
put("build_version", Build.VERSION.CODENAME);
put("is_rooted", Boolean.valueOf(isRooted));
}
}).toString().getBytes());
}
});
}
Any idea about this?
I'm rewriting some of my code after years of stepping away from it, and wanted to ask the community for a push in the right direction from a more modern architecture perspective (if one is needed).
--
One of the things my app does is send JSON data (maybe about 15-20 key-value pairs in total) upon clicking a button in the app.
I wrote the code to use Volley inside an AsyncTask to interact with my API.
I created a progress bar that would basically block the UI with a loading spinner until the data sent out and then got a confirm back from the API.
When that is done, it would dismiss and the user could carry on, but in a few rare cases some of my users complain the data is slow and the progress bar takes a while to go away (a full 5-10 minutes, which is interesting) or just never goes away at all.
I believe I erred here in creating the spinner, so I will do away with that and have it run in the background.
I found myself more confused than ever at the seemingly various approaches and frameworks out there for interacting with APIs that weren't as available years ago, so wanted to ask here in hopes of getting a more unified / community-based response.
My Question
Is it still a modern/ideal/commonly found approach to
Create a class that extends AsyncTask<type here>
Add your your onPreExecute, doInBackground(String... params), onPostExecute, declarations and code
Use code like this to interact with your API using Volley:
My old code is below, and unfortunately I've wrote many tasks like this (practically every case of where I need to make an API call has this large bloated file that follows the format below).
#Override
protected String doInBackground(String... params)
{
RequestQueue mmRequestQueue = Volley.newRequestQueue(context);
StringRequest mmyReq = new StringRequest(Method.POST, "ENDPOINT HERE", new Response.Listener<String>()
{
#Override
public void onResponse(String rawResponse) {
JSONObject response = null;
try {
response = new JSONObject(rawResponse);
//do stuff with response here..
}
catch(Exception ex)
{
//logging code here
}
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
//handle my stuff here
}
}
)
{
#Override
protected Map<String, String> getParams()
{
Map<String, String> params = new HashMap<String, String>();
//put my params here, for example:
params.put("helloworld", val1);
params.put("helloworld2", val2);
return params;
}
};
mmRequestQueue.add(mmyReq);
try {
Thread.sleep(1000); //not sure why this is even here anymore, I can't recall if this was intentional or not, maybe it was to show the progress bar which I won't be using anymore anyway?
} catch (InterruptedException e) {
}
return "";
}
I have an android app with Azure Mobile Services and implemented Offline Sync. The app works well but when syncing data it seems not to complete so there is always a few rows on tables which have not synced?
Anyone have any ideas what the problem might be. I believe that on the next try it would finish where it left off or am I wrong?
Thanks in advance
The app works well but when syncing data it seems not to complete so there is always a few rows on tables which have not synced?
I would recommend you use fiddler to capture the network traces when handling the sync operations.
For Incremental Sync, the request would be as follows:
Get https://{your-app-name}.azurewebsites.net/tables/TodoItem?$filter=(updatedAt%20ge%20datetimeoffset'2017-11-03T06%3A56%3A44.4590000%2B00%3A00')&$orderby=updatedAt&$skip=0&$top=50&__includeDeleted=true
For opting out of incremental sync, you would retrieve all records without the filter updatedAt.
Get https://{your-app-name}.azurewebsites.net/tables/TodoItem?$skip=0&$top=50&__includeDeleted=true
Note: If there are too many items, the SDK would send multiple requests to pull all items that match your given query from the associated remote table. Also, you need to make sure you specify the includeDeleted() in your query.
In summary, you need to make sure that all items could be retrieved via the above requests. Additionally, if the pull operation has pending local updates, then the pull operation would first execute a push operation. So, I assume that you could catch the exception when calling pull operation for handling the conflict resolution.
Bruce's answer is fine but I used a slightly different method without the need to use fiddler.
I change my connection from this
mClient = new MobileServiceClient("[AZUREWEBSITE]", cntxall);
mClient.setAndroidHttpClientFactory(new MyOkHttpClientFactory());
To this
mClient = new MobileServiceClient("[AZUREWEBSITE]", cntxall).withFilter(
new ServiceFilter() {
#Override
public ListenableFuture<ServiceFilterResponse> handleRequest(ServiceFilterRequest request, NextServiceFilterCallback nextServiceFilter) {
// Get the request contents
String url = request.getUrl();
String content = request.getContent();
if (url != null) {
Log.d("Request URL:", url);
}
if (content != null) {
Log.d("Request Content:", content);
}
// Execute the next service filter in the chain
ListenableFuture<ServiceFilterResponse> responseFuture = nextServiceFilter.onNext(request);
Futures.addCallback(responseFuture, new FutureCallback<ServiceFilterResponse>() {
#Override
public void onFailure(Throwable e) {
Log.d("Exception:", e.getMessage());
}
#Override
public void onSuccess(ServiceFilterResponse response) {
if (response != null && response.getContent() != null) {
Log.d("Response Content:", response.getContent());
}
}
});
return responseFuture;
}
}
);
This is the logging method for Azure connections and shows the request in the log.
We are using crashlyticsDidDetectCrashDuringPreviousExecution to detect java crashes and report them to our BI systems, but our app is mostly C++ and we are using crashlytics NDK, we can't find anything similar to crashlyticsDidDetectCrashDuringPreviousExecution.
Is there any way that we can actually detect an NDK crash when the app starts?
thanks
Oded
Mike from Fabric here.
Currently, there isn't a way to do this within Fabric or the SDK for an NDK crash.
NOTE: This works on older version only (Crashlytics 2.6.7 and CrashlyticsNDK 1.1.6)
I'm also looking for a solution for this.
We currently found a partial solution. I'm not sure how good it is, it's definitely not official, plus it's asynchronic (which we're trying to overcome by looping), but it's the best solution I found and it seems like it's working
Fabric.with(this, new Crashlytics.Builder().core(core.build()).build(), new CrashlyticsNdk(), new Crashlytics());
if (!userLeft) { // our handling to fix bug, see explanation below
new Thread(new Runnable() {
#Override
public void run() {
SessionEventData crashEventData = null;
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000); // in ms
} catch (InterruptedException e) { }
crashEventData = CrashlyticsNdk.getInstance().getCrashEventData();
if (crashEventData != null)
{
// there was a crash!
// crash timestamp can be found at crashEventData.timestamp
break;
}
}
}
}).start();
}
Explaination for userLeft:
We had some bug with reporting crash for users that exited app, and this is the solution for that. We set this flag to true, and save it on the device (SharedPreferences). We do it on our main activity (which extends NativeActivity), on finish() func.
Code:
#Override
public void finish() {
// set some key such as USER_LEFT to TRUE
super.finish();
}
After that, just get that USER_LEFT value, assign it into userLeft param, and set it back to false on SharedPerferences.
Any insights about this solution?
What's a good pattern to use, when I want to
create the proxy entity -- works
set some properties -- works
send to GAE -- works
if the "save" button is clicked again
proxy = requestContext.edit(proxy_returned_from_server_above); // fails with "A request is already in progress"
I have spent a few days, trying many options, without any luck.
Is there a sample android app or suggestions? something that used GAE, android and GWT requestfactory?
using a "new" requestContext as some suggest does not work.
I faced the same problem. So i figured it out that you have to build the MyRequestFactory every time before call its method.
//Build this every time
MyRequestFactory requestFactory = Util.getRequestFactory(mContext,
MyRequestFactory.class);
//
final CustomRequest request = requestFactory
.customRequest();
request.queryImages().fire(
new Receiver<List<ImageProxy>>() {
#Override
public void onFailure(ServerFailure error) {
String erro = "Failure: "
+ error.getMessage();
Log.e("fail",
erro);
}
#Override
public void onSuccess(List<ImageProxy> result) {
db.importImage(result);
}
});