I want to make a request in my android app when the button is clicked. In Python I could do this like that:
import requests
params = {
'param1':some_string,
'param2':some_int,
'param3':another_string
}
requests.post("https://some.api.com/method/some.method", params=params)
I'd like to do the same in Kotlin when I push the button. I tried tp do this with Fuel and khhtp but didn't succeed much -- app crashed as soon as I pushed the button, responsible for sending request.
UPD: What I used:
AndroidManifest.xml
...
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
...
build.gradle
dependencies {
...
compile 'com.github.jkcclemens:khttp:0.1.0'
...
}
MainActivity.kt
fun request(){
var message = "message"
var uid = "123456" //I wanted to use it as int, but mapOf didn't allow me
var token = "token"
val payload = mapOf("token" to token, "user_id" to uid, "message" to message)
get("https://some.api.com/method/some.method", params=payload)
val popup = Toast.makeText(this,"Message sent!",Toast.LENGTH_LONG)
popup.show()
}
activity_main.xml
<Button
...
android:onClick="request" />
This is the example with khhtp, the one with Fuel is gone.
UPD2. Part of Logcat output:
You just need to look at the stack trace to find the issue. The code is throwing a NetworkOnMainThreadException. This happens when you try to access the network from within Android's main (often called UI) thread. This question have some good answers about this issue, however instead of trying to use AsyncTask make sure to read the documentation of your chosen network library and see how to make the call on a different thread.
I'm not sure if this is the root of your problem but your request method signature should be:
fun request(view: View)
{
}
As other members answered your code is calling network operation on main thread that's why it is crashing . You can avoid this either by using Kotlin Coroutines or by using methods of Anko Library (Which is officially supported by kotlin to simplify things in android). Here i just give a reference for how to do Async call in Anko.
doAsync {
// Call all operation related to network or other ui blocking operations here.
uiThread {
// perform all ui related operation here
}
}
To do it as Kotlin Coroutines, you can refer this answer:-
Kotlin Coroutines the right way in Android
I found the answer, basically what's happening is that you are not able to run internet connections at main thread, To override, add the following to the class where the user is performing network operations:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Reference (https://www.educative.io/edpresso/how-to-fix-androidosnetworkonmainthreadexception-error)
Related
I need to publish my flutter application on the playstore but I received several rejections. My application is used to identify the caller using my database.
I think my problem is that I don't know how to ask permission to become the default application for spam detection. Does anyone have the answer to this?
I've tried to change the permissions i asked in the android manifest, my last version is this :
\<uses-permission android:name="android.permission.READ_PHONE_STATE"/\> \<uses-permission android:name="android.permission.READ_CALL_LOG"/\> \<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/\>
Thank you very much for your help !
In order to screen calls correctly should extend the CallScreeningService class:
class MyCallScreeningService : CallScreeningService() {
override fun onScreenCall(details: Call.Details) {
val callResponse = when {
// Perform checks to determine if the call should be blocked or allowed.
// Return a new CallResponse object with the appropriate response action.
// e.g. CallResponse.reject() to block the call, CallResponse.allow() to allow the call.
else -> null // Return null if the call should be allowed.
}
respondToCall(details, callResponse) // Send the call response to the system.
}
}
You'll still need to register your CallScreeningService implementation in your AndroidManifest.xml file for it to be used by the system. Also, you will need to request the necessary permissions to access call details and control call responses.
Here's a more detailed article about this subject
I am a novice developer. Can someone help me how can I set the image I have the url as the wallpaper title when I click a button? (Kotlin)
You could go through this official documentation for android developers.
Load and display images from the Internet
You need to use WallpaperManager to set the wallpaper, and there's a handy setStream function that takes an InputStream. So instead of having to download the image, you can just open a stream to it, and pass that to WallpaperManager:
button.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
val inputStream = URL("https://cdn2.thecatapi.com/images/oe.jpg").openStream()
WallpaperManager.getInstance(requireContext()).setStream(inputStream)
}
}
Or if you don't want to use coroutines (you should, it's safer since they get cancelled automatically) you could run it in a worker thread
thread(start = true) {
val inputStream = URL("https://cdn2.thecatapi.com/images/oe.jpg").openStream()
WallpaperManager.getInstance(requireContext()).setStream(inputStream)
}
But you need to do one of those things, because you can't do network stuff on the main thread.
You also need the SET_WALLPAPER and INTERNET permissions in your AndroidManifest.xml:
// inside the main <manifest> block
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.INTERNET" />
I'm triying to use a http server inside my android xamarin.forms app. It need to translate this C# code:
var server = WebServer
.Create(url)
.EnableCors()
.WithLocalSession()
.WithStaticFolderAt("c:/web");
var cts = new CancellationTokenSource();
var task = server.RunAsync(cts.Token);
Console.ReadKey(true);
cts.Cancel();
try
{
task.Wait();
} catch (AggregateException)
{
// We'd also actually verify the exception cause was that the task
// was cancelled.
server.Dispose();
}
Now, the problem is that task.Wait() block and make the android App to be non responsive.
Now, I try to put the task into the form app:
type App() =
inherit Application()
let mutable task:System.Threading.Tasks.Task = null
do
let t, form = mainWebForm()
task <- t
base.MainPage <- form
async {
task.Start()
} |> ignore
But it not work on Android. However, in iOS it work fine (ie: the web server start listening)
Creating an async and passing it to ignore does not actually run the code inside the async. It creates a computation that would do something when started, but never starts it. So, if you wanted to use async, your last three lines could be something like this:
async {
task.Start()
} |> Async.Start
However, you also switched from calling task.Wait() to calling task.Start() which should independently also prevent blocking the thread. So you can most likely just call:
task.Start()
Alternatively, if you wanted to do the blocking Wait inside an async queued in background, you would write (but note that there should be absolutely no reason for doing this):
async {
task.Wait()
} |> Async.Start
I'm trying to make an http request in Android, using Kotlin, and I've come across two ways of doing so.
One is the traditional way, using AsyncTask (not really pretty) which I got to work with the following code (just the doInBackground, as the rest of the class seemed unnecessary):
override fun doInBackground(vararg params: Void?): String? {
val url = URL("myUrl")
val httpClient = url.openConnection() as HttpURLConnection
if(httpClient.getResponseCode() == HttpURLConnection.HTTP_OK){
try {
val stream = BufferedInputStream(httpClient.getInputStream())
val data: String = readStream(inputStream = stream)
return data;
} catch (e : Exception) {
e.printStackTrace()
} finally {
httpClient.disconnect()
}
}else{
println("ERROR ${httpClient.getResponseCode()}")
}
return null
}
Now, I've come across a library called Anko, which many here know, and I tried to use its DSL for asynchronous tasks. The thing is, I haven't found a lot of info here about Anko for asynchronous tasks, so I thought I would open a new topic to see if someone could walk me through what I'm doing wrong, or what they think I should do to make it work.
The code I wanted to use is the following:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
async() {
val result = URL("myUrl").readText()
textView1.setText(result)
}
}
I tried to keep it as slim as possible so to minimize any potential mistakes, but I must be doing something wrong here because the code inside the async block is not doing anything, yet the app is not crashing and I'm not getting any exceptions. I've tried debugging it using Intellij IDEA, but after the first line inside the async block it stops the debugging while saying "The application is running". My best guess is that it got hung up somewhere in that first line due to the failed connection, but I don't know.
I've also tried to use the regular URL("myUrl").openConnection() inside the async block, but that hasn't worked either.
Anyway, any help would be deeply appreciated.
The problem textView1 contents not getting updated is caused by calling setText outside of main thread.
The documentation shows a nice example how to properly use async. Take a look at the following adapted version of your code:
async() {
val result = URL("http://stackoverflow.com/").readText()
uiThread {
textView1.text = result
}
}
PS. While not directly related to the question consider using a nicer http client i.e. Retrofit, OkHttp
The problem turned out to be a lot more basic than what I was thinking. It was a problem of compatibility apparently from having an older version of Android Studio running with the new version 1.0.2 of the Kotlin plugin and, again, apparently the function readText was not working properly and therefore I wasn't getting anything from it.
Anyway, I updated Android Studio, with the latest version of Kotlin and it started working fine, although I'm going to see if I can find out what it was that was causing the problem inside readText.
Using Flex 4.5 for Android development, this is the script that should create the database:
private var db:File = File.userDirectory.resolvePath("events.db");
private var conn:SQLConnection;
public function MyDB() {
conn = new SQLConnection();
conn.addEventListener(SQLEvent.OPEN, openHandler);
conn.addEventListener(SQLErrorEvent.ERROR, errorHandler);
conn.open(db, );
}
and I have added this permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
but I get this error:
SQLError: 'Error #3125: Unable to open the database file.', details:'Connection closed.', operation:'open', detailID:'1001'
at flash.data::SQLConnection/internalOpen()
at flash.data::SQLConnection/open()
at com.galleons.util::MyDB()[/Users/luca/Documents/Adobe Flash Builder 4.5/Galleons/src/com/galleons/util/MyDB.as:24]
I know it's an old question, but anyway I was facing the same error and found the cause. If any of the parent directories of File which you pass to SQLConnection.open() does not exist, Flash Player throws an Error with detailID=1001. Simply call dbFile.parent.createDirectory() and the error should be gone.
Similar answer was given on Adobe Forums: SQLError #3125
Have you checked the 'usual suspects'?
file exists
not locked by some other app / stale version of your app
path is correct
At least part of the problem is due to mixing the SQLConnection class's open() method – which is synchronous – with events that are only supposed to be used when opening an asynchronous connection. You would open an asynchronous connection by using the openAsync() method instead of the open() method.
The docs are contradictory in this matter because it is, in fact, possible to listen for SQLEvent.OPEN when opening a synchronous connection. However, notice that the SQLErrorEvent.ERROR listener is not being triggered in your code and you are instead getting a runtime error. The docs make no mention of SQLErrorEvent.ERROR working with a synchronous connection; that does appear to be the case.
It's possible this is an AIR bug, but I suspect mixing synchronous methods with asynchronous event listeners is just a gray area. It's also likely that the problem could be solved if you instead wrap the open() call in a try/catch block, which is the recommended way to catch synchronous errors:
try
{
conn.open(db);
trace("Hey, is that a database?", (db.exists));
}
catch (err:SQLError)
{
trace("Error, database not created:", err.message);
trace("Error details:", err.details);
}