我一直在编写用于FTP文件传输的应用程序,我需要隐藏一些UI元素并在单击按钮时使一些可见。可见性设置与应用程序启动时相同,并且不会更改。知道为什么吗?
这是我的元素:
ip= (EditText) findViewById(R.id.ipadd);
portt=(EditText) findViewById(R.id.port);
conn= (Button) findViewById(R.id.connectb);
pb= (ProgressBar) findViewById(R.id.pb);
trans=(TextView) findViewById(R.id.transfer);
以下是应用程序(onCreate)启动时的设置:
pb.setVisibility(View.INVISIBLE);
trans.setVisibility(View.INVISIBLE);
ip.setVisibility(View.VISIBLE);
portt.setVisibility(View.VISIBLE);
conn.setVisibility(View.VISIBLE);
将应用这些设置。 这是单击按钮时该功能的代码:
Ftp ftp;
errflag=false;
ip.setVisibility(View.INVISIBLE);
portt.setVisibility(View.INVISIBLE);
conn.setVisibility(View.INVISIBLE);
trans.setVisibility(View.VISIBLE);
pb.setVisibility(View.VISIBLE);
while(!errflag) {
try{
ftp=new Ftp();
String result = ftp.execute("hi").get();
if(result.equals("Finished"))
break;
} catch(Exception e){
e.printStackTrace();
}
}
代码中的所有内容都可以正常工作,但这些元素的可见性除外。 该控件进入while循环并正确退出,但不会更改元素的可见性。是的,该函数在单击按钮时调用,因此它在UI线程中,但是我仍然尝试将代码包装在runOnUIThread中似乎没有任何改变的方法。 任何意见将不胜感激。
异步任务代码:
public class Ftp extends AsyncTask<String ,String,String>
{
protected String doInBackground(String... urls)
{
try
{
String ipadd= ip.getText().toString();
int port =Integer.parseInt(portt.getText().toString());
Socket socket=new Socket(ipadd,port);
//Button conn=(Button) findViewById(R.id.connectb);
//conn.setEnabled(false);
BufferedReader br= new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedOutputStream bo= new BufferedOutputStream(socket.getOutputStream());
PrintWriter pw= new PrintWriter(bo,true);
String file=br.readLine();
if(file.equals("Finished"))
return file;
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
File f= new File(path, "/" + file);
byte[] buff= new byte[1024];
int len;
pw.println("done");
DataInputStream is= new DataInputStream(socket.getInputStream());
FileOutputStream fos= new FileOutputStream(f);
Thread.sleep(1);
publishProgress(file);
while((len=is.read(buff))!=-1)
{
fos.write(buff,0,len);
}
Log.i("status","Finsihed");
/* else
{
Toast.makeText(MainActivity.this,"File already exists!",Toast.LENGTH_LONG).show();
}*/
}catch(NumberFormatException nfe)
{
errflag=true;
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this,"Enter a proper IP and port!",Toast.LENGTH_LONG).show();
}
});
nfe.printStackTrace();
}
catch(java.net.UnknownHostException un)
{
errflag=true;
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this,"Enter a proper IP and port!",Toast.LENGTH_LONG).show();
}
});
//Toast.makeText(MainActivity.this,"Enter a proper IP and port!",Toast.LENGTH_LONG).show();
un.printStackTrace();
}
catch(java.net.NoRouteToHostException no)
{errflag=true;
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this,"There is no active server at the specified IP and port!",Toast.LENGTH_LONG).show();
}
});
no.printStackTrace();
}
catch(Exception e)
{
errflag=true;
Log.i("this","error");
e.printStackTrace();
}
return "Not Yet";
}
protected void onProgressUpdate(String... para)
{
super.onProgressUpdate(para);
trans.setText("Transfering file: "+para[0]);
}
}`
然后我创建了一个新线程:
public class MyThread extends Thread
{
public void run() {
while (!errflag) {
try {
Ftp ftp = new Ftp();
String res = ftp.execute("hi").get();
if (res.equals("Finished"))
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
并将功能代码更改为:
errflag=false;
ip.setVisibility(View.INVISIBLE);
portt.setVisibility(View.INVISIBLE);
conn.setVisibility(View.INVISIBLE);
trans.setVisibility(View.VISIBLE);
pb.setVisibility(View.VISIBLE);
/*ftp=new Ftp();
String result = ftp.execute("hi").get();
if(result.equals("Finished"))
break;*/
try {
MyThread t = new MyThread();
t.start();
}catch(Exception ex)
{
ex.printStackTrace();
}
答案 0 :(得分:1)
我认为,您应该将while循环移到另一个线程中。 更改可见性意味着视图层次结构将在下一帧重绘,并且[可见性]仅在下一次绘制迭代时才考虑在内。因此,当您阻塞ui线程(在while循环中)时,将永远无法达到此重绘阶段。
UPD:您应该释放UI线程,因此只需在另一个线程中循环运行即可。
ip.setVisibility(View.INVISIBLE);
portt.setVisibility(View.INVISIBLE);
conn.setVisibility(View.INVISIBLE);
trans.setVisibility(View.VISIBLE);
pb.setVisibility(View.VISIBLE);
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
errflag=false;
while(!errflag) {
try{
ftp=new Ftp();
String result = ftp.execute("hi").get();
if(result.equals("Finished"))
break;
} catch(Exception e){
e.printStackTrace();
}
}
}
});
答案 1 :(得分:1)
感谢您的帮助。我找到了解决方案。显然,将繁重的工作放在另一个普通线程上不会改变任何事情。AsyncTasks是为此目的而设计的。 我读了这篇文章:https://tekeye.uk/android/examples/asynctask-helps-avoid-anr 我将while循环放入另一个asynctask类中,并在“ onPreExecute()”中进行了UI更改,然后将循环放入“ doInBackground()”中。它的工作原理很吸引人。 这是我的代码:
class HeavyWork extends AsyncTask<String,Void,Void>
{
protected void onPreExecute()
{
pb.setVisibility(View.VISIBLE);
trans.setVisibility(View.VISIBLE);
ip.setVisibility(View.INVISIBLE);
portt.setVisibility(View.INVISIBLE);
conn.setVisibility(View.INVISIBLE);
}
protected Void doInBackground(String... urls)
{
start();
return null;
}
protected void onPostExecute(Void a)
{
pb.setVisibility(View.INVISIBLE);
trans.setVisibility(View.INVISIBLE);
ip.setVisibility(View.VISIBLE);
portt.setVisibility(View.VISIBLE);
conn.setVisibility(View.VISIBLE);
trans.setText("Waiting for files");
}
}
启动方法是:
public void start()
{
while (!errflag) {
try {
Ftp ftp = new Ftp();
String res = ftp.execute("hi").get();
if (res.equals("Finished"))
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后我将onClick方法更改为:
errflag=false;
/*ftp=new Ftp();
String result = ftp.execute("hi").get();
if(result.equals("Finished"))
break;*/
new HeavyWork().execute("hi");
但是似乎您无法从另一个asynctask线程调用asynctask,因此您需要从UI线程调用它。 为此,我从doInBackground删除了start并将其粘贴在onPostExecute上,因为它在UI线程上运行,如下所示:
class HeavyWork extends AsyncTask<String,Void,Void>
{
protected void onPreExecute()
{
pb.setVisibility(View.VISIBLE);
trans.setVisibility(View.VISIBLE);
ip.setVisibility(View.INVISIBLE);
portt.setVisibility(View.INVISIBLE);
conn.setVisibility(View.INVISIBLE);
}
protected Void doInBackground(String... urls)
{
return null;
}
protected void onPostExecute(Void a)
{
start();
pb.setVisibility(View.INVISIBLE);
trans.setVisibility(View.INVISIBLE);
ip.setVisibility(View.VISIBLE);
portt.setVisibility(View.VISIBLE);
conn.setVisibility(View.VISIBLE);
trans.setText("Waiting for files");
}
}
就是这样。有效。
非常感谢你们,尤其是亚历山大和尼古拉。您真是太好了:)
答案 2 :(得分:0)
尝试在如下所示的工作线程中执行ftp方法,可能是您阻止了UI的更新。
Ftp ftp;
errflag=false;
ip.setVisibility(View.INVISIBLE);
portt.setVisibility(View.INVISIBLE);
conn.setVisibility(View.INVISIBLE);
trans.setVisibility(View.VISIBLE);
pb.setVisibility(View.VISIBLE);
try {
new Thread(new Runnable() {
public void run() {
// a potentially time consuming task
while(!errflag) {
ftp = new Ftp();
String result = ftp.execute("hi").get();
if(result.equals("Finished"))
break;
}
}
}).start();
} catch(Exception e){
e.printStackTrace();
}
}
答案 3 :(得分:0)
请尝试仅在主线程中运行以下命令,看看是否有帮助。
ip.setVisibility(View.INVISIBLE);
portt.setVisibility(View.INVISIBLE);
conn.setVisibility(View.INVISIBLE);
trans.setVisibility(View.VISIBLE);
pb.setVisibility(View.VISIBLE);