bej*_*rge 2308 java android android-networking networkonmainthread
我在为RssReader运行我的Android项目时遇到错误.
码:
URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
Run Code Online (Sandbox Code Playgroud)
它显示以下错误:
android.os.NetworkOnMainThreadException
Run Code Online (Sandbox Code Playgroud)
我该如何解决这个问题?
Mic*_*tor 2491
当应用程序尝试在其主线程上执行网络操作时,抛出此异常.运行您的代码AsyncTask:
class RetrieveFeedTask extends AsyncTask<String, Void, RSSFeed> {
private Exception exception;
protected RSSFeed doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
} catch (Exception e) {
this.exception = e;
return null;
} finally {
is.close();
}
}
protected void onPostExecute(RSSFeed feed) {
// TODO: check this.exception
// TODO: do something with the feed
}
}
Run Code Online (Sandbox Code Playgroud)
如何执行任务:
在MainActivity.java文件中,您可以在oncreate()方法中添加此行
new RetrieveFeedTask().execute(urlToRssFeed);
Run Code Online (Sandbox Code Playgroud)
不要忘记将其添加到AndroidManifest.xml文件中:
<uses-permission android:name="android.permission.INTERNET"/>
Run Code Online (Sandbox Code Playgroud)
小智 647
您应该几乎总是在线程上运行网络操作或作为异步任务.
但是,如果您愿意接受后果,则可以删除此限制并覆盖默认行为.
加:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Run Code Online (Sandbox Code Playgroud)
在你的班上,
和
在android manifest.xml文件中添加此权限:
<uses-permission android:name="android.permission.INTERNET"/>
Run Code Online (Sandbox Code Playgroud)
后果:
您的应用程序将(在互联网连接不稳定的区域)变得无响应并锁定,用户感知速度缓慢并且必须执行强制终止,并且您冒着活动管理器杀死您的应用并告诉用户该应用已停止的风险.
Android提供了一些关于良好编程实践的好建议,以设计响应能力:http: //developer.android.com/reference/android/os/NetworkOnMainThreadException.html
Dr.*_*iji 410
我用新的方法解决了这个问题Thread.
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
Run Code Online (Sandbox Code Playgroud)
Ste*_*vie 157
接受的答案有一些重要的缺点.除非你真的知道自己在做什么,否则不建议使用AsyncTask进行网络连接.一些不利方面包括:
executeOnExecutor方法并提供备用执行程序).当在Gingerbread上同时执行时,在ICS上串行运行时运行正常的代码可能会中断,例如,如果您有无意的执行顺序依赖项.如果您想避免短期内存泄漏,在所有平台上都有明确定义的执行特性,并且有基础来构建非常强大的网络处理,您可能需要考虑:
Service或者IntentService替代,也许使用a PendingIntent来通过Activity的onActivityResult方法返回结果.下行方面:
AsyncTask,虽然没有您想象的那么多IntentService等效Service实现来轻松控制此操作,也许就像这样.向上方面:
onActivityResult方法接收下载结果AsyncTask进行Activity,但如果用户上下文切换出应用程序以进行电话呼叫,系统可能会在上载完成之前终止应用程序.它不太可能杀死具有活动的应用程序Service.IntentService(如上面链接的那个),您可以通过控制并发级别来控制并发级别Executor.您可以IntentService非常轻松地实现在单个后台线程上执行下载.
第1步:创建一个IntentService以执行下载.您可以通过Intentextra 来告诉它要下载什么,并将其传递PendingIntent给用于将结果返回到Activity:
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
public class DownloadIntentService extends IntentService {
private static final String TAG = DownloadIntentService.class.getSimpleName();
public static final String PENDING_RESULT_EXTRA = "pending_result";
public static final String URL_EXTRA = "url";
public static final String RSS_RESULT_EXTRA = "url";
public static final int RESULT_CODE = 0;
public static final int INVALID_URL_CODE = 1;
public static final int ERROR_CODE = 2;
private IllustrativeRSSParser parser;
public DownloadIntentService() {
super(TAG);
// make one and re-use, in the case where more than one intent is queued
parser = new IllustrativeRSSParser();
}
@Override
protected void onHandleIntent(Intent intent) {
PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT_EXTRA);
InputStream in = null;
try {
try {
URL url = new URL(intent.getStringExtra(URL_EXTRA));
IllustrativeRSS rss = parser.parse(in = url.openStream());
Intent result = new Intent();
result.putExtra(RSS_RESULT_EXTRA, rss);
reply.send(this, RESULT_CODE, result);
} catch (MalformedURLException exc) {
reply.send(INVALID_URL_CODE);
} catch (Exception exc) {
// could do better by treating the different sax/xml exceptions individually
reply.send(ERROR_CODE);
}
} catch (PendingIntent.CanceledException exc) {
Log.i(TAG, "reply cancelled", exc);
}
}
}
Run Code Online (Sandbox Code Playgroud)
第2步:在清单中注册服务:
<service
android:name=".DownloadIntentService"
android:exported="false"/>
Run Code Online (Sandbox Code Playgroud)
步骤3:从Activity调用服务,传递PendingResult对象,Service将使用该对象返回结果:
PendingIntent pendingResult = createPendingResult(
RSS_DOWNLOAD_REQUEST_CODE, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), DownloadIntentService.class);
intent.putExtra(DownloadIntentService.URL_EXTRA, URL);
intent.putExtra(DownloadIntentService.PENDING_RESULT_EXTRA, pendingResult);
startService(intent);
Run Code Online (Sandbox Code Playgroud)
第4步:处理onActivityResult中的结果:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RSS_DOWNLOAD_REQUEST_CODE) {
switch (resultCode) {
case DownloadIntentService.INVALID_URL_CODE:
handleInvalidURL();
break;
case DownloadIntentService.ERROR_CODE:
handleError(data);
break;
case DownloadIntentService.RESULT_CODE:
handleRSS(data);
break;
}
handleRSS(data);
}
super.onActivityResult(requestCode, resultCode, data);
}
Run Code Online (Sandbox Code Playgroud)
包含一个完整的工作Android的工作室/ gradle这个项目一个项目的GitHub可以在这里.
ven*_*iac 72
使用Service或AsyncTask
另请参阅Stack Overflow问题:
android.os.NetworkOnMainThreadException从Android发送电子邮件
hen*_*343 71
在另一个线程上执行网络操作
例如:
new Thread(new Runnable(){
@Override
public void run() {
// Do network action in this function
}
}).start();
Run Code Online (Sandbox Code Playgroud)
并将其添加到AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
Run Code Online (Sandbox Code Playgroud)
San*_*eep 58
您使用以下代码禁用严格模式:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
Run Code Online (Sandbox Code Playgroud)
建议不要这样做:使用AsyncTask界面.
Dhr*_*dal 51
基于网络的操作无法在主线程上运行.您需要在子线程上运行所有基于网络的任务或实现AsyncTask.
这是您在子线程中运行任务的方式:
new Thread(new Runnable(){
@Override
public void run() {
try {
// Your implementation goes here
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Run Code Online (Sandbox Code Playgroud)
Vai*_*iya 46
把你的代码放在里面:
new Thread(new Runnable(){
@Override
public void run() {
try {
// Your implementation
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Run Code Online (Sandbox Code Playgroud)
要么:
class DemoTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... arg0) {
//Your implementation
}
protected void onPostExecute(Void result) {
// TODO: do something with the feed
}
}
Run Code Online (Sandbox Code Playgroud)
Ole*_*siy 43
使用Android Annotations是一种选择.它允许您在后台线程中简单地运行任何方法:
// normal method
private void normal() {
doSomething(); // do something in background
}
@Background
protected void doSomething()
// run your networking code here
}
Run Code Online (Sandbox Code Playgroud)
请注意,虽然它提供了简单性和可读性的好处,但它有其缺点.
Ash*_*hok 40
该错误是由于在主线程中执行长时间运行操作,您可以使用AsynTask或Thread轻松解决问题.您可以检查此库AsyncHTTPClient以获得更好的处理.
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
@Override
public void onStart() {
// Called before a request is started
}
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// Called when response HTTP status is "200 OK"
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
// Called when response HTTP status is "4XX" (for example, 401, 403, 404)
}
@Override
public void onRetry(int retryNo) {
// Called when request is retried
}
});
Run Code Online (Sandbox Code Playgroud)
Kap*_*ats 39
您不应该在主线程(UI线程)上执行任何耗时的任务,例如任何网络操作,文件I/O或SQLite数据库操作.因此,对于这种操作,您应该创建一个工作线程,但问题是您不能直接从工作线程执行任何与UI相关的操作.为此,你必须使用Handler并传递Message.
为了简化这些东西,Android提供各种方式,如AsyncTask,AsyncTaskLoader,CursorLoader或IntentService.因此,您可以根据您的要求使用其中任何一种.
siv*_*ag1 38
如果您正在编写AsyncTask内联而不是作为类扩展,并且除此之外,如果需要从中获取响应AsyncTask,则可以使用如下get()方法.
RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();
Run Code Online (Sandbox Code Playgroud)
(从他的例子.)
rha*_*vey 27
对我来说就是这样:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="10" />
Run Code Online (Sandbox Code Playgroud)
我正在测试我的应用程序的设备是4.1.2,这是SDK版本16!
确保目标版本与Android目标库相同.如果您不确定目标库是什么,请右键单击您的项目 - > 构建路径 - > Android,它应该是勾选的那个.
此外,正如其他人所提到的,包括访问Internet的正确权限:
<uses-permission android:name="android.permission.INTERNET"/>
Run Code Online (Sandbox Code Playgroud)
dhi*_*ran 23
在您的活动中使用此功能
btnsub.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//Initialize soap request + add parameters
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME1);
//Use this to add parameters
request.addProperty("pincode", txtpincode.getText().toString());
request.addProperty("bg", bloodgroup.getSelectedItem().toString());
//Declare the version of the SOAP request
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
envelope.dotNet = true;
try {
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
//this is the actual part that will call the webservice
androidHttpTransport.call(SOAP_ACTION1, envelope);
// Get the SoapResult from the envelope body.
SoapObject result = (SoapObject) envelope.getResponse();
Log.e("result data", "data" + result);
SoapObject root = (SoapObject) result.getProperty(0);
// SoapObject s_deals = (SoapObject) root.getProperty(0);
// SoapObject s_deals_1 = (SoapObject) s_deals.getProperty(0);
//
System.out.println("********Count : " + root.getPropertyCount());
value = new ArrayList<Detailinfo>();
for (int i = 0; i < root.getPropertyCount(); i++) {
SoapObject s_deals = (SoapObject) root.getProperty(i);
Detailinfo info = new Detailinfo();
info.setFirstName(s_deals.getProperty("Firstname").toString());
info.setLastName(s_deals.getProperty("Lastname").toString());
info.setDOB(s_deals.getProperty("DOB").toString());
info.setGender(s_deals.getProperty("Gender").toString());
info.setAddress(s_deals.getProperty("Address").toString());
info.setCity(s_deals.getProperty("City").toString());
info.setState(s_deals.getProperty("State").toString());
info.setPinecode(s_deals.getProperty("Pinecode").toString());
info.setMobile(s_deals.getProperty("Mobile").toString());
info.setEmail(s_deals.getProperty("Email").toString());
info.setBloodgroup(s_deals.getProperty("Bloodgroup").toString());
info.setAdddate(s_deals.getProperty("Adddate").toString());
info.setWaight(s_deals.getProperty("waight").toString());
value.add(info);
}
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent(getApplicationContext(), ComposeMail.class);
//intent.putParcelableArrayListExtra("valuesList", value);
startActivity(intent);
}
}).start();
}
});
Run Code Online (Sandbox Code Playgroud)
Nov*_*vak 23
只是明确说明一些事情:
主线程基本上是UI线程.
所以说你不能在主线程中进行网络操作意味着你不能在UI线程中进行网络操作,这意味着你不能在*runOnUiThread(new Runnable() { ... }*其他线程内的块中进行网络操作.
(我只是想知道为什么我在主线程以外的其他地方得到了这个错误.这就是为什么;这个线程帮助了;希望这个评论会帮助其他人.)
ama*_*eep 21
如果执行任务花费太多时间,则由于在主线程上执行任何繁重的任务而发生此异常.
为避免这种情况,我们可以使用线程或执行器来处理它
Executors.newSingleThreadExecutor().submit(new Runnable() {
@Override
public void run() {
// You can perform your task here.
}
});
Run Code Online (Sandbox Code Playgroud)
KG6*_*ZVP 18
关于这个问题已经有很多很好的答案,但是自从这些答案发布以来,已经出现了许多优秀的图书馆.这是一种新手指南.
我将介绍几个用于执行网络操作的用例和一个或两个解决方案.
通常Json可以是XML或其他东西
假设您正在编写一个应用程序,用户可以跟踪股票价格,利率和货币汇率.您找到一个类似于以下内容的Json API:
http://api.example.com/stocks //ResponseWrapper<String> object containing a list of Srings with ticker symbols
http://api.example.com/stocks/$symbol //Stock object
http://api.example.com/stocks/$symbol/prices //PriceHistory<Stock> object
http://api.example.com/currencies //ResponseWrapper<String> object containing a list of currency abbreviation
http://api.example.com/currencies/$currency //Currency object
http://api.example.com/currencies/$id1/values/$id2 //PriceHistory<Currency> object comparing the prices of the first currency (id1) to the second (id2)
Run Code Online (Sandbox Code Playgroud)
对于具有多个端点的API而言,这是一个很好的选择,并允许您声明ReST端点,而不必像其他库(如ion或Volley)那样单独编写它们.(网站:http://square.github.io/retrofit/)
你如何在财务API中使用它?
的build.gradle
将这些行添加到模块级别buid.gradle:
implementation 'com.squareup.retrofit2:retrofit:2.3.0' //retrofit library, current as of September 21, 2017
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' //gson serialization and deserialization support for retrofit, version must match retrofit version
Run Code Online (Sandbox Code Playgroud)
FinancesApi.java
public interface FinancesApi {
@GET("stocks")
Call<ResponseWrapper<String>> listStocks();
@GET("stocks/{symbol}")
Call<Stock> getStock(@Path("symbol")String tickerSymbol);
@GET("stocks/{symbol}/prices")
Call<PriceHistory<Stock>> getPriceHistory(@Path("symbol")String tickerSymbol);
@GET("currencies")
Call<ResponseWrapper<String>> listCurrencies();
@GET("currencies/{symbol}")
Call<Currency> getCurrency(@Path("symbol")String currencySymbol);
@GET("currencies/{symbol}/values/{compare_symbol}")
Call<PriceHistory<Currency>> getComparativeHistory(@Path("symbol")String currency, @Path("compare_symbol")String currencyToPriceAgainst);
}
Run Code Online (Sandbox Code Playgroud)
FinancesApiBuilder
public class FinancesApiBuilder {
public static FinancesApi build(String baseUrl){
return new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(FinancesApi.class);
}
}
Run Code Online (Sandbox Code Playgroud)
FinancesFragment片段
FinancesApi api = FinancesApiBuilder.build("http://api.example.com/"); //trailing '/' required for predictable behavior
api.getStock("INTC").enqueue(new Callback<Stock>(){
@Override
public void onResponse(Call<Stock> stockCall, Response<Stock> stockResponse){
Stock stock = stockCall.body();
//do something with the stock
}
@Override
public void onResponse(Call<Stock> stockCall, Throwable t){
//something bad happened
}
}
Run Code Online (Sandbox Code Playgroud)
如果您的API要求发送API密钥或其他标头(如用户令牌等),则Retrofit可以轻松实现(请参阅此详细答案以获取详细信息:https://stackoverflow.com/a/42899766/1024412).
假设你正在构建一个"情绪天气"应用程序,它可以查找用户的GPS位置并检查该区域的当前温度并告诉他们心情.这种类型的应用程序不需要声明API端点; 它只需要能够访问一个API端点.
对于这种类型的访问,这是一个很棒的库.
请阅读msysmilu的好答案(/sf/answers/1999191911/)
Volley也可用于ReST API,但由于需要更复杂的设置,我更喜欢使用Square上的Retrofit(http://square.github.io/retrofit/)
假设您正在构建社交网络应用,并希望加载朋友的个人资料照片.
的build.gradle
将此行添加到模块级别buid.gradle:
implementation 'com.android.volley:volley:1.0.0'
Run Code Online (Sandbox Code Playgroud)
ImageFetch.java
Volley需要比Retrofit更多的设置.您需要创建一个这样的类来设置RequestQueue,ImageLoader和ImageCache,但它不是太糟糕:
public class ImageFetch {
private static ImageLoader imageLoader = null;
private static RequestQueue imageQueue = null;
public static ImageLoader getImageLoader(Context ctx){
if(imageLoader == null){
if(imageQueue == null){
imageQueue = Volley.newRequestQueue(ctx.getApplicationContext());
}
imageLoader = new ImageLoader(imageQueue, new ImageLoader.ImageCache() {
Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
return imageLoader;
}
}
Run Code Online (Sandbox Code Playgroud)
user_view_dialog.xml
将以下内容添加到布局xml文件中以添加图像:
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/profile_picture"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
app:srcCompat="@android:drawable/spinner_background"/>
Run Code Online (Sandbox Code Playgroud)
UserViewDialog.java
将以下代码添加到onCreate方法(Fragment,Activity)或构造函数(Dialog):
NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());
Run Code Online (Sandbox Code Playgroud)
Square的另一个优秀图书馆.请访问该网站以获取一些很好的例子:http://square.github.io/picasso/
Nab*_*bin 16
简单来说,
不要在UI线程中进行网络工作
例如,如果您执行HTTP请求,那就是网络操作.
解:
办法:
把你所有的作品都放进去
run() 新线程的方法doInBackground() AsyncTask类的方法.但:
当您从Network响应中获取某些内容并希望在您的视图中显示它时(如在TextView中显示响应消息),您需要返回到UI线程.
如果你不这样做,你会得到ViewRootImpl$CalledFromWrongThreadException.
如何?
onPostExecute()方法更新视图runOnUiThread()在run()方法内部调用方法和更新视图.msy*_*ilu 10
虽然上面有一个巨大的解决方案池,但没有人提到com.koushikdutta.ion:https://github.com/koush/ion
它也是异步的,使用起来非常简单:
Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
@Override
public void onCompleted(Exception e, JsonObject result) {
// do stuff with the result or error
}
});
Run Code Online (Sandbox Code Playgroud)
Rav*_*abu 10
已经解释了新的Thread和AsyncTask解决方案.
AsyncTask理想情况下应该用于短期操作.普通Thread不适合Android.
使用HandlerThread和Handler查看备用解决方案
HandlerThread
用于启动具有looper的新线程的方便类.然后可以使用looper来创建处理程序类.请注意,
start()仍然必须调用.
处理器:
Handler允许您发送和处理与线程的MessageQueue关联的Message和Runnable对象.每个Handler实例都与一个线程和该线程的消息队列相关联.当您创建一个新的Handler时,它被绑定到正在创建它的线程的线程/消息队列 - 从那时起,它将消息和runnables传递给该消息队列并在消息出来时执行它们队列.
解:
创建 HandlerThread
呼叫start()上HandlerThread
Handler通过获取Looper来创建HanlerThread
将与网络操作相关的代码嵌入到Runnable对象中
提交Runnable任务Handler
示例代码段,其中包含地址 NetworkOnMainThreadException
HandlerThread handlerThread = new HandlerThread("URLConnection");
handlerThread.start();
handler mainHandler = new Handler(handlerThread.getLooper());
Runnable myRunnable = new Runnable() {
@Override
public void run() {
try {
Log.d("Ravi", "Before IO call");
URL page = new URL("http://www.google.com");
StringBuffer text = new StringBuffer();
HttpURLConnection conn = (HttpURLConnection) page.openConnection();
conn.connect();
InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
BufferedReader buff = new BufferedReader(in);
String line;
while ( (line = buff.readLine()) != null) {
text.append(line + "\n");
}
Log.d("Ravi", "After IO call");
Log.d("Ravi",text.toString());
}catch( Exception err){
err.printStackTrace();
}
}
};
mainHandler.post(myRunnable);
Run Code Online (Sandbox Code Playgroud)
使用这种方法的优点:
Thread/AsyncTask为每个网络操作创建新的是昂贵的.在Thread/AsyncTask将被销毁且下一次网络运营重新创建.但随着Handler和HandlerThread方法,您可以提交许多网络操作(如Runnable的任务),以单HandlerThread用Handler.yoA*_*ex5 10
您可以将代码的一部分移动到另一个线程中以卸载main thread并避免获取ANR,NetworkOnMainThreadException,IllegalStateException(例如,无法访问主线程上的数据库,因为它可能会长时间锁定UI).
您应该选择一些方法取决于具体情况
Java Thread或Android HandlerThread
Java线程只能一次性使用,并在执行其run方法后死掉.
HandlerThread是一个方便的类,用于启动具有looper的新线程.
AsyncTask旨在成为Thread和Handler的辅助类,并不构成通用的线程框架.理想情况下,AsyncTasks应该用于短操作(最多几秒钟.)如果需要保持线程长时间运行,强烈建议您使用java.util.concurrent包提供的各种API,例如Executor,ThreadPoolExecutor和FutureTask.
线程池实现ThreadPoolExecutor,ScheduledThreadPoolExecutor ...
实现ExecutorService的ThreadPoolExecutor类,它可以对线程池进行精细控制(例如,核心池大小,最大池大小,保持活动时间等)
ScheduledThreadPoolExecutor - 一个扩展ThreadPoolExecutor的类.它可以在给定延迟之后或定期安排任务.
FutureTask执行异步处理,但是,如果结果尚未就绪或处理尚未完成,则调用get()将阻塞该线程
AsyncTaskLoaders因为它们解决了AsyncTask固有的许多问题
这是Android上长时间运行处理的事实选择,一个很好的例子就是上传或下载大文件.即使用户退出应用程序,上传和下载也可能继续,您肯定不希望阻止用户在执行这些任务时使用该应用程序.
实际上,您必须使用JobInfo.Builder创建服务并创建作业,该作业指定了何时运行服务的条件.
用于通过使用可观察序列来编写异步和基于事件的程序的库.
协同程序(Kotlin)
它的主要内容是,它使异步代码看起来非常像同步
阅读更多内容:
8种在Android中进行异步处理的方法,以及
使用
Android中的线程池计算Android网络访问的演变
小智 9
Android 不允许在主线程上运行长时间运行的操作。
因此,只需使用不同的线程并在需要时将结果发布到主线程即可。
new Thread(new Runnable() {
@Override
public void run() {
/*
// Run operation here
*/
// After getting the result
runOnUiThread(new Runnable() {
@Override
public void run() {
// Post the result to the main thread
}
});
}
}).start();
Run Code Online (Sandbox Code Playgroud)
小智 8
RxAndroid是这个问题的另一个更好的替代方案,它使我们免于创建线程的麻烦,然后在Android UI线程上发布结果.我们只需要指定需要执行任务的线程,并在内部处理所有事务.
Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() {
@Override
public List<String> call() {
return mRestClient.getFavoriteMusicShows();
}
});
mMusicShowSubscription = musicShowsObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>>() {
@Override
public void onCompleted() { }
@Override
public void onError(Throwable e) { }
@Override
public void onNext(List<String> musicShows){
listMusicShows(musicShows);
}
});
Run Code Online (Sandbox Code Playgroud)
通过指定(Schedulers.io()),RxAndroid将getFavoriteMusicShows() 在不同的线程上运行.
通过使用AndroidSchedulers.mainThread()我们想在UI线程上观察这个Observable,即我们希望onNext()在UI线程上调用我们的回调
这有效.刚刚将Dr.Luiji的答案变得更简单一些.
new Thread() {
@Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
Run Code Online (Sandbox Code Playgroud)
还有另一种解决此问题的非常方便的方法 - 使用rxJava的并发功能.您可以在后台执行任何任务并以非常方便的方式将结果发布到主线程,因此这些结果将被传递到处理链.
第一个经过验证的答案建议是使用AsynTask.是的,这是一个解决方案,但现在已经过时,因为有新的工具.
String getUrl() {
return "SomeUrl";
}
private Object makeCallParseResponse(String url) {
return null;
//
}
private void processResponse(Object o) {
}
Run Code Online (Sandbox Code Playgroud)
getUrl方法提供URL地址,它将在主线程上执行.
makeCallParseResponse(..) - 做实际工作
processResponse(..) - 将在主线程上处理结果.
异步执行的代码如下所示:
rx.Observable.defer(new Func0<rx.Observable<String>>() {
@Override
public rx.Observable<String> call() {
return rx.Observable.just(getUrl());
}
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.map(new Func1<String, Object>() {
@Override
public Object call(final String s) {
return makeCallParseResponse(s);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
processResponse(o);
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// Process error here, it will be posted on
// the main thread
}
});
Run Code Online (Sandbox Code Playgroud)
与AsyncTask相比,此方法允许任意次数切换调度程序(例如,在一个调度程序上获取数据并在另一个调度程序上处理这些数据(例如,Scheduler.computation()).您还可以定义自己的调度程序.
要使用此库,请在build.gradle文件中包含以下行:
compile 'io.reactivex:rxjava:1.1.5'
compile 'io.reactivex:rxandroid:1.2.0'
Run Code Online (Sandbox Code Playgroud)
最后一个依赖项包括对.mainThread()调度程序的支持.
在Android上,网络操作不能在主线程上运行。您可以使用Thread, AsyncTask(short-running tasks), Service(long-running tasks) 进行网络操作。android.os.NetworkOnMainThreadException当应用程序尝试在其主线程上执行网络操作时抛出。如果您的任务耗时超过 5 秒,则需要强制关闭。
运行您的代码AsyncTask:
class FeedTask extends AsyncTask<String, Void, Boolean> {
protected RSSFeed doInBackground(String... urls) {
// TODO: Connect
}
protected void onPostExecute(RSSFeed feed) {
// TODO: Check this.exception
// TODO: Do something with the feed
}
}
Run Code Online (Sandbox Code Playgroud)
或者
new Thread(new Runnable(){
@Override
public void run() {
try {
// Your implementation
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Run Code Online (Sandbox Code Playgroud)
不建议这样做。
但出于调试目的,您也可以使用以下代码禁用严格模式:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
Run Code Online (Sandbox Code Playgroud)
小智 7
Google 在 Android 11 中弃用了 Android AsyncTask API。
\n即使您在主活动之外创建线程类,仅通过在主活动中调用它,您也会得到相同的错误。这些调用必须在可运行线程内,但如果您需要一些异步代码在后台执行或稍后在此处执行,您可以查看 Kotlin 和 Java 的一些替代方案:
\n*/sf/ask/4113741341/*\nRun Code Online (Sandbox Code Playgroud)\n对我特别有用的是 mayank1513 的答案,用于在上面的链接上找到的可运行线程的Java\xc2\xa08实现。代码如下:
\nnew Thread(() -> {\n // do background stuff here\n runOnUiThread(() -> {\n // OnPostExecute stuff here\n });\n}).start();\nRun Code Online (Sandbox Code Playgroud)\n但是,您可以首先在代码的某些部分定义线程,然后在其他地方启动它,如下所示:
\n线程定义
\nThread thread = new Thread(() -> {\n // do background stuff here\n runOnUiThread(() -> {\n // OnPostExecute stuff here\n });\n});\nRun Code Online (Sandbox Code Playgroud)\n线程调用
\nthread.start();\nRun Code Online (Sandbox Code Playgroud)\n我希望这可以避免某人因看到已弃用的而感到头疼AsyncTask。
小智 6
您不能在Android上的UI线程上实现网络操作.你将不得不使用AsyncTask类来执行网络相关的操作,如发送API请求,从URL下载图像等,并使用AsyncTask的回调方法,你可以得到onPostExecute menthod的结果,你将在UI线程和你可以使用来自Web服务或类似内容的数据填充UI.
示例:假设您要从URL下载图像:https://www.samplewebsite.com/sampleimage.jpg
使用AsyncTask的解决方案:分别是.
public class MyDownloader extends AsyncTask<String,Void,Bitmap>
{
@Override
protected void onPreExecute() {
// Show progress dialog
super.onPreExecute();
}
@Override
protected void onPostExecute(Bitmap bitmap) {
//Populate Ui
super.onPostExecute(bitmap);
}
@Override
protected Bitmap doInBackground(String... params) {
// Open URL connection read bitmaps and return form here
return result;
}
@Override
protected void onProgressUpdate(Void... values) {
// Show progress update
super.onProgressUpdate(values);
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:不要忘记在Android清单文件中添加Internet权限.它会像魅力一样工作.:)
你可以使用KOTLIN和ANKO.
Kotlin是Android的新官方语言更多关于它你可以在这里找到 https://kotlinlang.org/docs/tutorials/kotlin-android.html
Anko支持Android中的Kotlin库,其中一些文档 https://github.com/Kotlin/anko
该解决方案非常实用,只有少量代码由@AntonioLeiva编写 https://antonioleiva.com/anko-background-kotlin-android/
doAsync {
var result = runLongTask()
uiThread {
toast(result)
}
}
Run Code Online (Sandbox Code Playgroud)
虽然很简单,但是NetworkOnMainThread当您运行后台作业时,UI Thread您需要做的就是longTask job在后台运行您的工作.您可以在Android App中使用此方法和Kotlin与Anko一起执行此操作.
主线程是UI线程,并且您无法在主线程中执行可能阻止用户交互的操作。您可以通过两种方式解决此问题:
像这样强制在主线程中执行任务
StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);
Run Code Online (Sandbox Code Playgroud)
或创建一个简单的处理程序并根据需要更新主线程。
Runnable runnable;
Handler newHandler;
newHandler = new Handler();
runnable = new Runnable() {
@Override
public void run() {
try {
//update UI
} catch (Exception e) {
e.printStackTrace();
}
}
};
newHandler.post(runnable);
Run Code Online (Sandbox Code Playgroud)
并停止使用该线程:
newHandler.removeCallbacks(runnable);
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请查看以下内容:无痛线程
如果您使用 Kotlin,则可以使用协程:
fun doSomeNetworkStuff() {
GlobalScope.launch(Dispatchers.IO) {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
当应用程序尝试在其主线程上执行网络操作时会抛出此异常。如果您的任务耗时超过 5 秒,则需要强制关闭。
运行您的代码AsyncTask:
class RetrieveFeedTask extends AsyncTask<String, Void, Boolean> {
protected RSSFeed doInBackground(String... urls) {
// TODO: Connect
}
protected void onPostExecute(RSSFeed feed) {
// TODO: Check this.exception
// TODO: Do something with the feed
}
}
Run Code Online (Sandbox Code Playgroud)
我们还可以使用RxJava将网络操作移至后台线程。它也相当简单。
webService.doSomething(someData)
.subscribeOn(Schedulers.newThread())-- This for background thread
.observeOn(AndroidSchedulers.mainThread()) -- for callback on UI
.subscribe(result -> resultText.setText("It worked!"),
e -> handleError(e));
Run Code Online (Sandbox Code Playgroud)
你可以用 RxJava 做更多的事情。这里有一些 RxJava 的链接。随意挖掘。
小智 5
You can also resolve this issue by using Strict Mode using the below code. It's also an alternative to resolving this issue.
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Run Code Online (Sandbox Code Playgroud)
But the best practice would be to use AsyncTask.
| 归档时间: |
|
| 查看次数: |
1152959 次 |
| 最近记录: |