https://developer.android.com/studio 下载了linux 版:android-studio-2022.2.1.20-linux.tar.gz
按照安装文档轻松安装。建议,最好让电脑科学上网,因为有很多个文件是从google网站上下载的。
还有最好不要用虚拟终端输出程序结果。因为速度很慢。找一个旧手机代替,速度快得多。
下面的代码是输入框的内容显示在文本框中。
以下的程序都采用的是Empty Views Activity 模板。
发现android编程,ui界面部分只要把布局编辑器练熟就行了,难的还是代码的事件处理部份。ui的很多控件初学都用不上,只要把三四个常用的搞熟就可以练代码了。
package com.example.wz;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //按照布局文件activity_main.xml 显示,估计此方法是不停刷新此文件的内容,所以程序不用再setContentView
Button button=findViewById(R.id.button2); //android 用findViewById 取得java的控件实例
EditText editText=findViewById(R.id.editTextText); //editText 对应的布局编译器中为Plain Text 文本输入框
TextView textView=findViewById(R.id.textView3);
button.setOnClickListener(view -> { //按键的响应
String s = String.valueOf(editText.getText()); //取文本框输入内容
textView.setText(s);
});
}
}
如要连接网络,必须在AndroidManifest.xml文件中加上此两句
下面的代码是连接服务器
package com.example.wz;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //按照布局文件activity_main.xml 显示,估计此方法是不停刷新此文件的内容,所以程序多次setContentView()。
Button button=findViewById(R.id.button2); //android 用findViewById 取得java的控件实例
EditText editText=findViewById(R.id.editTextText); //editText 对应的布局编译器中为Plain Text 文本输入框
TextView textView=findViewById(R.id.textView3);
button.setOnClickListener(view -> { //按键的响应
// String s = String.valueOf(editText.getText()); //取文本框输入内容
// textView.setText("接收数据");
try {
Socket socket=new Socket("192.168.43.61",3000);
InputStream inputStream=socket.getInputStream();
ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
String s=objectInputStream.readUTF();
textView.setText(s);
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
}
注意:try catch语句要注释掉throw new RunimeException(e);这句,否则一有错,程序就退出。有这个基础程序框架,就可以试试把java程序搬到手机上。
还有setContentView()方法,估计安卓系统是定时不停地刷新桌面显示控件,有点像java的Timer,所以程序不用多次用此方法,一次就行了。
android 线程间传递数据,不能用java 线程的传递方法,如静态类变量就不能用。
package com.example.wz;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
static Handler handler;
static TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
EditText editText = findViewById(R.id.editTextText);
textView = findViewById(R.id.textView);
Handler.Callback hc=new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) { //这里必须调用handle类的镶嵌类Handle.Callback的handleMessage方法。
int t=msg.arg1;
textView.setText(String.valueOf(t));
return false;
}
};
handler =new Handler(Looper.myLooper(),hc);
button.setOnClickListener(view -> {
Th th = new Th();
th.start();
});
}
}
class Th extends Thread {
int t=0;
public void run() {
while (true) {
Message message = new Message();
message.arg1=t;
MainActivity.handler.sendMessage(message);
t++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// throw new RuntimeException(e);
}
}
}
}
此种传递数据的方法,数据的产生和ui显示是异步的。我理解有点像map 的键值对,这个ss就是键,接照键的对应关系,线程先把值存在”map”中,ui再取出此值显示。这样理解好记忆。
安卓的主线程只能处现ui代码和事件响应代码,其他的java逻辑算法代码都不能放在主线程中,java代码只能放在响应事件的代码块中,或者放在其他子线程中。而且响应事件的代码耗时不能太久,更不能放循环等待的语句,如有这种耗时的代码,必须放在新线程中,用事件响应启动此线程。如按钮单击启动耗时线程。
其实这也是一个android编程通用方法,把ui代码放在主线程中,其他的一切逻辑代码另开一个线程完成,主线程用一个事件响应启动这个新线程,新线程的数据通过上面程序的方法传给主线程完成显示。
看jdk学Handle
Handler 允许您发送和处理Message
与线程关联的 Runnable 对象MessageQueue
。每个 Handler 实例都与一个线程和该线程的消息队列相关联。当您创建一个新的处理程序时,它会绑定到一个Looper
. 它会将消息和可运行对象传递到该 Looper 的消息队列,并在该 Looper 的线程上执行它们。
Handler 有两个主要用途:(1) 安排消息和可运行对象在未来某个时间点执行;(2) 将要在与您自己的线程不同的线程上执行的操作排队。
调度消息是通过 post(Runnable)
、postAtTime(java.lang.Runnable, long)
、 postDelayed(Runnable, Object, long)
、sendEmptyMessage(int)
、 sendMessage(Message)
、sendMessageAtTime(Message, long)
和 sendMessageDelayed(Message, long)
方法完成的。post版本允许您将 Runnable 对象入队,以便在接收到消息队列时调用它们;sendMessage版本允许您将包含将由Message
Handler 的方法处理的数据包的对象排入队列handleMessage(Message)
(要求您实现 Handler 的子类)。
发布或发送到处理程序时,您可以允许项目在消息队列准备就绪后立即处理,或者指定处理前的延迟或处理的绝对时间。后两者允许您实现超时、滴答和其他基于时间的行为。
handle post() 方法,发现只能更新一次,不知道是否正确
此方法代码很简单
package com.example.wz;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
static Handler handler=new Handler();
static TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
EditText editText = findViewById(R.id.editTextText);
textView = findViewById(R.id.textView);
button.setOnClickListener(view -> {
Th th = new Th();
th.start();
});
}
}
class Th extends Thread {
public void run() {
MainActivity.handler.post(()->{
MainActivity.textView.setText("hello nanning");
});
}
}
这里的handle实例必须放在主线程中,其实把它想成java场景中的静态类变量就好理解了。
如要循环,可以这样处理,但又不能加Thread.sleep()延时
class Th extends Thread { //刚实验,此post方法只能更新一次ui。如加循环,报错
public void run () {
while(true) {
h.post(new Runnable() {
public void run() {
textView.setText(String.valueOf(1));
}
});
h.post(new Runnable() {
public void run() {
textView.setText(String.valueOf(2));
}
});
}
}
}
这个post方法虽然只能执行一次更新ui,也可编写许多场景的程序了。如连接服务器一次读取数据,输入网址读取网页文件,查询一次文件目录,如是线程不停传递数据则不能用此方法。
利用handle.post()连接服务器读取一次数据
package com.example.wz;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
static Handler h = new Handler();
static TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
EditText editText = findViewById(R.id.editTextText);
textView = findViewById(R.id.textView);
button.setOnClickListener(view -> {
Th th = new Th();
th.start();
});
}
}
class Th extends Thread { //刚实验,此post方法只能更新一次ui。如加循环,报错
public void run() {
Socket socket= null;
String s;
try {
socket = new Socket("192.168.2.8",3000);
InputStream inputStream=socket.getInputStream();
ObjectInputStream objectInputStream=new
ObjectInputStream(inputStream);
s=objectInputStream.readUTF();
MainActivity.h.post(new Runnable() {
public void run() {
MainActivity.textView.setText(s);
}
});
objectInputStream.close();
} catch (IOException e) {
// throw new RuntimeException(e);
}
}
}
手机要是上网,必须要在全局文件中加这俩句
=========================================================================
android 文件
参考出处:https://blog.csdn.net/huweiliyi/category_8913738.html
raw目录
asserts目录
data/data/包名
sdcard目录
其中raw下的和asserts下的文件可以以资源文件的形式读取,这些目录的数据只能读取,不能写入,两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。
data/data/包名和sdcard目录文件可读可写。其中data/data/包名目录不需要申请权限,sdcard目录需要申请权限
读取文件要在全局文件中加这两句
data/data/(包名) 目录文件读写
将数据以普通文件的形式保存在 /data/data/包名中,该方法不需要申请权限。
存放在数据区(/data/data/包名)的文件可以使用openFileOutput和openFileInput进行操作。
也可以直接指定文件/data/data/包名路径读写。
data/data/包名/shared_prefs
存放SharedPreferences数据
data/data/包名/databases
存放数据库数据
data/data/包名/files
存放普通数据
data/data/包名/cache
存放缓存文件
开发IDE 右边有一个Device File Explorer 用它可以浏览手机的整个目录结构
可以用它看/data/data/ 有啥文件,在读取。